-
Notifications
You must be signed in to change notification settings - Fork 0
feat(release): refuse lightweight tags and pin k8s by digest #109
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
550c237
2119788
d00c78f
f62e7ab
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| # Doctoring — CI attack-evidence battery (issue #11) | ||
|
|
||
| This note grounds the issue #11 slice: the compiled gateway binary is started | ||
| in CI with a hermetic libcoraza engine, a deterministic OWASP CRS attack | ||
| battery is fired over real HTTP, and every attempt must be blocked with the | ||
| cited CRS rule id and recorded as a security event that keeps the forwarded | ||
| client IP unmasked. | ||
|
|
||
| ## What is proven (and what is not) | ||
|
|
||
| Proven end to end on the real binary: operator-supplied `CORAZA_LIB_PATH` | ||
| loading, rules-file admission, per-transaction evaluation of method/URI/body, | ||
| block responses citing `coraza/crs: rule <id>`, benign traffic still | ||
| forwarding, and unmasked client attribution in `/api/events`. | ||
|
|
||
| Not proven: detection *quality* against arbitrary live traffic. The CI engine | ||
| is the build-script ABI stub (`src/coraza_abi_stub.rs`), a fixture that | ||
| mirrors the libcoraza C ABI, not Coraza itself. Quality evidence stays with an | ||
| operator deployment using a real libcoraza plus the OWASP Core Rule Set; this | ||
| slice only removes "the path was never exercised in CI" from the gap list. | ||
|
|
||
| ## Adopted standards and literature | ||
|
|
||
| OWASP Foundation. (n.d.). *OWASP Core Rule Set documentation*. | ||
| https://coreruleset.org/docs/ | ||
|
|
||
| - **Design impact:** Battery entries map to canonical CRS rule families — | ||
| 942100 SQLi (libinjection), 941100 XSS (libinjection), 930100 path | ||
| traversal, 932100 Unix command injection, 944120 Log4j JNDI. Rule ids in | ||
| block reasons and events stay CRS ids so operator dashboards read the same | ||
| vocabulary in CI evidence and production. | ||
|
|
||
| Scarfone, K., & Mell, P. (2007). *Guide to intrusion detection and prevention | ||
| systems (IDPS)* (NIST Special Publication 800-94). National Institute of | ||
| Standards and Technology. https://doi.org/NIST.SP.800-94 | ||
|
|
||
| - **Design impact:** IDPS evaluation distinguishes the detection *path* from | ||
| detection *efficacy*. SP 800-94's testing guidance motivates keeping the two | ||
| claims separate: CI asserts the prevention path (signature → interrupt → | ||
| block → record), while efficacy against evasive payloads requires curated | ||
| corpora and is explicitly out of scope for this fixture. | ||
|
|
||
| Saltzer, J. H., & Schroeder, M. D. (1975). The protection of information in | ||
| computer systems. *Proceedings of the IEEE*, *63*(9), 1278–1308. | ||
| https://doi.org/10.1109/PROC.1975.9939 | ||
|
|
||
| - **Design impact:** Complete mediation and fail-safe defaults. The battery | ||
| runs through the same route pipeline (`mode: block`) as production traffic, | ||
| so no test-only bypass exists; an engine that fails to load refuses startup | ||
| before bind instead of degrading silently. | ||
|
|
||
| MITRE. (n.d.). *CWE-20: Improper input validation*. MITRE Corporation. | ||
| https://cwe.mitre.org/data/definitions/20.html | ||
|
|
||
| - **Design impact:** The battery covers encoded variants (`%3Cscript`, | ||
| `%24%7BJNDI`, `..%2F`) because input-validation defects classically live at | ||
| decoding boundaries; the gateway evaluates the raw request line exactly as | ||
| received, so fixtures pin that behavior rather than a decoded copy. | ||
|
|
||
| ## Verification posture | ||
|
|
||
| - `tests/binary.rs::live_gateway_detects_owasp_attack_battery_end_to_end` | ||
| spawns the binary, creates the block route over the admin API, fires nine | ||
| battery cases (GET query attacks across five rule families plus a POST-body | ||
| XSS), asserts HTTP 403 + `engine=coraza` + cited rule id per case, asserts a | ||
| benign request forwards, and asserts `/api/events` records one event per | ||
| attempt with `X-Forwarded-For` preserved verbatim. | ||
| - `src/coraza_inprocess.rs::stub_engine_battery_matches_each_owasp_family` | ||
| pins the fixture contract itself, including first-match ordering so the | ||
| overlapping `; cat /etc/passwd` payload attributes to RCE (932100), not | ||
| traversal. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| #!/usr/bin/env bash | ||
| # Fail closed unless REF is an annotated git tag (lightweight/unsigned refs | ||
| # are not admitted to the release pipeline). | ||
| set -euo pipefail | ||
| if [[ $# -ne 1 ]]; then | ||
| echo "usage: $0 <tag>" >&2 | ||
| exit 1 | ||
| fi | ||
| ref="$1" | ||
| if [[ ! "$ref" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then | ||
| echo "admit-release-tag: $ref is not a vX.Y.Z tag" >&2 | ||
| exit 1 | ||
| fi | ||
| kind="$(git cat-file -t "$ref" 2>/dev/null || true)" | ||
| if [[ "$kind" != "tag" ]]; then | ||
| echo "admit-release-tag: $ref is ${kind:-missing}, not an annotated tag; use git tag -a" >&2 | ||
| exit 1 | ||
| fi | ||
|
Comment on lines
+14
to
+18
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔍 Admission checks annotated, not signed The comment (admit-release-tag.sh) and CHANGELOG claim unsigned tags are refused, but the check only rejects lightweight tags via Was this helpful? React with 👍 or 👎 to provide feedback. |
||
| echo "admit-release-tag: admitted annotated tag $ref" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| #!/usr/bin/env bash | ||
| # Fail closed unless IMAGE-DIGEST.txt is a GHCR content digest, then print | ||
| # the Kubernetes image line operators must pin (never a floating tag). | ||
| set -euo pipefail | ||
| if [[ $# -ne 1 ]]; then | ||
| echo "usage: $0 <IMAGE-DIGEST.txt>" >&2 | ||
| exit 1 | ||
| fi | ||
| file="$1" | ||
| if [[ ! -f "$file" ]]; then | ||
| echo "pin-k8s-digest: missing $file" >&2 | ||
| exit 1 | ||
| fi | ||
| ref="$(tr -d '[:space:]' < "$file")" | ||
| if [[ ! "$ref" =~ ^ghcr\.io/contextualwisdomlab/waf-ids-ai-soc@sha256:[0-9a-f]{64}$ ]]; then | ||
| echo "pin-k8s-digest: refused non-digest or wrong image: $ref" >&2 | ||
| exit 1 | ||
| fi | ||
| printf 'image: %s\nimagePullPolicy: IfNotPresent\n' "$ref" |
Uh oh!
There was an error while loading. Please reload this page.