PR #214: "Containerise the payments API and deploy it"
Author's description: "Adds a Dockerfile and a Deployment so we can ship the API. Image builds, pods start, tests pass. Cleaned up the secrets after the build. Needs host access for metrics, so I made it privileged."
Your job as reviewer: read both files below and write down every security problem, ranked by impact. Then press Reveal ranked findings to compare with the answer key.
Dockerfile
loading…
k8s/deployment.yaml
loading…
| # | Impact | Where | Finding | Fix |
|---|
Mission 1: find the key that "was deleted"
The PR author ran rm -f /app/.env /app/.build-token at the end of the Dockerfile. Pick the vulnerable image, type the fake key fake-demo-key-123 in the search box and press Scan layers. Click the highlighted rows to see which file in which layer still holds it. Then press Show what docker run sees: .env and .build-token are gone from the merged filesystem, yet the layers still hold them. Finally switch to fixed and scan again.
Image history (oldest first):
| # | Instruction (docker history) | Layer | Size | Hits |
|---|
Rows from the base image are dimmed. "metadata" rows (ARG, ENV, EXPOSE, CMD…) create no layer, but they still appear in the history.
Layer contents
Option 2: from the terminal
docker history --no-trunc dhacker-pr-review/api-vulnerable:lab | grep fake-demo-key-123
docker save dhacker-pr-review/api-vulnerable:lab -o vuln.tar
mkdir vuln && tar -xf vuln.tar -C vuln && cd vuln
# every layer is a tar file: which ones contain the key?
for l in blobs/sha256/*; do tar -xOf "$l" 2>/dev/null | grep -aq fake-demo-key-123 && echo "key in $l"; done
# layers in order (oldest first), then look for .env and its deletion marker
python3 -c "import json;print('\n'.join(json.load(open('manifest.json'))[0]['Layers']))"
tar -tf blobs/sha256/<layer> | grep -E 'app/(\.env|\.build-token|\.wh\.)'
tar -xOf blobs/sha256/<layer-with-.env> app/.env
# what the running container sees:
docker run --rm dhacker-pr-review/api-vulnerable:lab cat /app/.env # No such fileMission 2: turn review opinions into rules
Choose a manifest and a Pod Security Standards level, then press Run policy check. Each control from the Kubernetes docs is listed with PASS or FAIL and the exact field that caused it. Start with vulnerable at restricted; then switch the level to baseline and see which failures disappear. Finally run fixed.
Pod Security Standards controls
Field paths are shown relative to spec.template.spec (the pod spec inside the Deployment).
| Result | Profile | Control | Field that caused it |
|---|
Manifest (offending lines marked)
Beyond PSS: reviewer checks the standard does not cover
Option 2: from the terminal
# offline schema validation (needs internet once, to fetch the Kubernetes JSON schemas) docker run --rm -v "$PWD:/w" -w /w ghcr.io/yannh/kubeconform:v0.8.0 -summary -strict vulnerable/k8s/deployment.yaml # the same rules as Rego, evaluated by Conftest (offline) docker run --rm -v "$PWD:/w" -w /w openpolicyagent/conftest:v0.71.1 test \ --policy policy -n pss.baseline -n pss.restricted vulnerable/k8s/deployment.yaml # the Python checker the console uses (needs: pip install pyyaml) python3 policy/pss_check.py vulnerable/k8s/deployment.yaml --level restricted curl -s "http://127.0.0.1:8090/api/check?target=vulnerable&level=restricted&mode=enforce"
Mission 3: compare vulnerable and fixed
Pick a file. Left is the PR as submitted, right is the fixed version. Amber lines are removed or changed, cyan lines are new. The scoreboard below is computed from the same data as Missions 1 and 2.
vulnerable PR as submitted
fixed after review
Scoreboard
| Check | vulnerable | fixed |
|---|
Option 2: from the terminal
diff -u vulnerable/Dockerfile fixed/Dockerfile diff -u vulnerable/k8s/deployment.yaml fixed/k8s/deployment.yaml python3 policy/pss_check.py vulnerable/k8s/deployment.yaml; python3 policy/pss_check.py fixed/k8s/deployment.yaml docker run --rm dhacker-pr-review/api-vulnerable:lab id # uid=0(root) docker run --rm dhacker-pr-review/api-fixed:lab id # uid=10001 gid=10001