Putting Guardrails to Work – Workload Hardening (Custom SCC, Seccomp, SELinux)
Duration: ~25 minutes
Overview
You’ll author and apply a hardened SecurityContextConstraints object, combine it with seccomp and SELinux context discipline, and prove it works through positive and negative deployment tests.
Harden a workload with a custom SCC where needed, plus seccomp and SELinux controls, and verify the pod still runs under stronger constraints.
Why it matters
Default settings are like issuing every warehouse worker a multi‑tool with blades, saws, and pry hooks when they only needed a flat screwdriver. Extra capabilities become unintended weapons if someone misuses or compromises the account. Hardened runtime boundaries (SCC + seccomp + SELinux) strip the “just in case” powers that attackers love to discover after a simple pod foothold. Business outcome: lower chance a minor pod compromise escalates into node‑level panic, plus clearer evidence of least privilege for auditors.
What does it solve
Broad SCC usage silently enables: * Leftover Linux capabilities (each one is an exploration vector) * Accidental root UID usage (scripts work as root, drift ignored) * Looser SELinux contexts (more permissive file/process access) * Unfiltered syscalls (toolbox open for exploitation chains)
Hardening prunes that list down to essentials. Negative tests (deliberate failing pods) ensure protections aren’t theoretical.
Your Mission
Click each step only if you need a hint.
Inspect baseline
oc get scc restricted -o yaml | head -n 40
Create hardened SCC
oc apply -f - <<'EOF'
apiVersion: security.openshift.io/v1
kind: SecurityContextConstraints
metadata:
name: hardened-nonroot
allowPrivilegedContainer: false
allowHostDirVolumePlugin: false
allowHostIPC: false
allowHostNetwork: false
allowHostPID: false
allowHostPorts: false
allowedCapabilities: []
defaultAllowPrivilegeEscalation: false
requiredDropCapabilities: ["ALL"]
runAsUser:
type: MustRunAsRange
uidRangeMin: 1000660000
uidRangeMax: 1000669999
fsGroup:
type: MustRunAs
ranges:
- min: 1000660000
max: 1000669999
seLinuxContext:
type: MustRunAs
seLinuxOptions:
level: s0:c26,c30
seccompProfiles:
- runtime/default
volumes:
- configMap
- emptyDir
- projected
- secret
- downwardAPI
users: []
priority: 10
EOF
Namespace + bind SCC
oc new-project 201-03-w-harden
oc adm policy add-scc-to-group hardened-nonroot system:serviceaccounts:201-03-w-harden
Valid pod (should Run)
oc apply -n 201-03-w-harden -f - <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: good
annotations:
seccomp.security.alpha.kubernetes.io/pod: runtime/default
spec:
securityContext:
runAsUser: 1000660001
fsGroup: 1000660001
containers:
- name: app
image: registry.access.redhat.com/ubi9/ubi
command: ["sh","-c","id; sleep 1000"]
securityContext:
allowPrivilegeEscalation: false
EOF
oc get pod good -n 201-03-w-harden -o jsonpath='{.metadata.annotations.openshift\.io/scc}{"\n"}'
Negative test – disallowed capability
oc apply -n 201-03-w-harden -f - <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: bad-cap
spec:
containers:
- name: app
image: registry.access.redhat.com/ubi9/ubi
command: ["sh","-c","sleep 1000"]
securityContext:
capabilities:
add: ["NET_RAW"]
EOF
oc describe pod bad-cap -n 201-03-w-harden | grep -i deni || true
Negative test – root UID
oc apply -n 201-03-w-harden -f - <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: bad-uid
spec:
securityContext:
runAsUser: 0
containers:
- name: app
image: registry.access.redhat.com/ubi9/ubi
command: ["sh","-c","sleep 1000"]
EOF
| Expect a rejection or scheduling failure. |
Prove seccomp still blocks risky syscalls on the hardened pod
oc exec good -- unshare -m true || echo "Blocked or not permitted (expected)"
Debrief
Hardened SCC, seccomp, capability drops, and SELinux close gaps that restricted defaults alone leave for sophisticated workloads.
What breaks without this:
-
Leftover capabilities / loose syscalls → privilege escalation after container compromise
-
Invented custom SCCs everywhere → unmaintainable exception sprawl
Controls that matter: hardened SCC only when needed, SPO/seccomp profiles, drop ALL then add back, SELinux types, and RHACS drift detection.
Quick facts: do not invent a custom SCC if restricted (plus image fixes) already fits. Detect capability drift continuously.
