diff --git a/deploy/networkpolicies.yaml b/deploy/networkpolicies.yaml index 7a74919..99624ca 100644 --- a/deploy/networkpolicies.yaml +++ b/deploy/networkpolicies.yaml @@ -37,6 +37,32 @@ spec: --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy +metadata: + name: audit-core-whitehat-ingress + namespace: audit-core +spec: + podSelector: + matchLabels: + app.kubernetes.io/name: audit-core + policyTypes: [Ingress] + ingress: + # Governed E2 evidence plane. Both selectors belong to one peer and are + # therefore ANDed: only the registered audit-core probe in the dedicated + # whitehat namespace reaches this port. Application sender authentication + # and tenant scope remain the inner boundary. + - from: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: whitehat + podSelector: + matchLabels: + whitehat.security/plane: "true" + whitehat.security/target: audit-core + ports: + - {protocol: TCP, port: 8080} +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy metadata: name: audit-core-operator-ingress namespace: audit-core diff --git a/docs/operator-runbook.md b/docs/operator-runbook.md index ae87b82..3506bf0 100644 --- a/docs/operator-runbook.md +++ b/docs/operator-runbook.md @@ -118,6 +118,21 @@ custody defect: stop and investigate. ## Sender credential rotation +### Governed E2 evidence identities + +The `whitehat` test plane has a dedicated ingress policy. It admits only pods +in namespace `whitehat` carrying both `whitehat.security/plane: "true"` and +`whitehat.security/target: audit-core`; bearer authentication and sender scope +still apply to every request. The policy is connectivity, not authorization. + +A dated `live-e2` engagement may request exactly two temporary identities. Each +identity is bound to `source=whitehat-security`, one named synthetic tenant, +`may_write=true`, and `may_read=true`. Provision token values only through the +sanctioned sender-registry custody lane and the plane's mount-only credential +projection. Never reuse the production `user-engine` identity. Revoke both +identities and remove their registry entries when the plane lease ends; an +engagement is incomplete until that cleanup is evidenced. + OpenBao path `platform/workloads/audit-core/senders` is the authority for ExternalSecret `audit-core-senders`. The initial in-cluster registry was wrap-migrated on 2026-08-14 without printing or staging its values; do not diff --git a/tests/test_networkpolicies.py b/tests/test_networkpolicies.py new file mode 100644 index 0000000..cc192de --- /dev/null +++ b/tests/test_networkpolicies.py @@ -0,0 +1,26 @@ +from pathlib import Path + + +ROOT = Path(__file__).parents[1] + + +def test_whitehat_ingress_is_bound_to_namespace_and_target_labels(): + documents = (ROOT / "deploy" / "networkpolicies.yaml").read_text().split("\n---\n") + policy = next( + document + for document in documents + if "name: audit-core-whitehat-ingress" in document + ) + + # Both selectors must remain in the same `from` peer. Splitting them into + # two list items changes AND to OR and would admit every pod in either set. + expected_peer = """ - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: whitehat + podSelector: + matchLabels: + whitehat.security/plane: \"true\" + whitehat.security/target: audit-core""" + assert expected_peer in policy + assert policy.count(" - namespaceSelector:") == 1 + assert " - {protocol: TCP, port: 8080}" in policy diff --git a/workplans/AUDIT-WP-0008-tenancy-posture-alignment.md b/workplans/AUDIT-WP-0008-tenancy-posture-alignment.md index c628dc0..9fd3d14 100644 --- a/workplans/AUDIT-WP-0008-tenancy-posture-alignment.md +++ b/workplans/AUDIT-WP-0008-tenancy-posture-alignment.md @@ -393,17 +393,20 @@ minute, and requires two temporary read-enabled identities each scoped to one fixture tenant. The production `user-engine` identity remains unchanged and is not a test credential. -Whitehat supplied a production engagement record at `3770b41` and a bounded -adapter at `7396fe7`. Target review found that the adapter omits audit-core's -required `Idempotency-Key` header on POST, so it would abort fixture seeding -with `idempotency_key_mismatch` and cannot yet produce evidence. Review reply -`74b815ea-341f-455d-8fdb-2333f5753f76` accepted the two-identity fixture shape -in principle and requested that fix plus corrected production-approval and -owner-acknowledgement provenance before formal acknowledgement. +Whitehat supplied and corrected a bounded adapter, including audit-core's +required `Idempotency-Key` and deterministic retry payloads. The original +production engagement was then cancelled at the session cutoff with zero +target requests and its identifier is terminal. Whitehat subsequently added +the governed test-plane contract and fail-closed admission at `95129d7`. -This is progress, not evidence and not live authorization. T05 becomes `done` -only when the corrected engagement is acknowledged, the bounded run completes, -and its sanitized target report has been routed to `risk-nexus`. +Audit-core now declares a dedicated ingress peer for that plane: only a pod in +namespace `whitehat` carrying both the plane and `target=audit-core` labels can +reach port 8080 through it. Authentication and tenant scope remain mandatory. +The operator runbook records the exact two-identity fixture shape and cleanup +obligation. This is readiness, not evidence or live authorization. T05 becomes +`done` only after a new engagement is approved and owner-acknowledged, the +cluster plane and value-safe custody broker are provisioned, the bounded run +completes, and its sanitized target report reaches `risk-nexus`. ```task id: AUDIT-WP-0008-T06