Lesson 20 Security & Best Practices
Theme:

Homework

Audit, harden, and enforce security policies across Helm charts using real-world tools and techniques.

Submission: For each task, include the files you created or modified, rendered YAML output, and scanner reports (screenshots or text). Be prepared to explain your security rationale for each decision in class.

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:

For each checklist item, include:

  1. A short description of what to check
  2. The severity level (critical, high, medium, low)
  3. An example of a compliant configuration (YAML snippet)
  4. 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

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:

  1. Pin the image to a specific tag or digest (not :latest)
  2. Remove the hardcoded password; use a Kubernetes Secret reference instead
  3. Create a dedicated ServiceAccount with automountServiceAccountToken: false
  4. Add pod-level securityContext (non-root, seccomp, fsGroup)
  5. Add container-level securityContext (drop ALL capabilities, no privilege escalation, read-only root FS)
  6. Set resource requests and limits
  7. Remove hostPort
  8. Enable a default-deny NetworkPolicy
  9. Add liveness and readiness probes
  10. 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

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:

  1. Write the ConstraintTemplate with complete Rego logic
  2. Write the Constraint resource that applies it to all namespaces except kube-system
  3. Create a test pod YAML that violates the constraint
  4. Create a test pod YAML that passes the constraint
  5. If you have Gatekeeper installed, demonstrate the admission rejection. Otherwise, use gator test (the Gatekeeper CLI) to validate locally
Tip: Install the Gatekeeper CLI for local testing: brew install gator. Then run gator test --filename=constraints/ --filename=test-pods/ to validate your constraints without a live cluster.

Self-check

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