2.4 KiB
KCA OCSP responder
Standalone Rust/Axum responder. It reads one full JSON status snapshot per CA from S3-compatible object storage, caches it for one second with a single-flight refresh, and signs OCSP responses with a delegated responder certificate.
It has no KCA database access, no Redis access, and no KCA master key. It only needs:
s3:GetObjecton the configured bucket/prefix;- the CA certificate for each issuer;
- a delegated OCSP signer certificate and private key for each CA. The responder currently accepts RSA-SHA256 and ECDSA P-256 signers in PKCS#8, PKCS#1 RSA, or SEC1 EC PEM form.
Snapshot layout
KCA publishes objects as:
<prefix>/<CA certificate SHA-256>.json
KCA publishes these objects when KCA_OCSP_S3_BUCKET is configured. The JSON
contains all certificates issued by that CA, both valid and revoked. The
responder never infers status from a partial revoked-only list.
Run locally
- Create a config based on
responder.example.yaml. - Put your CA certificates and delegated signer files where the config points.
- Export standard AWS credentials / endpoint variables as needed.
- Make the signer key readable by the container user (
ocsp, uid/gid100:101in the provided image), or mount it via a Docker secret. - Run:
OCSP_CONFIG=./responder.yaml cargo run
The default listen address is 0.0.0.0:2560.
Verify with OpenSSL
For a CA certificate ca.crt and leaf certificate leaf.crt:
openssl ocsp \
-issuer ca.crt \
-cert leaf.crt \
-url http://127.0.0.1:2560/ocsp \
-resp_text \
-noverify
-noverify skips local trust setup; the response still shows the signature
algorithm and included responder certificate. For production verification,
build a trust store containing the CA or validate with your normal PKI tooling.
Endpoints
POST /ocsp—application/ocsp-requestGET /ocsp/<base64url-request>— optional GET formGET /healthzGET /readyz
Cache and availability
- Per-CA cache TTL:
s3.cache_ttl_ms(default 1000 ms). - Concurrent requests for the same CA share one S3
GetObject. - If S3 fails, a previously cached snapshot is served for
s3.stale_grace_seconds; otherwise the OCSP response istryLater. - 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.