Homework
Audit, harden, and enforce security policies across Helm charts using real-world tools and techniques.
Task 1 — Security Audit Checklist
Create a comprehensive security audit checklist for Helm charts. Your checklist must be a structured document (YAML, JSON, or markdown) with at least 20 items organised into these categories:
- Pod Security — securityContext, capabilities, privilege escalation, read-only filesystem, non-root user, seccomp profiles
- Resource Management — CPU/memory requests and limits, LimitRanges, ResourceQuotas
- RBAC & Identity — dedicated ServiceAccount, minimal Role verbs, no wildcard permissions, automountServiceAccountToken disabled
- Network Security — default-deny NetworkPolicies, ingress/egress restrictions, no hostNetwork or hostPort
- Image & Supply Chain — pinned image tags or SHA digests, trusted registries only, image pull secrets, no
:latesttag - Secrets Hygiene — no hardcoded secrets in values.yaml, external secret management integration, encrypted at rest
For each checklist item, include:
- A short description of what to check
- The severity level (
critical,high,medium,low) - An example of a compliant configuration (YAML snippet)
- An example of a non-compliant configuration
Then apply your checklist to the default output of helm create myapp and document which items pass and which fail.
Self-check
- Checklist contains at least 20 items across all 6 categories
- Each item has description, severity, compliant example, and non-compliant example
- Audit of
helm createdefault chart identifies at least 8 failing items - Checklist is machine-readable (YAML or JSON) or clearly structured (markdown table)
Task 2 — Harden a Vulnerable Chart
Start with the following intentionally insecure values.yaml and Deployment template. Fix every security issue.
Insecure values.yaml
# VULNERABLE - DO NOT USE IN PRODUCTION
replicaCount: 1
image:
repository: myregistry.io/webapp
tag: latest
pullPolicy: Always
dbPassword: "s3cret-passw0rd!" # hardcoded secret
serviceAccount:
create: false # uses default SA
securityContext: {} # no pod security
containerSecurityContext: {} # no container security
resources: {} # no resource limits
networkPolicy:
enabled: false # no network restrictions
Insecure Deployment snippet
containers:
- name: webapp
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
securityContext:
privileged: true
runAsUser: 0
ports:
- containerPort: 8080
hostPort: 8080 # binds to node port
env:
- name: DB_PASSWORD
value: {{ .Values.dbPassword }}
Your hardened version must address all of the following:
- Pin the image to a specific tag or digest (not
:latest) - Remove the hardcoded password; use a Kubernetes Secret reference instead
- Create a dedicated ServiceAccount with
automountServiceAccountToken: false - Add pod-level securityContext (non-root, seccomp, fsGroup)
- Add container-level securityContext (drop ALL capabilities, no privilege escalation, read-only root FS)
- Set resource requests and limits
- Remove
hostPort - Enable a default-deny NetworkPolicy
- Add liveness and readiness probes
- Add an image pull secret reference
Render both versions and run kube-score or Polaris against them. Include a before/after comparison of the scanner scores.
Self-check
- All 10 issues above are fixed in the hardened chart
- kube-score reports zero CRITICAL findings on the hardened version
- Polaris score improves by at least 40 points (e.g., from ~30 to 70+)
helm templaterenders cleanly with no errors- The hardened chart deploys to a
restrictedPSS namespace without admission errors
Task 3 — OPA Gatekeeper Constraints
Write OPA Gatekeeper ConstraintTemplates and Constraints that enforce three security policies across your cluster. Each constraint must block non-compliant resources at admission time.
Constraint 1: Require Non-Root Containers
Create a ConstraintTemplate (using Rego) and a Constraint that rejects any pod where runAsNonRoot is not true or runAsUser is 0.
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8srequirenonroot
spec:
crd:
spec:
names:
kind: K8sRequireNonRoot
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequirenonroot
# YOUR REGO CODE HERE:
# - Check spec.securityContext.runAsNonRoot == true
# - Check all containers have runAsUser != 0
# - Return violation message for non-compliant pods
Constraint 2: Deny Privileged Containers
Block any container with securityContext.privileged: true or allowPrivilegeEscalation: true.
Constraint 3: Require Resource Limits
Reject any pod where any container is missing resources.limits.cpu or resources.limits.memory.
For each constraint:
- Write the ConstraintTemplate with complete Rego logic
- Write the Constraint resource that applies it to all namespaces except
kube-system - Create a test pod YAML that violates the constraint
- Create a test pod YAML that passes the constraint
- If you have Gatekeeper installed, demonstrate the admission rejection. Otherwise, use
gator test(the Gatekeeper CLI) to validate locally
brew install gator. Then run gator test --filename=constraints/ --filename=test-pods/ to validate your constraints without a live cluster.
Self-check
- Three ConstraintTemplates with syntactically valid Rego
- Three Constraints excluding
kube-system - For each constraint: one violating and one passing test case
gator testor live admission controller correctly rejects violating pods- Error messages are descriptive (include the container name and the specific violation)
Grading Rubric
| Criterion | Points | Requirements |
|---|---|---|
| Task 1 — Audit checklist | 25 | 20+ items across 6 categories; each with severity, compliant, and non-compliant examples; audit of default chart with 8+ failures identified |
| Task 2 — Chart hardening | 35 | All 10 issues fixed; kube-score/Polaris before and after comparison; deploys to restricted PSS namespace; no hardcoded secrets |
| Task 3 — OPA Gatekeeper | 30 | 3 ConstraintTemplates with valid Rego; 3 Constraints with namespace exclusion; 6 test pods (pass/fail pairs); demonstrated with gator test or live cluster |
| Code quality & documentation | 10 | Clean YAML; meaningful comments; clear explanations of security rationale for each decision |