From d129ba60efe4a69e1673009e0576b2da1e8099ce Mon Sep 17 00:00:00 2001 From: thanhnv Date: Sat, 18 Jul 2026 00:15:38 +0700 Subject: [PATCH] fix: require Vault audit signing in production --- docs/plans/CASAN_BACKLOG_STATUS.md | 2 +- packages/casan-harness/scripts/bash/sign-audit-head.sh | 4 ++++ packages/casan-harness/tests/phase-sec02-tests.sh | 6 ++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/plans/CASAN_BACKLOG_STATUS.md b/docs/plans/CASAN_BACKLOG_STATUS.md index 024cd2c..10e7031 100644 --- a/docs/plans/CASAN_BACKLOG_STATUS.md +++ b/docs/plans/CASAN_BACKLOG_STATUS.md @@ -36,7 +36,7 @@ | # | Hạng mục | Trạng thái | Bước tiếp theo (bản production) | |---|---|:--:|---| -| T2.1 | KMS mặc định + HSM | 🟡 Docker lab ✅ (Vault Transit) | `infra/local-prod` dựng Vault dev @ `:18200`; `infra-lab verify` chứng minh sign+verify. Prod: Vault/AWS-KMS/CloudHSM + token ngắn hạn qua IdP; bỏ fallback khoá local ở môi trường prod. | +| T2.1 | KMS mặc định + HSM | 🟡 production fail-closed + Docker lab ✅ | `infra/local-prod` dựng Vault dev @ `:18200`; `infra-lab verify` chứng minh sign+verify. `sign-audit-head.sh` nay từ chối local-key fallback khi `CASAN_PROFILE=prod` (SEC-02 test). Còn: Vault/AWS-KMS/CloudHSM thật + token ngắn hạn qua IdP và Transit encryption cho dữ liệu tenant. | | T2.2 | WORM store thật (S3 Object Lock) | 🟡 Docker lab ✅ (MinIO Object Lock) | MinIO bucket `casan-worm` bật Object Lock COMPLIANCE 1d. Prod: S3 Object Lock/QLDB + trusted timestamp; cần AWS creds + bucket Object-Lock. | | T2.3 | Dashboard deploy + auth | 🟡 Docker lab ✅ (nginx basic auth + /healthz) | Dashboard container + nginx reverse-proxy @ `:18080`, user/pass lab `casan/casan`; `/healthz` exposed. Prod: host/TLS/OIDC or enterprise auth. | | T2.4 | Kênh alert managed + on-call | 🟡 Docker lab ✅ (webhook emulator) | `alert-webhook` @ `:19092` nhận live POST. Prod: trỏ `CASAN_ALERT_WEBHOOK` tới Slack/PagerDuty + rota/on-call thật. | diff --git a/packages/casan-harness/scripts/bash/sign-audit-head.sh b/packages/casan-harness/scripts/bash/sign-audit-head.sh index c83b07e..1544247 100755 --- a/packages/casan-harness/scripts/bash/sign-audit-head.sh +++ b/packages/casan-harness/scripts/bash/sign-audit-head.sh @@ -103,6 +103,10 @@ PY fi else # Fallback — local key (dev environment without Vault) + if [[ "${CASAN_PROFILE:-}" == "prod" ]]; then + echo "SIGN_AUDIT_HEAD_FAIL reason=vault_kms_required_in_prod" >&2 + exit 1 + fi AUDIT_PRIV="$CASAN_GOVERNANCE_ROOT/audit-private.pem" if [[ ! -f "$AUDIT_PRIV" ]]; then echo "SIGN_AUDIT_HEAD_SKIP no private key and VAULT_ADDR not set — verify will show anchor=unsigned" >&2 diff --git a/packages/casan-harness/tests/phase-sec02-tests.sh b/packages/casan-harness/tests/phase-sec02-tests.sh index 41a777d..cca0de2 100644 --- a/packages/casan-harness/tests/phase-sec02-tests.sh +++ b/packages/casan-harness/tests/phase-sec02-tests.sh @@ -56,6 +56,12 @@ env CASAN_VERIFY_STRICT=1 CASAN_AUDIT_KEY_DIR="$KD2" bash "$BASH_DIR/governance- && pass "unsigned head from enforced run FAILS strict verify (fail-closed)" \ || fail "unsigned head passed strict verify" +# 4) Production must never silently fall back from Vault Transit to a local key. +printf '{"timestamp":"2026-07-18T00:00:00Z","action":"test"}\n' > "$WORK/audit.jsonl" +[[ "$(rc_of env CASAN_PROFILE=prod VAULT_ADDR= VAULT_TOKEN= CASAN_GOVERNANCE_ROOT="$WORK/prod-gov" bash "$BASH_DIR/sign-audit-head.sh" "$WORK/audit.jsonl")" -ne 0 ]] \ + && pass "prod audit signer refuses local-key fallback when Vault is unavailable" \ + || fail "prod audit signer accepted a local-key fallback" + echo "" echo "===== SEC-02 SUMMARY: PASS=$PASS FAIL=$FAIL =====" [[ "$FAIL" -eq 0 ]] || exit 1