Lab 34 - Security review challenge

Lab 34 - Security review challenge

Infodiscover

Goal: a team asks for a security review before go-live. Find the problems, fix them, and prove each fix. Chapters: Day 4 - all of them.

The application

cd ~
cat > payments.yaml <<'YAML'
apiVersion: v1
kind: Namespace
metadata: { name: payments }
---
apiVersion: v1
kind: ServiceAccount
metadata: { name: payments-app, namespace: payments }
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata: { name: payments-app-admin }
subjects: [{ kind: ServiceAccount, name: payments-app, namespace: payments }]
roleRef: { kind: ClusterRole, name: cluster-admin, apiGroup: rbac.authorization.k8s.io }
---
apiVersion: v1
kind: ConfigMap
metadata: { name: payments-cfg, namespace: payments }
data:
  DB_HOST: db
  DB_PASSWORD: "Summer2026!"
---
apiVersion: apps/v1
kind: Deployment
metadata: { name: api, namespace: payments }
spec:
  replicas: 2
  selector: { matchLabels: { app: api } }
  template:
    metadata: { labels: { app: api } }
    spec:
      serviceAccountName: payments-app
      containers:
        - name: api
          image: nginx:latest
          envFrom: [{ configMapRef: { name: payments-cfg } }]
          securityContext: { privileged: true }
---
apiVersion: apps/v1
kind: Deployment
metadata: { name: db, namespace: payments }
spec:
  replicas: 1
  selector: { matchLabels: { app: db } }
  template:
    metadata: { labels: { app: db } }
    spec:
      containers:
        - name: db
          image: nginx:1.27
---
apiVersion: v1
kind: Service
metadata: { name: db, namespace: payments }
spec:
  selector: { app: db }
  ports: [{ port: 80 }]
YAML
kubectl apply -f payments.yaml

(db is a stand-in - nginx on port 80 plays the database.)

Your review

Find at least six findings. Tools you know: kubectl auth can-i, kubectl get ... -o yaml, trivy config, trivy image, the PSA dry run, ~/reach.sh from Lab 32.

Definition of done:

  1. payments-app can do nothing outside payments - and inside only what an API server that reads its own ConfigMaps needs.
  2. No password in a ConfigMap.
  3. Namespace payments enforces Pod Security baseline, warns on restricted; api runs without warnings.
  4. Only api can reach db; nothing from other namespaces reaches api except Traefik.
  5. No latest images.
  6. trivy config on your final manifests shows no HIGH or CRITICAL findings.

Hints

kubectl auth can-i --list --as system:serviceaccount:payments:payments-app, then kubectl get clusterrolebindings -o wide | grep payments.

trivy config ~/payments.yaml gives you a list in seconds.

Lab 29’s hardened.yaml shows a Pod that passes restricted. The API container needs the unprivileged nginx image and port 8080.

Solution

#FindingFix
1ServiceAccount bound to cluster-admindelete the ClusterRoleBinding; Role get,list on configmaps in payments + RoleBinding
2Password in a ConfigMap (readable with view rights)move DB_PASSWORD to a Secret, envFrom.secretRef; rotate the password - it was exposed
3privileged containerremove; add restricted securityContext, nginxinc/nginx-unprivileged:1.27
4nginx:latestpin a version (or digest)
5no Pod Security labelsenforce=baseline, warn=restricted (+ audit=restricted)
6no NetworkPolicies - db reachable from everywheredefault deny ingress; db from app=api; api from namespace traefik
7no resource limitsrequests + limits
8token automounted in db (no API use)automountServiceAccountToken: false
kubectl delete clusterrolebinding payments-app-admin
kubectl create role cfg-reader -n payments --verb=get,list --resource=configmaps
kubectl create rolebinding payments-app -n payments --role=cfg-reader --serviceaccount=payments:payments-app
kubectl auth can-i list secrets -A --as system:serviceaccount:payments:payments-app   # no
kubectl create secret generic payments-db -n payments --from-literal=DB_PASSWORD='rotated-value'
kubectl patch cm payments-cfg -n payments --type=json -p '[{"op":"remove","path":"/data/DB_PASSWORD"}]'
kubectl label ns payments pod-security.kubernetes.io/enforce=baseline \
  pod-security.kubernetes.io/warn=restricted pod-security.kubernetes.io/audit=restricted

For the Deployments and NetworkPolicies, edit payments.yaml, re-apply and re-run trivy config. Discuss: which findings would an admission policy (Lab 31) have prevented at deploy time?

Clean up

kubectl delete ns payments
kubectl delete clusterrolebinding payments-app-admin --ignore-not-found