Capabilities¶
What each platform can do today and what is designed. The architecture explains the parts; decisions 0058 to 0066 set the direction.
| mark | means |
|---|---|
| 📄 designed | described in a decision or reference page; no code |
| 🧪 built | the code exists and is tested; not yet run live |
| ✅ supported | built, tested in CI and run in an installation |
| n/a | does not apply to that platform |
The ingest path, notary and cursor observe write and read the v1 layout (🧪). The rest of the target architecture is 📄. Only the previous release's CLI (v0.6.x) reads the v0 archive.
Ingest¶
| feature | Kubernetes | AWS | self-hosted |
|---|---|---|---|
http sink (Connect to the receiver) |
✅ | 📄 | 📄 |
nats sink and consumer (JetStream) |
✅ | n/a | 📄 |
sqs sink and consumer, selectable as forward.sqs and consume.sqs (untested live) |
n/a | 🧪 | n/a |
lambda sink (direct invocation of the writer) |
n/a | 📄 | n/a |
the writer as an AWS Lambda behind an SQS event source mapping, with partial batch responses (audit-writer-lambda, AWS) |
n/a | 🧪 | n/a |
s3 sink (in process: the writer puts the object) |
✅ | ✅ | ✅ |
log sink |
🧪 | 🧪 | 🧪 |
| acknowledgement carries Archived, Queued or Logged | 🧪 | 🧪 | 🧪 |
require: start-up guard, read from configuration (require, forward, consume, sink.expect) |
✅ | 🧪 | 🧪 |
sink conformance suite (sdk/sink/sinktest) |
🧪 | 🧪 | 🧪 |
| a full spool fails the write | 📄 | 📄 | 📄 |
| deduplication on Postgres or in memory | ✅ | 📄 | 📄 |
| deduplication on JetStream (duplicate window, KV with TTL) | 📄 | n/a | n/a |
deduplication on DynamoDB (conditional put with TTL, dedupe/dynamodbdedupe; LocalStack in CI) |
n/a | 🧪 | n/a |
| one configuration file against a schema, version 2 (version 1 read for one minor) | ✅ | 🧪 | 📄 |
secrets named by ...Secret and found through secrets.source (env, file, ssm); env refused on Lambda; SSM read with the function's own role |
✅ | 🧪 | 📄 |
/readyz beside /healthz on the writer, query service and indexer; the chart's readiness probes read it |
✅ | n/a | 📄 |
event=unknown_catalogue and audit_writer_catalogue_unknown_total for a record naming a catalogue version the writer lacks, and the <name>-writer-unknown-catalogue alarm |
🧪 | 🧪 | 🧪 |
the ingest queue's sender model: Ingest.Senders (required) and Redrivers, a deny to every other principal |
n/a | 🧪 | n/a |
a record from a queue is stamped from what SQS sets: recorded_at from SentTimestamp, the observer from SenderId through senders |
n/a | 🧪 | n/a |
SinkService.Write holds a caller to the source its workload is listed for (workloads) |
🧪 | n/a | 🧪 |
| metrics over OTLP: acknowledgements by durability, write latency per transport, index lag, consumer failures | 🧪 | 🧪 | 🧪 |
queue metrics: the age of each message at receive (audit.queue.message.age, from SentTimestamp), and CloudWatch alarms on the DLQ and the oldest message |
n/a | 🧪 | n/a |
chart value telemetry.otlp (endpoint, protocol, extraEnv): the OpenTelemetry environment on every pod |
🧪 | n/a | n/a |
telemetry from a Lambda with the function role's identity and no secret (the OTLP extension layer audit-otlp, which sluis publishes, AWS) |
n/a | 🧪 | n/a |
traces over OTLP: server and client spans, traceparent across NATS headers and SQS attributes, no personal data on a span |
🧪 | 🧪 | 🧪 |
chart renders: alerts: nine alert rules as a VMRule or PrometheusRule, unit-tested on vmalert-tool |
🧪 | 🧪 | 🧪 |
chart renders: dashboards: the audit overview for Grafana's sidecar, held to the observability dashboard lint |
🧪 | 🧪 | 🧪 |
The s3 sink works against any S3-compatible store. Without Object Lock it is the unlocked store tier 0056 calls attested, not the install preset of that name.
The archive¶
| feature | Kubernetes | AWS | self-hosted |
|---|---|---|---|
| v1 layout, written and read (bucket contract): one object per ingest batch, keyed by ingest time | 🧪 | 🧪 | 🧪 |
catalogue/<app>/<version>, written once, compared when present |
🧪 | 🧪 | 🧪 |
audit verify: key, metadata, sha256 and per-record hashes of every object |
🧪 | 🧪 | 🧪 |
audit verify --root: the seals of a range, against pinned roots (below) |
🧪 | 🧪 | 🧪 |
| Object Lock, compliance mode | ✅ | ✅ | n/a |
governance trial, then compliance (0065); the Pulumi library takes NONE, GOVERNANCE or COMPLIANCE |
📄 | 🧪 | n/a |
| lifecycle to Glacier Instant Retrieval and Deep Archive (a rule per profile prefix in the Pulumi library) | n/a | 🧪 | n/a |
| bucket-contract conformance suite (records, catalogue and ordering, against the memory store and S3) | 🧪 | 🧪 | 🧪 |
| conformance of seals, delegation and revocation: against the memory store and S3, with a key file and a KMS P-384 key (LocalStack) | 🧪 | 🧪 | 🧪 |
Notary¶
Seals (0061) come from audit-notary, a binary and image of its own.
| feature | Kubernetes | AWS | self-hosted |
|---|---|---|---|
seals, chained through prev, one per profile, tenant and hour, empty hours too; settle window; idempotent; refuses to seal what does not match its metadata |
🧪 | 🧪 | 🧪 |
Merkle root over per-record hashes (RFC 6962), inclusion proofs and the vectors for n = 0, 1, 2, 3 and 5 (internal/merkle) |
🧪 | 🧪 | 🧪 |
keys/roots.jwks, written once; thumbprints pinned by the verifier |
🧪 | 🧪 | 🧪 |
chart: jobs.notary, an hourly CronJob under an identity of its own, refused if it is the writer's |
🧪 | n/a | n/a |
seal age: audit.seal.age, the AuditSealStale alert and a dashboard panel |
🧪 | 🧪 | 🧪 |
| verifying a delegation (window, scope, 25 hours) and a revocation | 🧪 | 🧪 | 🧪 |
| signing a delegation: a notary on a short-lived delegated key (decision L3: daily) | 📄 | 📄 | 📄 |
signer: AWS KMS ECC_NIST_P384 |
🧪 | 🧪 | n/a |
signer: OpenBAO transit ecdsa-p384 |
🧪 | n/a | 🧪 |
| signer: P-384 key file | 🧪 | 🧪 | 🧪 |
| signer: PKCS#11 | n/a | n/a | 📄 |
| signer: TPM | n/a | n/a | 📄 |
notary as a function on an EventBridge Scheduler schedule (audit-notary-lambda) |
n/a | 🧪 | n/a |
audit verify of seals: signature, chain, count and root against the objects, missing seals |
🧪 | 🧪 | 🧪 |
Seals are tested against the in-memory store and LocalStack S3, signed by a key file and a KMS key. No installation has run them, so none is ✅. The ed25519 and P-256 signers still sign and verify in keys, and sign no seal.
Observe¶
| feature | Kubernetes | AWS | self-hosted |
|---|---|---|---|
| index and search on Postgres | ✅ | 📄 | 📄 |
cursor observe: audit-observe lists the bucket from a durable cursor per profile and tenant, behind a settle window (0062) |
🧪 | 🧪 | 🧪 |
| notifications as a wake-up (a NATS subject or an SQS queue that only shortens the poll) | 🧪 | 🧪 | 🧪 |
| one database role per part: the writer's has no index, observe's writes it, the query service's reads it (0066) | 🧪 | 🧪 | 🧪 |
| reindex from the archive (v1), and a cursor reset | 🧪 | 🧪 | 🧪 |
| usage quotas | 📄 | 📄 | 📄 |
| billing statements | 📄 | 📄 | 📄 |
Packaging¶
| feature | Kubernetes | AWS | self-hosted |
|---|---|---|---|
audit toolchain archives and container images |
✅ | ✅ | ✅ |
| Helm chart | ✅ | n/a | n/a |
| Helm chart modes per part | 📄 | n/a | n/a |
Pulumi library (bucket with Object Lock, lifecycle and a break-glass-only lock policy, seal and digest key policies, queue and DLQ, functions, roles, schedule, alarms, a cross-account read role; audit/deploy/pulumi, mocks only) |
n/a | 🧪 | n/a |
| CloudWatch alarm set: throttles, DLQ not empty, oldest message age, errors, unknown catalogue version, notary silence, to SNS and alert-ingress | n/a | 🧪 | n/a |
| rpm and deb packages | n/a | n/a | 📄 |