Skip to content

Commit

Permalink
feat: improve infrastructure security (#75)
Browse files Browse the repository at this point in the history
* ci: update paths-filter action

* ci: sign container images

* chore: add Kyverno policy

* chore: add user in backend Dockerfile

* chore: add security context to deployments

* chore: add resource limits to deployments

* feat(kube): add network policies

* ci: don't sign the image if not pushing
  • Loading branch information
Kuruyia authored Feb 24, 2024
1 parent 04707ea commit 5c576d5
Show file tree
Hide file tree
Showing 15 changed files with 175 additions and 5 deletions.
19 changes: 19 additions & 0 deletions .github/workflows/flow_backend_build_push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ jobs:
packages: write
contents: read
steps:
- name: Install Cosign
uses: sigstore/cosign-installer@v3
if: ${{ inputs.push-image }}

- name: Setup Docker buildx
uses: docker/setup-buildx-action@v3

Expand All @@ -53,6 +57,7 @@ jobs:

- name: Build and push Docker image
uses: docker/build-push-action@v5
id: build_and_push
with:
push: ${{ inputs.push-image }}
tags: ${{ steps.meta.outputs.tags }}
Expand All @@ -61,3 +66,17 @@ jobs:
cache-to: type=gha,mode=max
context: "{{ defaultContext }}:${{ inputs.service-build-context-path }}"
build-args: SERVICE_NAME=${{ inputs.service-name }}

- name: Sign image with Cosign
if: ${{ inputs.push-image }}
run: |
images=""
for tag in ${TAGS}; do
images+="${tag}@${DIGEST} "
done
cosign sign --yes --key env://COSIGN_PRIVATE_KEY ${images}
env:
TAGS: ${{ steps.meta.outputs.tags }}
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
DIGEST: ${{ steps.build_and_push.outputs.digest }}
3 changes: 2 additions & 1 deletion .github/workflows/on_push_pr_main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
steps:
- uses: actions/checkout@v4

- uses: dorny/paths-filter@v2
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
Expand Down Expand Up @@ -101,6 +101,7 @@ jobs:
name: Build & push Docker image of the "${{ matrix.service }}" service
needs: lint_backend
uses: ./.github/workflows/flow_backend_build_push.yml
secrets: inherit
strategy:
matrix:
service: [api_gateway, jobs, messaging, employer, notification, profile, recommendation]
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/on_semver_tag.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ jobs:
build_push_backend:
name: Build & push Docker image of the "${{ matrix.service }}" service
uses: ./.github/workflows/flow_backend_build_push.yml
secrets: inherit
strategy:
matrix:
service: [api_gateway, jobs, messaging, employer, notification, profile, recommendation]
Expand Down
2 changes: 2 additions & 0 deletions backend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ RUN --mount=type=cache,target=/root/.gradle ./gradlew clean bootJar
# Run stage
FROM amazoncorretto:17-alpine AS run
ARG SERVICE_NAME
RUN addgroup -S linkedout && adduser -u 1001 -S linkedout -G linkedout
WORKDIR /app

COPY --from=build /app/$SERVICE_NAME/build/libs/$SERVICE_NAME.jar ./app.jar

USER 1001
ENTRYPOINT ["java", "-jar", "./app.jar"]
8 changes: 8 additions & 0 deletions kube/base/api_gateway/deployment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,20 @@ spec:
labels:
app.kubernetes.io/name: linkedout-apigw
app.kubernetes.io/part-of: linkedout
network-group: api-gateway
spec:
containers:
- name: linkedout-apigw
image: ghcr.io/thomas-mauran/linkedout/api_gateway
imagePullPolicy: Always
env: []
securityContext:
runAsNonRoot: true
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
ports:
- containerPort: 9090
name: api
8 changes: 8 additions & 0 deletions kube/base/employer/deployment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,20 @@ spec:
labels:
app.kubernetes.io/name: linkedout-employer
app.kubernetes.io/part-of: linkedout
network-group: microservices
spec:
containers:
- name: linkedout-employer
image: ghcr.io/thomas-mauran/linkedout/employer
imagePullPolicy: Always
env: []
securityContext:
runAsNonRoot: true
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
ports:
- containerPort: 8083
name: api
8 changes: 8 additions & 0 deletions kube/base/jobs/deployment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,20 @@ spec:
labels:
app.kubernetes.io/name: linkedout-jobs
app.kubernetes.io/part-of: linkedout
network-group: microservices
spec:
containers:
- name: linkedout-jobs
image: ghcr.io/thomas-mauran/linkedout/jobs
imagePullPolicy: Always
env: []
securityContext:
runAsNonRoot: true
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
ports:
- containerPort: 8081
name: api
8 changes: 8 additions & 0 deletions kube/base/messaging/deployment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,20 @@ spec:
labels:
app.kubernetes.io/name: linkedout-messaging
app.kubernetes.io/part-of: linkedout
network-group: microservices
spec:
containers:
- name: linkedout-messaging
image: ghcr.io/thomas-mauran/linkedout/messaging
imagePullPolicy: Always
env: []
securityContext:
runAsNonRoot: true
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
ports:
- containerPort: 8082
name: api
8 changes: 8 additions & 0 deletions kube/base/notification/deployment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,20 @@ spec:
labels:
app.kubernetes.io/name: linkedout-notification
app.kubernetes.io/part-of: linkedout
network-group: microservices
spec:
containers:
- name: linkedout-notification
image: ghcr.io/thomas-mauran/linkedout/notification
imagePullPolicy: Always
env: []
securityContext:
runAsNonRoot: true
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
ports:
- containerPort: 8084
name: api
8 changes: 8 additions & 0 deletions kube/base/profile/deployment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,20 @@ spec:
labels:
app.kubernetes.io/name: linkedout-profile
app.kubernetes.io/part-of: linkedout
network-group: microservices
spec:
containers:
- name: linkedout-profile
image: ghcr.io/thomas-mauran/linkedout/profile
imagePullPolicy: Always
env: []
securityContext:
runAsNonRoot: true
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
ports:
- containerPort: 8085
name: api
8 changes: 8 additions & 0 deletions kube/base/recommendation/deployment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,20 @@ spec:
labels:
app.kubernetes.io/name: linkedout-recommendation
app.kubernetes.io/part-of: linkedout
network-group: microservices
spec:
containers:
- name: linkedout-recommendation
image: ghcr.io/thomas-mauran/linkedout/recommendation
imagePullPolicy: Always
env: []
securityContext:
runAsNonRoot: true
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
ports:
- containerPort: 8086
name: api
9 changes: 9 additions & 0 deletions kube/prod/add-resource-limits.patch.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
- op: add
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "1Gi"
cpu: "0.5"
limits:
memory: "2Gi"
cpu: "1"
15 changes: 11 additions & 4 deletions kube/prod/kustomization.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,25 @@ kind: Kustomization
namespace: linkedout
resources:
- ../base
- kyverno-policy.yml
- network-policies.yml

patches:
- target:
group: networking.k8s.io
group: apps
version: v1
kind: Ingress
path: api_gateway/configure-ingress.patch.yml
kind: Deployment
path: add-nats.patch.yml
- target:
group: apps
version: v1
kind: Deployment
path: add-nats.patch.yml
path: add-resource-limits.patch.yml
- target:
group: networking.k8s.io
version: v1
kind: Ingress
path: api_gateway/configure-ingress.patch.yml
- target:
group: apps
version: v1
Expand Down
28 changes: 28 additions & 0 deletions kube/prod/kyverno-policy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: check-linkedout-image-signature
spec:
validationFailureAction: Enforce
background: false
webhookTimeoutSeconds: 30
failurePolicy: Fail
rules:
- name: check-image
match:
any:
- resources:
kinds:
- Pod
verifyImages:
- imageReferences:
- "ghcr.io/thomas-mauran/linkedout/*"
attestors:
- count: 1
entries:
- keys:
publicKeys: |-
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEaFU86MNnoiHTLXkBrgnPO18R5gpo
cMic199RKzUa6YftDcDCEovrR0nyzfGp3pKcr4nhjwi3qNRQRHPz76EaWg==
-----END PUBLIC KEY-----
47 changes: 47 additions & 0 deletions kube/prod/network-policies.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: microservices
spec:
podSelector:
matchLabels:
network-group: microservices
policyTypes:
- Ingress
- Egress
egress:
- to:
- podSelector:
matchLabels:
app.kubernetes.io/name: nats
- podSelector:
matchLabels:
app.kubernetes.io/name: postgresql
- podSelector:
matchLabels:
helm.neo4j.com/neo4j.name: linkedout
- podSelector:
matchLabels:
app.kubernetes.io/name: minio
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: coredns-egress
spec:
podSelector:
matchLabels:
network-group: microservices
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53

0 comments on commit 5c576d5

Please sign in to comment.