Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions labs/lab7/k8s/deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: juice-shop
namespace: juice-shop
labels:
app: juice-shop
spec:
replicas: 1
selector:
matchLabels:
app: juice-shop
template:
metadata:
labels:
app: juice-shop
spec:
automountServiceAccountToken: false
serviceAccountName: juice-shop
securityContext:
seccompProfile:
type: RuntimeDefault
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
initContainers:
- name: prepare-db-file
image: bkimminich/juice-shop@sha256:fd58bdc9745416afce8184ee0666278a436574633ea7880365153a63bfd418b0
command:
- /nodejs/bin/node
- -e
- require("fs").cpSync("/juice-shop/data", "/work/data", {recursive:true, force:true}); require("fs").cpSync("/juice-shop/.well-known", "/work/well-known", {recursive:true, force:true}); require("fs").cpSync("/juice-shop/frontend/dist/frontend", "/work/frontend", {recursive:true, force:true})
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi
volumeMounts:
- name: data
mountPath: /work/data
- name: well-known
mountPath: /work/well-known
- name: frontend
mountPath: /work/frontend
containers:
- name: juice-shop
image: bkimminich/juice-shop@sha256:fd58bdc9745416afce8184ee0666278a436574633ea7880365153a63bfd418b0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3000
name: http
protocol: TCP
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
volumeMounts:
- mountPath: /tmp
name: tmp
- mountPath: /juice-shop/logs
name: logs
- mountPath: /juice-shop/ftp
name: ftp
- mountPath: /juice-shop/data
name: data
- mountPath: /juice-shop/i18n
name: i18n
- mountPath: /juice-shop/frontend/dist/frontend
name: frontend
- mountPath: /juice-shop/.well-known
name: well-known
volumes:
- name: tmp
emptyDir: {}
- name: logs
emptyDir: {}
- name: ftp
emptyDir: {}
- name: data
emptyDir: {}
- name: i18n
emptyDir: {}
- name: frontend
emptyDir: {}
- name: well-known
emptyDir: {}
8 changes: 8 additions & 0 deletions labs/lab7/k8s/namespace.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
apiVersion: v1
kind: Namespace
metadata:
name: juice-shop
labels:
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
pod-security.kubernetes.io/enforce: restricted
42 changes: 42 additions & 0 deletions labs/lab7/k8s/networkpolicy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: juice-shop-restricted
namespace: juice-shop
spec:
podSelector:
matchLabels:
app: juice-shop
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: ingress-nginx
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: juice-shop
ports:
- protocol: TCP
port: 3000
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
- to:
- ipBlock:
cidr: 0.0.0.0/0
ports:
- protocol: TCP
port: 443
6 changes: 6 additions & 0 deletions labs/lab7/k8s/serviceaccount.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
apiVersion: v1
kind: ServiceAccount
metadata:
namespace: juice-shop
name: juice-shop
automountServiceAccountToken: false
54 changes: 54 additions & 0 deletions labs/lab7/policies/pod-hardening.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package main

import rego.v1

# Extract Pod spec from Deployment
pod_spec = input.spec.template.spec {
input.kind == "Deployment"
}

# Collect both normal and init containers
containers[container] {
container := pod_spec.containers[_]
}

containers[container] {
container := pod_spec.initContainers[_]
}

# Deny if runAsNonRoot is not explicitly true
deny[msg] {
input.kind == "Deployment"
spec_security := object.get(pod_spec, "securityContext", {})
object.get(spec_security, "runAsNonRoot", false) != true
msg := "pod spec must set securityContext.runAsNonRoot: true"
}

# Deny if any container does not have readOnlyRootFilesystem: true
deny[msg] {
input.kind == "Deployment"
container := containers[_]
container_security := object.get(container, "securityContext", {})
object.get(container_security, "readOnlyRootFilesystem", false) != true
msg := sprintf("container %q must set securityContext.readOnlyRootFilesystem: true", [container.name])
}

# Deny if any container allows privilege escalation (not set to false)
deny[msg] {
input.kind == "Deployment"
container := containers[_]
container_security := object.get(container, "securityContext", {})
object.get(container_security, "allowPrivilegeEscalation", true) != false
msg := sprintf("container %q must set securityContext.allowPrivilegeEscalation: false", [container.name])
}

# Deny if capabilities.drop does not include ALL
deny[msg] {
input.kind == "Deployment"
container := containers[_]
container_security := object.get(container, "securityContext", {})
capabilities := object.get(container_security, "capabilities", {})
dropped := object.get(capabilities, "drop", [])
not "ALL" in dropped
msg := sprintf("container %q must drop all Linux capabilities with capabilities.drop: [\"ALL\"]", [container.name])
}
Loading