audit-core/tenancy.yaml

134 lines
7.2 KiB
YAML
Raw Normal View History

# audit-core tenancy posture
#
# Declared per NetKingdom Tenancy Posture v0.1 (draft-7),
# net-kingdom/canon/standards/tenancy-posture_v0.1.md.
# Location and schema per Decision 5.4; per-path detail per Decision 5.2;
# provider block per Decision 5.5.
#
# Conformance is accuracy, not altitude (§6). Nothing here is claimed above
# what this repo can evidence today, and two rungs are deliberately declared
# lower than the mechanism in place — see `gap.E` and `gap.R`.
tenancy:
reviewed: "2026-08-17"
service_class: batch # §8.3.2. Co-resident with latency-critical
# tenant-engine on platform-pg; the mixture is
# reported by the platform, not hidden.
current: { I: 1, A: 2, E: 1, P: 1, R: 1 }
target: { I: 1, A: 2, E: 3, P: 1, R: 2 }
# §5.2 — declare per path, quote the minimum. The quoted E above is the
# minimum across paths. As of AUDIT-WP-0008-T04 both paths carry the same
# mechanism; the quoted level stays at 1 for the evidence reason in gap.E,
# not because a path is weaker.
paths:
E:
write: 2 # Sender credential bound to the sources and tenants it may
# claim; checked at one choke point (audit_core/ingestion.py).
read: 2 # Event reads filtered to permitted tenants; surfaces with no
# tenant key require full scope. Cross-tenant fetch returns
# 404, not 403, so the surface is not an existence oracle.
placement_exceptions: [] # No tenant is on dedicated substrate. All
# tenants share database audit_core on
# platform-pg.
gap:
I: >-
I1 is accurate and is not currently a target. Senders authenticate with
bearer tokens and the tenant arrives in the request body, checked against
an allowlist bound to the credential (§4.1 places request-supplied tenant
identifiers at I1 however canonical the string). The allowlist is a real
control, but it is an A-axis control; it does not make the identity
verified. Moving to I2 means senders carrying a verified token with a
tenant claim, which is a change to every sender and not audit-core's to
make alone. Recorded as accurate, not as ambition.
A: >-
A2 is accurate. Authorization is a single local boundary — permitted
sources, permitted tenants, may_write, may_read — bound once and centrally.
No flex-auth delegation. A3 is not a near-term target: flex-auth is itself
at A0 on its own self-report (/v1/check authenticates no caller), so
delegating to it today would lower this service's assurance, not raise it.
E: >-
The E2 mechanism is in place on both paths as of AUDIT-WP-0008-T04, and
the quoted level is still 1. This is deliberate. §13.2 states that a
passing CI run is not E2 evidence: the E2 artifact is adversarial, needs
separate tenant contexts compared against each other, and carries a review
date rather than a green build. The repo's cross-tenant tests are
mechanical. Under §13.1 the level is not claimable until that artifact
exists, so E stays at 1 until AUDIT-WP-0008-T05 produces it with
whitehat-security. Declaring E2 on the strength of unit tests would be the
overclaim §6 prohibits, and the read-path defect this repo just fixed was
found precisely by refusing that kind of reasoning.
E_target: >-
E3 (row-level security per rapp-postgres ADR-0003) targeted 2027-03-31.
Blocked behind the E2 artifact — §4.3 requires E2 evidence alongside any
E3 claim — and needs the EXPLAIN comparison first, since RLS disables
functional indexes built on non-leakproof functions. E4 is unreachable at
P1 by the §3.2 coupling and is not a target.
R: >-
R1 today: the platform default 30-day window applies and audit-core has
declared nothing above it. R2 is requested and in flight — audit-core has
asked rapp-postgres to add `backupRetentionDays: 30` to
consumers/audit-core.yaml, making the window declared rather than
inherited. That file is rapp-postgres's, so R2 is not audit-core's to
declare unilaterally. The erasure horizon is published on /readyz as
recoverable_days.
R_ceiling: >-
R4 is unreachable under the current design and is not a target. Per
Decision 4.5.3 — which this repo found — the hash chain commits to a
SHA-256 of the cleartext record, which survives key destruction as a
confirmation oracle over low-entropy fields. A fleet R4 target must exempt
this service explicitly. See docs/erasure-and-audit.md (AUDIT-WP-0008-T03).
credentials: >-
Stated gap against Decision 9.2 rather than a silent exclusion. Database
credentials comply with 9.1: dynamic leases re-read from a mounted Secret
at connection time, no restart on rotation. Ingest credentials do not:
they are static long-lived bearer tokens, rotated overlap-first by
publishing a replacement alongside the incumbent and then dropping the
predecessor. audit-core raised this omission during review and is not
exempting itself from the rule it asked for. No dated remedy yet; leasing
consumer-facing credentials needs a broker path that does not exist.
retention_placement: >-
audit-core's INTENT wants unbounded WORM archive. That is data.archive in
ITC-CAP terms, recorded as an unmet requirement in
data/capability/audit-core-operational.json, and it is deliberately not a
backup-window question: a 30-day WAL window is not an archive, is not
searchable, and restores instance-wide. Reviewed 2026-12-31. If no
data.archive provision is procured by then, audit-core reopens placement
under the §4.5 retention trigger, with P2 as the fallback — a worse answer
than archive, named now so it is not improvised later.
# §5.5 — audit-core provisions operations.audit to senders, so it declares
# what it makes reachable for a consumer's audit trail, not only where it
# sits. A sender's tenant separation inside the trail is audit-core's to
# enforce; the sender cannot reach a level this service does not offer.
provides:
capability: operations.audit
profile: administrative
reachable:
E2: >-
Reachable now. A sender credential is bound to the tenants it may write
for and, if it may read, to the tenants it may read back.
E3: >-
Not reachable yet. Requires rapp-postgres's ADR-0003 GUC contract
applied to the audit_core schema. Targeted 2027-03-31.
E4: >-
Unreachable. One database, one runtime credential, no per-tenant
credential and no per-tenant substrate. A sender needing a structural
guarantee that another tenant cannot reach its audit records cannot get
it here, and should be told so rather than sold E2 in E4's language
(§11.4).
R2: >-
Reachable once the declared window lands; the horizon is already
published on /readyz.
R4: >-
Unreachable by design, per R_ceiling above. A consumer with a verified
erasure obligation over its audit trail cannot discharge it here.