Use S3 object expiry for OCSP snapshots
This commit is contained in:
+29
-18
@@ -26,10 +26,11 @@ This isolates snapshots when the same public CA certificate exists in multiple
|
||||
vaults. The responder validates both this ID and the CA certificate fingerprint
|
||||
against every downloaded snapshot.
|
||||
|
||||
KCA publishes these objects when `KCA_OCSP_S3_BUCKET` is configured. The JSON
|
||||
contains all certificates issued by that CA, both valid and revoked, and a
|
||||
required `generated_at` timestamp. The responder never infers status from a
|
||||
partial revoked-only list.
|
||||
KCA publishes these objects when `KCA_OCSP_S3_BUCKET` is configured. The
|
||||
`kca-ocsp-status/v2` JSON contains all certificates issued by that CA, both
|
||||
valid and revoked, without a generation timestamp. Freshness is carried by the
|
||||
S3 `Expires` header instead. The responder never infers status from a partial
|
||||
revoked-only list.
|
||||
|
||||
## Upgrading from fingerprint-named snapshots
|
||||
|
||||
@@ -39,6 +40,13 @@ KCA publisher. The responder deliberately does not fall back to legacy
|
||||
objects, OCSP requests return `tryLater`. After verifying the new snapshots,
|
||||
the obsolete fingerprint-named objects can be removed.
|
||||
|
||||
## Upgrading from timestamped snapshots
|
||||
|
||||
Version 2 snapshots remove `generated_at` and require an S3 `Expires` header.
|
||||
Upgrade the publisher and responder together: old objects have no `Expires` and
|
||||
are rejected, while old responders cannot parse the version 2 JSON. Until the
|
||||
new publisher writes a snapshot, the new responder returns `tryLater`.
|
||||
|
||||
## Run locally
|
||||
|
||||
1. Create a config based on `responder.example.yaml`, setting each issuer's
|
||||
@@ -97,20 +105,23 @@ build a trust store containing the CA or validate with your normal PKI tooling.
|
||||
## Cache and availability
|
||||
|
||||
- Per-CA cache TTL: `s3.cache_ttl_ms` (default 1000 ms).
|
||||
- Concurrent requests for the same CA share one S3 `GetObject`.
|
||||
- `s3.stale_grace_seconds` is also the hard maximum snapshot age, measured from
|
||||
`generated_at`. Expired or future-dated snapshots are rejected even when S3
|
||||
remains readable; if no valid cached snapshot remains, OCSP returns
|
||||
`tryLater`.
|
||||
- If a refresh fails, a cached snapshot is served only while both its time since
|
||||
the last successful fetch and its `generated_at` age remain within
|
||||
`s3.stale_grace_seconds`.
|
||||
- Concurrent requests for the same CA share one refresh. Each refresh performs
|
||||
`HeadObject` to obtain `Expires` and the ETag, then `GetObject` with
|
||||
`If-Match` for that ETag. This supports RustFS, which does not return the
|
||||
stored `Expires` value from its local `GetObject` path, and prevents mixing
|
||||
metadata and bodies from different object versions. Concurrent overwrites
|
||||
cause a bounded retry of the complete HEAD/GET sequence.
|
||||
- `Expires` is the hard snapshot expiry. Missing, malformed and expired values
|
||||
are rejected; if no unexpired cached snapshot remains, OCSP returns
|
||||
`tryLater`. The header controls responder freshness only—S3 does not delete
|
||||
the object at that time.
|
||||
- If a refresh fails, a cached snapshot is served only until its own `Expires`
|
||||
timestamp, regardless of how recently it was fetched.
|
||||
- KCA republishes unchanged snapshots every
|
||||
`KCA_OCSP_HEARTBEAT_INTERVAL_SECONDS` (default 30 seconds). Keep that interval
|
||||
comfortably below the responder's `s3.stale_grace_seconds` (default 60). For
|
||||
a rolling upgrade, enable publisher heartbeats before the freshness-enforcing
|
||||
responder so existing snapshots remain within the age limit.
|
||||
- OCSP `thisUpdate` is the snapshot's `generated_at`. `nextUpdate` is capped at
|
||||
the snapshot's hard expiry, while `producedAt` is the response signing time.
|
||||
`KCA_OCSP_HEARTBEAT_INTERVAL_SECONDS` (default 30 seconds) and sets `Expires`
|
||||
using `KCA_OCSP_OBJECT_EXPIRY_SECONDS` (default 60 seconds). Keep the
|
||||
heartbeat comfortably below the object expiry.
|
||||
- OCSP `thisUpdate` and `producedAt` use the response time. `nextUpdate` is
|
||||
capped at the snapshot's hard expiry.
|
||||
- With multiple CAs, the TTL is per CA. If you need a global one-request-per-
|
||||
second limit across all CAs, that requires a shared rate limiter.
|
||||
|
||||
Reference in New Issue
Block a user