Prepare scoped factory audit custody and enforce receiver compatibility
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a07ff8-19d0-7820-b4d0-1353833cb7fc
This commit is contained in:
parent
d3a502b45c
commit
bfe65a5b05
11 changed files with 1053 additions and 1 deletions
121
docs/credential-lane-designs/factory-audit-senders-review.md
Normal file
121
docs/credential-lane-designs/factory-audit-senders-review.md
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
# Factory audit senders: concrete custody review
|
||||
|
||||
CCR-2026-0021 and CCR-2026-0022 are **proposed**. RPF-WP-0035-T08 owns the
|
||||
platform work; AUDIT-WP-0009-T09/T11 retain receiver admission. This packet
|
||||
requires the named platform operator, Audit Core owner and each producer owner
|
||||
to approve its request before native credential mutation.
|
||||
|
||||
## Scope to approve
|
||||
|
||||
| Request | Producer / exact source | OpenBao path | Producer Secret / key |
|
||||
| --- | --- | --- | --- |
|
||||
| CCR-2026-0021 | approval-engine | platform/workloads/approval-engine/audit-sender | approval-engine/approval-engine-audit / audit-token |
|
||||
| CCR-2026-0022 | informed-decision | platform/workloads/informed-decision/audit-sender | informed-decision/informed-decision-audit / token |
|
||||
|
||||
Each sender is limited to `tenant:platform`, write true, read false,
|
||||
`evidence_kind: load-bearing`, `secret_policy: redact`. The producer receives
|
||||
only its own `AUDIT_TOKEN`. `CUSTODY_REQUEST` is a non-secret provenance marker
|
||||
stored beside that token, enabling an interrupted first provision to identify
|
||||
its own version-1 value. It is not projected to the producer.
|
||||
|
||||
Each lane has its own exact-path policy, Kubernetes auth role and namespace-
|
||||
restricted ClusterSecretStore. Only `external-secrets/external-secrets` may
|
||||
log in to the reader role (15-minute session). Neither producer can read the
|
||||
full sender registry or its sibling's token. The coding-agent boundary gains
|
||||
exact denies on the two new data/metadata paths; existing rules are preserved.
|
||||
|
||||
The approved first-provision operation would generate two independent values
|
||||
in the attended platform process, store them with CAS=0, and append the exact
|
||||
identities to `platform/workloads/audit-core/senders` with compare-and-set on
|
||||
its observed KV version. That process necessarily reads the existing registry
|
||||
in memory; it never emits its credentials or gives it to a producer. No token
|
||||
passes through Git, a Hub record, command arguments or stdout/stderr.
|
||||
|
||||
## Blocking receiver finding
|
||||
|
||||
On 2026-09-11 the native receiver is 1/1 Ready on
|
||||
`forgejo.coulomb.social/coulomb/audit-core@sha256:c2fe39a0185b99be3fc0cb14d2de69772b8e66e20490097c9d11d90cc39719a6`.
|
||||
Its `SenderIdentity` has **no evidence_kind support**. A synthetic registration
|
||||
probe in the native pod fails the load-bearing contract; the same probe against
|
||||
current Audit Core source passes. Readiness did not detect this contract gap.
|
||||
|
||||
`factory_audit_custody.py receiver-check` now enforces that contract before any
|
||||
credential access. An approved CCR alone cannot bypass it. Audit Core must
|
||||
build, publish, admit and roll out its current implementation and source scope
|
||||
first. Its existing AUDIT-WP-0009-T09/T11 tasks retain that work; no completed
|
||||
source task is reopened. No receiver restart or deployment was done here.
|
||||
|
||||
Approval Engine's namespace is also absent. Three of four ESO objects passed
|
||||
server dry-run in their intended namespaces; its ExternalSecret was refused
|
||||
because that namespace does not exist. This packet creates no namespace,
|
||||
workload or network permission. Its owner must supply that prerequisite.
|
||||
|
||||
## Executable sequence
|
||||
|
||||
Review the source and exact policies:
|
||||
|
||||
```sh
|
||||
python3 scripts/credential-change.py render CCR-2026-0021
|
||||
python3 scripts/credential-change.py render CCR-2026-0022
|
||||
python3 scripts/factory_audit_custody.py plan
|
||||
```
|
||||
|
||||
After a compatible receiver release, the credential-free check is:
|
||||
|
||||
```sh
|
||||
python3 scripts/factory_audit_custody.py receiver-check \
|
||||
--kubeconfig /operator/railiance-kubeconfig \
|
||||
--expected-receiver-image forgejo.coulomb.social/coulomb/audit-core@sha256:ADMITTED_DIGEST \
|
||||
--receipt /operator/unique-receiver-receipt.json
|
||||
```
|
||||
|
||||
The seed command requires approved CCR files with all named owner reviews,
|
||||
the expected image, exact Railiance cluster UID, ready/current pod, both target
|
||||
namespaces and the Warden attended platform-admin login envelope. Route via
|
||||
`warden route show openbao-platform-admin-login --json` before arranging access.
|
||||
Use its installed attended wrapper; do not copy a token into the command.
|
||||
|
||||
Inside that envelope, invoke:
|
||||
|
||||
```sh
|
||||
python3 scripts/factory_audit_custody.py seed \
|
||||
--kubeconfig /operator/railiance-kubeconfig \
|
||||
--expected-receiver-image forgejo.coulomb.social/coulomb/audit-core@sha256:ADMITTED_DIGEST \
|
||||
--confirm 'PROVISION CCR-2026-0021 CCR-2026-0022' \
|
||||
--receipt /operator/unique-custody-receipt.json
|
||||
```
|
||||
|
||||
A successful seed deliberately reports
|
||||
`custody_seeded_pending_delivery_and_receiver_reload`. It applies the exact
|
||||
reader metadata and seeds custody, but does not apply ESO objects, reload the
|
||||
shared receiver or claim live ingestion. Preserve that receipt. After an
|
||||
interruption, review it and use `--resume` with a new receipt: only exact
|
||||
request-owned version-1 custody is reused. Changed tokens, source scopes,
|
||||
provenance, unknown duplicate identities and concurrent registry writes refuse.
|
||||
No automatic deletion or rotation is attempted on failure.
|
||||
|
||||
Under the same reviewed lane, the subsequent attended delivery uses
|
||||
`manifests/factory-audit-senders.yaml`; verify both stores/ExternalSecrets and
|
||||
exact token equality inside the protected process. Sync the existing registry
|
||||
ExternalSecret, verify its update, and reload Audit Core through its owner
|
||||
runbook. Then run each real producer's accepted/duplicate and wrong-source,
|
||||
wrong-tenant/read-refusal checks and retrieve evidence with the independent
|
||||
operator reader. The script does not yet automate these owner acceptance steps.
|
||||
Do not mark either CCR verified/active until those receipts exist.
|
||||
|
||||
## Revocation and limits
|
||||
|
||||
ESO login expiry does **not** expire an audit bearer. Stop the affected producer,
|
||||
remove only its token from the receiver registry using CAS, reload the receiver
|
||||
and prove refusal, then disable its reader/projection. Retain stored events and
|
||||
KV provenance. Rotation is separately reviewed and overlap-first. Existing
|
||||
senders and reader permissions remain intact.
|
||||
|
||||
`warden route show audit-core-senders` still points to the older Mason bootstrap.
|
||||
The receiver runbook records the later OpenBao migration; this packet uses that
|
||||
current authority and the platform's existing attended custody mechanics. It
|
||||
creates no second registry or generic credential broker.
|
||||
|
||||
Factory policy/caller admission, registered human binding, CCR-2026-0019's
|
||||
operator group, native runtime delivery and spending/operating acceptance stay
|
||||
with their existing records. Sender approval does not admit any of those acts.
|
||||
81
docs/evidence/2026-09-11-factory-audit-custody.json
Normal file
81
docs/evidence/2026-09-11-factory-audit-custody.json
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
{
|
||||
"schema": "platform.factory-audit-custody-preparation.v1",
|
||||
"observed_at": "2026-09-11T00:00:15.014528+00:00",
|
||||
"platform_base_commit": "d3a502b45cebc0a658d0ee7499f1cfcf2a5902a4",
|
||||
"owner_task": "RPF-WP-0035-T08",
|
||||
"source_records": [
|
||||
"CCR-2026-0021",
|
||||
"CCR-2026-0022",
|
||||
"AUDIT-WP-0009-T09",
|
||||
"AUDIT-WP-0009-T11"
|
||||
],
|
||||
"status": "proposed_custody_with_receiver_release_prerequisite",
|
||||
"verification": {
|
||||
"new_tests_passed": 17,
|
||||
"existing_credential_change_tests_passed": 53,
|
||||
"tests_skipped": 0,
|
||||
"local_openbao_test_cases": 11,
|
||||
"actual_receiver_source_contract_passed": true,
|
||||
"all_22_ccrs_valid": true,
|
||||
"server_dry_run": {
|
||||
"objects": 4,
|
||||
"exact_namespace_passed": 3,
|
||||
"refusal": "approval-engine namespace absent",
|
||||
"cluster_changes_applied": 0
|
||||
}
|
||||
},
|
||||
"native_receiver": {
|
||||
"image": "forgejo.coulomb.social/coulomb/audit-core@sha256:c2fe39a0185b99be3fc0cb14d2de69772b8e66e20490097c9d11d90cc39719a6",
|
||||
"ready_replicas": 1,
|
||||
"replicas": 1,
|
||||
"evidence_kind_supported": false,
|
||||
"probe": "synthetic SenderRegistry contract in exact deployed pod; no environment registry read",
|
||||
"entry_refusal": "receiver_lacks_sender_contract",
|
||||
"credential_reads": 0,
|
||||
"source_contract_commit": "5c0ad522fb36092aa7ec2e8d72f63a5a91853b5b"
|
||||
},
|
||||
"recovery_proven": [
|
||||
"interruption after first token write reuses the same value",
|
||||
"lost registry write reply reconciles without another write",
|
||||
"concurrent registry change is preserved by CAS refusal then deliberate resume",
|
||||
"wrong provenance/scope/duplicate names/token collisions refuse",
|
||||
"each exact read policy denies sibling data, full registry and metadata",
|
||||
"all named approvals and exact credential coordinates are enforced"
|
||||
],
|
||||
"routing_finding": {
|
||||
"catalog": "audit-core-senders",
|
||||
"status": "draft",
|
||||
"catalog_points_to": "ops-mason bootstrap",
|
||||
"current_authority": "platform/workloads/audit-core/senders per audit-core operator runbook",
|
||||
"execution_owner": "railiance-platform attended custody; existing platform helper pattern"
|
||||
},
|
||||
"pending_decisions": [
|
||||
{
|
||||
"ccr": "CCR-2026-0021",
|
||||
"status": 201,
|
||||
"decision_id": "2c9fe9f0-034a-41d7-9d49-b99df488fdc8"
|
||||
},
|
||||
{
|
||||
"ccr": "CCR-2026-0022",
|
||||
"status": 201,
|
||||
"decision_id": "ee4ff001-256a-4406-9cb8-51be2cd5d31b"
|
||||
}
|
||||
],
|
||||
"source_sha256": {
|
||||
"scripts/factory_audit_custody.py": "77b5bd7bd1b27a642d87d73d799b8896ebca1808b7c95fc47dd603ba74d8d30e",
|
||||
"tests/test_factory_audit_custody.py": "aef55cb98862dd62e2202fe4d2348aa8915f23d059331fd07d5644598452dc9f",
|
||||
"manifests/factory-audit-senders.yaml": "3d682dfd517b516dcb20c40373aae2557e4d8d2b49b3392d75c2cb36cd80785d",
|
||||
"openbao/policies/agent-high-risk-boundary.hcl": "9d863886c815740e65458417949c73a616b6e038594979b343ea07d08c585f64",
|
||||
"openbao/policies/workload-kv-read-approval-engine-audit.hcl": "a527c3bdfe7bf356fcd19f499ebc3ad75a71256a22c19882ad0dfdd09e0f0eb9",
|
||||
"openbao/policies/workload-kv-read-informed-decision-audit.hcl": "389e952546d32692e87b4f249752a9bee0fafa9fc58bf50ab8904110bf6b3780",
|
||||
"credential-change-requests/CCR-2026-0021-approval-engine-audit.yaml": "33f3bb5d32f2dbada864e1b89cdb47fcb9742dfe313eb391ca2f342be6bc119a",
|
||||
"credential-change-requests/CCR-2026-0022-informed-decision-audit.yaml": "7656519a7be847e6cf1b4e3e03200c68f5a36d87db8c81b84a16511b5dfe5d3a",
|
||||
"docs/credential-lane-designs/factory-audit-senders-review.md": "70e7a3568821672c84e0ce0388f7b8bc7d1b920354b38153995ec45022c53e52"
|
||||
},
|
||||
"native_credentials_created": 0,
|
||||
"native_secret_reads": 0,
|
||||
"native_policy_writes": 0,
|
||||
"native_deployments": 0,
|
||||
"factory_attempts": 0,
|
||||
"paid_model_calls": 0
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue