Operate scheduled chain-head attestation (AUDIT-WP-0009-T12)
Apply the separate attestor identity, named-ConfigMap RBAC, attest egress and daily CronJob. Bootstrap an empty chain-head ConfigMap only because it was absent; drop the placeholder from the apply path so a later apply cannot overwrite a live head. One-shot job published a 59-event attestation; mounted readback and receiver write-denial passed. Offsite copy stays the operator path. Assistant: grok Assistant-Session: 01a0a182-bab7-7f11-b32b-d06f3af52082
This commit is contained in:
parent
805bacbc14
commit
4c940d49ae
5 changed files with 58 additions and 25 deletions
|
|
@ -105,7 +105,7 @@ spec:
|
||||||
type: RuntimeDefault
|
type: RuntimeDefault
|
||||||
containers:
|
containers:
|
||||||
- name: attest
|
- name: attest
|
||||||
image: forgejo.coulomb.social/coulomb/audit-core@sha256:c82e0442de0fd181342916ae9cd5d6de41d859e1efda637bd93936c67873afa5
|
image: forgejo.coulomb.social/coulomb/audit-core@sha256:ec15f63d49226bfe507af2bc38ffbd5e83f549ba2c6d1ae7a338e7e053f34615
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
command:
|
command:
|
||||||
- python
|
- python
|
||||||
|
|
@ -126,7 +126,9 @@ spec:
|
||||||
- name: AUDIT_CORE_AUTO_MIGRATE
|
- name: AUDIT_CORE_AUTO_MIGRATE
|
||||||
value: "0"
|
value: "0"
|
||||||
resources:
|
resources:
|
||||||
requests: {cpu: 50m, memory: 64Mi}
|
# 10m so a one-shot proof job can schedule on a node packed
|
||||||
|
# to 99% CPU requests; 50m would Pending (Insufficient cpu).
|
||||||
|
requests: {cpu: 10m, memory: 64Mi}
|
||||||
limits: {cpu: 500m, memory: 256Mi}
|
limits: {cpu: 500m, memory: 256Mi}
|
||||||
securityContext:
|
securityContext:
|
||||||
allowPrivilegeEscalation: false
|
allowPrivilegeEscalation: false
|
||||||
|
|
@ -146,18 +148,9 @@ spec:
|
||||||
secret:
|
secret:
|
||||||
secretName: audit-core-database
|
secretName: audit-core-database
|
||||||
defaultMode: 0440
|
defaultMode: 0440
|
||||||
---
|
# ConfigMap audit-core-chain-head is NOT in this file. Applying a placeholder
|
||||||
# Created empty by the operator so the CronJob's Role needs no `create`, and
|
# `{}` would overwrite a live attestation. Bootstrap once if absent:
|
||||||
# so the Deployment can mount it before the first run. An absent or undated
|
# kubectl -n audit-core create configmap audit-core-chain-head \
|
||||||
# attestation degrades the claim rather than breaking the receiver — that is
|
# --from-literal=chain-head.json='{}'
|
||||||
# T01's `no_attestation` path, and it is the correct behaviour on day one.
|
# kubectl -n audit-core label configmap audit-core-chain-head \
|
||||||
apiVersion: v1
|
# app.kubernetes.io/name=audit-core app.kubernetes.io/component=attest
|
||||||
kind: ConfigMap
|
|
||||||
metadata:
|
|
||||||
name: audit-core-chain-head
|
|
||||||
namespace: audit-core
|
|
||||||
labels:
|
|
||||||
app.kubernetes.io/name: audit-core
|
|
||||||
app.kubernetes.io/component: attest
|
|
||||||
data:
|
|
||||||
chain-head.json: "{}"
|
|
||||||
|
|
|
||||||
|
|
@ -199,10 +199,10 @@ spec:
|
||||||
ports:
|
ports:
|
||||||
- {protocol: UDP, port: 53}
|
- {protocol: UDP, port: 53}
|
||||||
- {protocol: TCP, port: 53}
|
- {protocol: TCP, port: 53}
|
||||||
# kube-apiserver. On this single-node k3s cluster the API server is the
|
# kube-apiserver. In-cluster clients use kubernetes.default.svc:443;
|
||||||
# host itself, so this is a host-network destination rather than a pod
|
# the host listener is 6443. Both, and no other ports.
|
||||||
# selector; narrow it to the API port.
|
|
||||||
- ports:
|
- ports:
|
||||||
|
- {protocol: TCP, port: 443}
|
||||||
- {protocol: TCP, port: 6443}
|
- {protocol: TCP, port: 6443}
|
||||||
---
|
---
|
||||||
apiVersion: networking.k8s.io/v1
|
apiVersion: networking.k8s.io/v1
|
||||||
|
|
|
||||||
23
docs/evidence/2026-09-15-t12-attest-run.json
Normal file
23
docs/evidence/2026-09-15-t12-attest-run.json
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"task": "AUDIT-WP-0009-T12",
|
||||||
|
"observed_at": "2026-09-15T19:15:40+00:00",
|
||||||
|
"job": "audit-core-attest-t12",
|
||||||
|
"job_succeeded": true,
|
||||||
|
"image": "forgejo.coulomb.social/coulomb/audit-core@sha256:ec15f63d49226bfe507af2bc38ffbd5e83f549ba2c6d1ae7a338e7e053f34615",
|
||||||
|
"published": true,
|
||||||
|
"schema": "audit-core.chain-head.v1",
|
||||||
|
"event_count": 59,
|
||||||
|
"head_prefix": "bb0937f02a772d1c",
|
||||||
|
"mounted_readback": true,
|
||||||
|
"receiver_patch": "URLError",
|
||||||
|
"rbac": {
|
||||||
|
"default_sa_can_patch_chain_head": false,
|
||||||
|
"attest_sa_can_patch_chain_head": true,
|
||||||
|
"attest_sa_can_create_configmaps": false
|
||||||
|
},
|
||||||
|
"cronjob": "audit-core-attest-chain",
|
||||||
|
"schedule": "17 3 * * *",
|
||||||
|
"offsite_copy": "not_written_here",
|
||||||
|
"readyz_tamper_evidence": false,
|
||||||
|
"readyz_note": "live image reports last-known claim on /readyz; the mounted file is the live attestation. Offsite copy remains RESOURCE-WP-0002-T06."
|
||||||
|
}
|
||||||
|
|
@ -97,3 +97,6 @@ def test_the_receiver_has_no_api_server_egress():
|
||||||
attest = next(d for d in documents if "name: audit-core-attest-egress" in d)
|
attest = next(d for d in documents if "name: audit-core-attest-egress" in d)
|
||||||
assert "component: attest" in attest
|
assert "component: attest" in attest
|
||||||
assert "6443" in attest
|
assert "6443" in attest
|
||||||
|
assert "443" in attest
|
||||||
|
assert "6443" not in receiver
|
||||||
|
assert "443" not in receiver
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ flavor: implementation
|
||||||
owner: claude
|
owner: claude
|
||||||
topic_slug: railiance
|
topic_slug: railiance
|
||||||
created: "2026-08-29"
|
created: "2026-08-29"
|
||||||
updated: "2026-09-14"
|
updated: "2026-09-15"
|
||||||
depends_on:
|
depends_on:
|
||||||
- AUDIT-WP-0007
|
- AUDIT-WP-0007
|
||||||
state_hub_workstream_id: "46a96b03-bc08-53b5-9c93-4071adabf734"
|
state_hub_workstream_id: "46a96b03-bc08-53b5-9c93-4071adabf734"
|
||||||
|
|
@ -608,14 +608,28 @@ runtime/spend gates remain separate. Factory attempts and paid calls remain 0.
|
||||||
|
|
||||||
```task
|
```task
|
||||||
id: AUDIT-WP-0009-T12
|
id: AUDIT-WP-0009-T12
|
||||||
status: todo
|
status: done
|
||||||
priority: high
|
priority: high
|
||||||
state_hub_task_id: "712ba035-edad-5528-8293-56375553d85a"
|
state_hub_task_id: "712ba035-edad-5528-8293-56375553d85a"
|
||||||
```
|
```
|
||||||
|
|
||||||
Residual from the source-complete T02: the 2026-09-11 receiver rollout found
|
Done 2026-09-15. Native attestor is live: ServiceAccount/Role/RoleBinding
|
||||||
no native attest CronJob or audit-core-chain-head ConfigMap. The new receiver
|
`audit-core-attest` (named ConfigMap get/update/patch only, no create),
|
||||||
correctly reports tamper_evidence=false while its 32-event chain is intact.
|
CronJob `audit-core-attest-chain` at 17:03 UTC, NetworkPolicy
|
||||||
|
`audit-core-attest-egress` (Postgres, DNS, API 443/6443). Empty ConfigMap
|
||||||
|
`audit-core-chain-head` was bootstrapped because it was absent; the
|
||||||
|
placeholder is no longer in the apply path so a later apply cannot clobber
|
||||||
|
a live head. One-shot Job `audit-core-attest-t12` published
|
||||||
|
`audit-core.chain-head.v1` for 59 events at 2026-09-15T19:15:40Z. Receiver
|
||||||
|
mount caught up; default SA cannot patch; attest SA cannot create ConfigMaps;
|
||||||
|
receiver API PATCH is a URLError (no API egress). CPU request is 10m so the
|
||||||
|
job schedules on the packed node.
|
||||||
|
|
||||||
|
Offsite copy is still RESOURCE-WP-0002-T06 / operator — this job does not
|
||||||
|
write Nextcloud. In-cluster attestation is a database-owner boundary only.
|
||||||
|
`/readyz` still reports last-known `tamper_evidence: false` on the live
|
||||||
|
image; the mounted file is the live claim. Receipt:
|
||||||
|
`docs/evidence/2026-09-15-t12-attest-run.json`.
|
||||||
Apply the reviewed separate attestor identity, exact-ConfigMap RBAC, component
|
Apply the reviewed separate attestor identity, exact-ConfigMap RBAC, component
|
||||||
egress and scheduled job; bootstrap an empty ConfigMap only if absent, never
|
egress and scheduled job; bootstrap an empty ConfigMap only if absent, never
|
||||||
overwrite a live attestation with the manifest placeholder. Prove one successful
|
overwrite a live attestation with the manifest placeholder. Prove one successful
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue