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
191 changes: 191 additions & 0 deletions labs/lab7/k8s/deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: juice-shop
namespace: juice-shop
spec:
replicas: 1
selector:
matchLabels:
app: juice-shop
template:
metadata:
labels:
app: juice-shop
spec:
serviceAccountName: juice-shop-sa
automountServiceAccountToken: false
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
initContainers:
- name: data-populate
image: bkimminich/juice-shop@sha256:fd58bdc9745416afce8184ee0666278a436574633ea7880365153a63bfd418b0
securityContext:
runAsNonRoot: true
runAsUser: 1000
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
seccompProfile:
type: RuntimeDefault
command:
- /nodejs/bin/node
- -e
- |
const fs = require('fs');
const path = require('path');
const src = '/juice-shop/data';
const dst = '/data';
const copy = (srcDir, dstDir) => {
fs.mkdirSync(dstDir, { recursive: true });
for (const name of fs.readdirSync(srcDir)) {
const srcPath = path.join(srcDir, name);
const dstPath = path.join(dstDir, name);
const stat = fs.statSync(srcPath);
if (stat.isDirectory()) {
copy(srcPath, dstPath);
} else {
fs.copyFileSync(srcPath, dstPath);
}
}
};
copy(src, dst);
volumeMounts:
- name: data
mountPath: /data
- name: csaf-populate
image: bkimminich/juice-shop@sha256:fd58bdc9745416afce8184ee0666278a436574633ea7880365153a63bfd418b0
securityContext:
runAsNonRoot: true
runAsUser: 1000
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
seccompProfile:
type: RuntimeDefault
command:
- /nodejs/bin/node
- -e
- |
const fs = require('fs');
const path = require('path');
const src = '/juice-shop/.well-known/csaf';
const dst = '/csaf';
const copy = (srcDir, dstDir) => {
fs.mkdirSync(dstDir, { recursive: true });
for (const name of fs.readdirSync(srcDir)) {
const srcPath = path.join(srcDir, name);
const dstPath = path.join(dstDir, name);
const stat = fs.statSync(srcPath);
if (stat.isDirectory()) {
copy(srcPath, dstPath);
} else {
fs.copyFileSync(srcPath, dstPath);
}
}
};
if (fs.existsSync(src)) {
copy(src, dst);
}
volumeMounts:
- name: csaf
mountPath: /csaf
- name: frontend-populate
image: bkimminich/juice-shop@sha256:fd58bdc9745416afce8184ee0666278a436574633ea7880365153a63bfd418b0
securityContext:
runAsNonRoot: true
runAsUser: 1000
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
seccompProfile:
type: RuntimeDefault
command:
- /nodejs/bin/node
- -e
- |
const fs = require('fs');
const path = require('path');
const src = '/juice-shop/frontend/dist';
const dst = '/frontend-dist';
const copy = (srcDir, dstDir) => {
fs.mkdirSync(dstDir, { recursive: true });
for (const name of fs.readdirSync(srcDir)) {
const srcPath = path.join(srcDir, name);
const dstPath = path.join(dstDir, name);
const stat = fs.statSync(srcPath);
if (stat.isDirectory()) {
copy(srcPath, dstPath);
} else {
fs.copyFileSync(srcPath, dstPath);
}
}
};
if (fs.existsSync(src)) {
copy(src, dst);
}
volumeMounts:
- name: frontend-dist
mountPath: /frontend-dist
containers:
- name: juice-shop
image: bkimminich/juice-shop@sha256:fd58bdc9745416afce8184ee0666278a436574633ea7880365153a63bfd418b0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3000
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
resources:
requests:
cpu: "100m"
memory: "200Mi"
limits:
cpu: "500m"
memory: "512Mi"
volumeMounts:
- name: tmp
mountPath: /tmp
- name: logs
mountPath: /usr/src/app/logs
- name: logs
mountPath: /juice-shop/logs
- name: ftp
mountPath: /juice-shop/ftp
- name: videos
mountPath: /juice-shop/frontend/dist/frontend/assets/public/videos
- name: csaf
mountPath: /juice-shop/.well-known/csaf
- name: data
mountPath: /juice-shop/data
- name: i18n
mountPath: /juice-shop/i18n
- name: frontend-dist
mountPath: /juice-shop/frontend/dist
volumes:
- name: tmp
emptyDir: {}
- name: logs
emptyDir: {}
- name: ftp
emptyDir: {}
- name: videos
emptyDir: {}
- name: csaf
emptyDir: {}
- name: data
emptyDir: {}
- name: i18n
emptyDir: {}
- name: frontend-dist
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/enforce: restricted
pod-security.kubernetes.io/warn: restricted
pod-security.kubernetes.io/audit: restricted
33 changes: 33 additions & 0 deletions labs/lab7/k8s/networkpolicy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: juice-shop-policy
namespace: juice-shop
spec:
podSelector:
matchLabels:
app: juice-shop
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
- ipBlock:
cidr: 127.0.0.1/32
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- 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:
name: juice-shop-sa
namespace: juice-shop
automountServiceAccountToken: false
34 changes: 34 additions & 0 deletions labs/lab7/policies/pod-hardening.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package main

# Helper: true if array arr contains value v
has_value(arr, v) if {
some i
arr[i] == v
}

deny contains msg if {
input.kind == "Deployment"
not input.spec.template.spec.securityContext.runAsNonRoot == true
msg := "pod spec must set spec.securityContext.runAsNonRoot: true"
}

deny contains msg if {
input.kind == "Deployment"
c := input.spec.template.spec.containers[_]
not c.securityContext.readOnlyRootFilesystem == true
msg := sprintf("container %q must set securityContext.readOnlyRootFilesystem: true", [c.name])
}

deny contains msg if {
input.kind == "Deployment"
c := input.spec.template.spec.containers[_]
not c.securityContext.allowPrivilegeEscalation == false
msg := sprintf("container %q must set securityContext.allowPrivilegeEscalation: false", [c.name])
}

deny contains msg if {
input.kind == "Deployment"
c := input.spec.template.spec.containers[_]
not has_value(c.securityContext.capabilities.drop, "ALL")
msg := sprintf("container %q must drop ALL capabilities", [c.name])
}
Loading
Loading