feat(lab11): hardened nginx reverse proxy + ModSecurity WAF sidecar - #6
Open
alileeeek wants to merge 11 commits into
Open
feat(lab11): hardened nginx reverse proxy + ModSecurity WAF sidecar#6alileeeek wants to merge 11 commits into
alileeeek wants to merge 11 commits into
Conversation
…nces; lab1 /api/Products endpoint - lec1 Slide 5: '-.-->' is not valid mermaid (use '-.->'), quote emoji labels - all submission templates with nested code blocks now use 4-backtick outer fences so GitHub stops closing them at the first inner fence - lab1 template + acceptance criteria still referenced /rest/products, which 404s in Juice Shop v20.0.0 (moved to /api/Products) Signed-off-by: Dmitrii Creed <creeed22@gmail.com>
…ame limit
Threagile uses the model title as the risks.xlsx sheet name; the shipped
41-char title crashed report generation at the Excel step ('the sheet name
length exceeds the 31 characters limit'), leaving JSONs/diagrams but no
risks.xlsx or report.pdf. Verified full output with threagile/threagile:0.9.1.
Also documented the pitfall in lab2.md.
Signed-off-by: Dmitrii Creed <creeed22@gmail.com>
Signed-off-by: Dmitrii Creed <creeed22@gmail.com>
…EADME Task 1 jq broke on real Checkov output: a directory scan runs multiple frameworks (terraform + secrets), so results_json.json is a JSON array and .results.failed_checks[] errored with 'Cannot index array with string'. Use .[] to iterate frameworks. Open-source Checkov assigns no severities (a Prisma Cloud feature), so the severity breakdown is replaced with passed/failed and triage is framed around rule frequency. Pulumi was referenced in Task 1's report, acceptance criteria, and rubric but Checkov never scanned it (no pulumi framework; the 'shipped' rendered-state file never existed). Pulumi is scanned by KICS in Task 2 — moved its severity table there and fixed the Task 2 jq paths (kics-ansible/, kics-pulumi/ instead of a kics/ dir that is never created). Closed the 6.3 numbering gap. README aligned to the actual lab (Checkov + KICS + custom Checkov policy): dropped tfsec/Terrascan/OPA references, corrected Pulumi as AWS (not GCP), and removed the nonexistent EKS resource from the Terraform description. Reported by Albert Khechoyan. Signed-off-by: Dmitrii Creed <creeed22@gmail.com>
Student-reported breakage where lab instructions assumed tool behavior the
pinned versions no longer have. Each fix verified against the real binaries.
Lab 7 (Trivy 0.69):
- 7.3 jq: add `installed: .InstalledVersion` so the 7.4 "Installed" column has data
- 7.7: `trivy k8s --namespace` was removed in 0.69 -> `--include-namespaces`
Lab 9 (Falco 0.43.1, Conftest 0.68):
- manifests are k8s/juice-{hardened,unhardened}.yaml, not flat good-pod/bad-pod
- 9.3 trigger B: a write to /usr/local/bin fires nothing in the 0.43.1 default
ruleset (rule moved to incubating feed) -> `cat /etc/shadow` (Read sensitive
file untrusted), confirmed firing in a live Falco run
- 9.4 hint: point at the real `open_write` macro instead of a non-existent rule
- bonus: `tcp.dport` -> `fd.sport` (real Falco field)
- add inotify pitfall + `-o watch_config_files=false` workaround for WSL2
- wire the shipped compose policy into 9.9 as a second target-shape demo
Reported by students in the DevSecOps-Intro cohort.
Signed-off-by: Dmitrii Creed <creeed22@gmail.com>
…rule passes
The hardened manifest pinned its image by tag (:v19.0.0), so a student who
implements the optional 5th hardening rule ("image must use sha256 digest,
not :tag") saw the GOOD manifest FAIL — contradicting 9.9-A's "should PASS
(0 failures)". Pin by the resolved v19.0.0 multi-arch index digest; the
unhardened manifest (:latest) still fails the rule as the bad example.
Digest resolved via 'docker buildx imagetools inspect', not fabricated.
Signed-off-by: Dmitrii Creed <creeed22@gmail.com>
…dened Signed-off-by: Dmitrii Creed <creeed22@gmail.com>
Docker Desktop's LinuxKit VM kernel lacks BTF + tracepoints, so Falco runs but detects nothing on Mac (esp. Apple Silicon). The Setup section wrongly said Docker Desktop 'is fine' — corrected it, and added a Common Pitfalls entry with the Colima fix and a 'test -f /sys/kernel/btf/vmlinux' gate check. Reported by a student on an M-series Mac. Signed-off-by: Dmitrii Creed <creeed22@gmail.com>
…macOS The run-imports.sh helper did not work as shipped: - Line 55 used mapfile, a bash 4+ builtin absent on stock macOS bash 3.2, so the script aborted on macOS. Replaced with a portable while-read loop and set -u-safe array handling; verified under bash 3.2.57. - Every hardcoded input path was wrong. Corrected to the real Lab 4-7 outputs and anchored them to the repo root so the script runs from any directory. - The script required DD_API while lab10.md tells students to export DD_URL, so require_env aborted immediately. It now accepts DD_URL and derives the API base. - It imported Nuclei (not in this course) and skipped Checkov/KICS/Trivy image/Trivy operator. It now imports exactly the documented Lab 4-7 table, with scan_type fallbacks verified against the DefectDojo 2.58.3 parser source. lab10.md aligned: correct script name (was import-all.sh), KICS split into kics-ansible/kics-pulumi, fixed the manual curl template path, and added the env.sample the plumbing promised. Importer outputs are now gitignored. Reported by Albert Khechoyan. Signed-off-by: Dmitrii Creed <creeed22@gmail.com>
The shipped nginx.conf listened on 8080/8443 and docker-compose.yml published 8080:8080/8443:8443, but every instruction and verification command in lab11.md assumes 80/443 (curl http://localhost, https://localhost, s_client -connect localhost:443, and the 11.1 spec 'HTTP on 80 -> HTTPS 443'). Following the lab gave connection-refused on 443. Switch nginx to listen 80/443, drop the :8443 from the redirect target, and publish 80:80/443:443. The juice backend stays behind the proxy on expose:3000 (verified end-to-end: nginx reaches juice:3000 with expose only, so publishing the backend on the host is unnecessary and would defeat the lab). Added a remap hint for rootless Docker / busy ports. Reported by Albert Khechoyan. Signed-off-by: Dmitrii Creed <creeed22@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Goal
Lab 11 (Bonus) submission: Hardened Nginx reverse proxy with TLS 1.3, security headers, rate limiting, and a ModSecurity v3 + OWASP CRS WAF sidecar to block SQL injection attempts.
Changes
labs/lab11/reverse-proxy/nginx.confwith production-grade hardening (TLS 1.3 only, 6 security headers, rate limiting, timeouts, cipher hardening).labs/lab11/waf/docker-compose.override.ymlfor the WAF sidecar (ModSecurity v3 + OWASP CRS v4.x).submissions/lab11.mdwith verification proofs, cert-rotation runbook, and tradeoff analysis.Testing
' OR 1=1--) passes through Nginx alone but is blocked (HTTP 403) by the WAF sidecar.Artifacts
labs/lab11/reverse-proxy/nginx.conflabs/lab11/waf/docker-compose.override.ymlsubmissions/lab11.mdTask Checklist