Preview release.These docs are a work in progress. Pages are still being written, links may break, and structure may shift without notice. Treat everything here as a draft and report issues onGitHub.
Registry Relay and Registry Notary enforce authentication, authorization, key publication, and audit as software controls (see Security overview). RS-SEC-G Section 9 draws a line at the deployment: secret and key provisioning, key custody and rotation, audit retention and storage, tenant isolation, transport termination and certificate management, edge rate limiting, deployment configuration, and incident response stay with the operator. This page turns that boundary into a checklist you work through before you call a deployment production-ready.
When to use this
Section titled “When to use this”Use this checklist before a production or evidence_grade deployment goes live, and again after
any change to signing keys, audit sinks, network placement, or the declared deployment profile. It
assumes you have already configured your service per the Registry Relay configuration reference
or the Registry Notary operator configuration reference.
Before you start
Section titled “Before you start”- Decide the deployment profile (
local,hosted_lab,production, orevidence_grade) you are claiming; see the deployment profile section of the Registry Relay configuration reference. The profile is never inferred from hostname or network position; you declare it. - Have
registry-notary doctor(Notary) or your Relay startup logs available to check gate findings as you work through each item.
Keys and custody
Section titled “Keys and custody”- Configure signing keys through the provider abstraction (
local_jwk_env,file_watch, orpkcs11) underevidence.signing_keys, not as inline YAML values. Startup fails closed if an active signing provider cannot be constructed. See the signing key provider reference. - Provision secrets (API-key fingerprints, source tokens, private JWKs, the audit hash secret) only
through the environment variables named in config. For local development the binary accepts
--env-file; for shared environments use the platform secret store and do not check dotenv files into the repository. - Rotate a signing key by adding a new
kid, moving credential profiles to it, then moving the old key topublish_onlyuntil its configured publication window ends or verifiers no longer need it. Do not delete a key verifiers may still need. - Keep RS256 scoped to the eSignet relying-party (RP) client assertion key (eSignet, the MOSIP-project identity provider, is the one integration that needs RS256). Credential profile, access token, and federation response signing use Ed25519 EdDSA or ES256/P-256; RS256 is rejected there.
- If a signing key uses
provider: pkcs11, confirm the deployed binary was built with thepkcs11capability (registry-notary build-info) and validate the module, token, and key lookup withregistry-notary doctor --config <path>. - Relay: confirm every env-backed
fingerprint.namereferenced in config exists in the runtime environment, and that no raw key, fingerprint, private JWK, or full environment dump reaches a log line; see the production checklist in the Registry Relay configuration reference.
Audit sink and retention
Section titled “Audit sink and retention”- Configure a durable audit sink (
fileorsyslog, not barestdout) before you declareproductionorevidence_grade. A missing durable sink tripsrelay.audit.sink_missing/notary.audit.sink_missing, which fails startup atevidence_grade(startup_failfor both services, and alreadystartup_failatproductionfor Notary). - Set
audit.hash_secret_envto an environment variable holding at least 32 bytes of deployment-specific random secret material. Relay startup fails closed if it is missing, empty, unset, or weak. - Keep
audit.write_policy: fail_closed(the default) unless an explicit availability exception accepts best-effort audit durability underavailability_first.fail_closedmeans a request whose audit record cannot be written returns503 audit.write_failedinstead of a success (REQ-SEC-G-009). - If you rotate the audit hash secret, retain the old secret under your audit retention controls for any period during which older records must remain comparable to new ones, or accept that new records will not match old audit handles.
- Hash-chained envelopes (
prev_hash,record_hash) detect ordering gaps and accidental corruption inside the retained set, but they do not prove that every historical audit record remains present. Use off-host audit shipping when completeness matters. - For
evidence_grade, configuredeployment.evidence.audit_ack_cursor_pathfor every shipping target, includingstdoutandsyslog. The off-host shipper writesregistry.audit.ack_cursor.v1after a successful hand-off. Registry Relay and Registry Notary report ready only whileacked_atis fresh andlast_acked_hashequals the live keyed audit chain tail. A matching cursor means the trusted shipper claims zero local backlog. The local cursor does not prove remote receipt or retention. - Run the shipper independently of application readiness. A signed configuration bundle produces
a bundle-acceptance audit record before the service starts serving requests. The service reports
503until the shipper acknowledges that record, then reports ready while the cursor stays at the current tail. - Replace the cursor atomically, keep it at or below 16 KiB, and mount it read-only for the Registry process. Keep the cursor path on local storage. Runtime reads use one 500 ms bounded worker and fail readiness when the file is missing, stale, malformed, unsafe, mismatched, or too slow.
- Treat
registry-relay doctorandregistry-notary doctoras offline contract checks. They can validate the cursor timestamp and shape but cannot bind it to a live audit tail, so a fresh cursor remainsunverified. Anevidence_gradeoffline doctor run therefore reports the hard shipping gate until the live service performs tail binding.
Transport and edge
Section titled “Transport and edge”- For the 1.0 single-node VM topology, follow Run single-node Compose behind your reverse proxy before exposing Relay or Notary beyond the host.
- Terminate TLS and manage certificates at your reverse proxy or load balancer; RS-SEC-G Section 9 leaves transport termination and certificate management to the operator.
- Keep the admin listener private. A publicly exposed admin surface trips
relay.admin.public_exposureornotary.admin.shared_exposure, bothstartup_failatevidence_grade. - Set explicit
cors.allowed_origins. The default CORS policy is deny by omission; add only the origins your integration actually needs. - Enable
server.trust_proxywith an explicittrusted_proxieslist only when a reverse proxy sits in front of Relay. Bothenabledandtrusted_proxiesdefault to off/empty. - Enforce ingress rate limiting at your gateway or edge, then either declare
deployment.evidence.ingress_rate_limit: trueor accept therelay.ingress.rate_limit_missingfinding it otherwise raises. The flag defaults tofalse. - Leave
allow_insecure_localhostandallow_insecure_private_networkfalse on Notary source connections in production unless a deployment review explicitly accepts the private-network source; a plainhttp://source with neither allowance tripsnotary.source.insecure_url, and enabling the escape hatch tripsnotary.source.private_network_escape. - For Postgres sources, require
sslmode=requireon the connection string and use read-only database credentials; for live materialization, scope that role toSELECTonly the configured table or view. - Apply the Registry Platform HTTP-security response headers and outbound-HTTP-policy primitive on source-connector egress; both are RS-SEC-G recommendations (REQ-SEC-G-012), not an enforced default, so confirm your build turns them on.
Deployment profile and posture endpoint
Section titled “Deployment profile and posture endpoint”- Declare
deployment.profileexplicitly. An omitted profile binds no gates and only raises adeployment.profile_undeclaredwarning, so a silent gap stays silent until you declare a profile. - Treat
evidence_gradeas requiring a signed local config bundle: running it from a plain local YAML file tripsrelay.config.unsigned/notary.config.unsignedand the process refuses to start. - Review
GET /admin/v1/postureregularly. It reports the declared profile, active findings, and active waivers, so the deployment’s actual state is inspectable rather than asserted. - Give every waiver a non-empty, non-secret reason and a mandatory expiry date.
startup_failgates are never waivable; a waiver naming one is rejected. Waiver reasons appear only in the restricted posture tier. - Use
deployment.evidence.*flags (for exampleingress_rate_limit,api_key_rotation) only to assert controls that live outside the process and cannot be observed by it. Each flag defaults tofalse. - If a Notary instance runs active-active with peers, declare
multi_instanceand use Redis-backed replay storage. In-memory replay under a multi-instance or federated declaration tripsnotary.replay.in_memory_high_risk.
Incident response
Section titled “Incident response”- Know your private disclosure channel before you need it: see Report a vulnerability.
- If credential-status is enabled, use the admin status endpoint (requires the
registry_notary:adminscope) to mark a compromised credentialrevoked. Registry Notary defines no other revocation flow; a credential issued with credential-status disabled cannot be revoked through the API. See Known limitations and non-guarantees. - Rotate a compromised signing key using the documented rotation procedure (new
kid, old key topublish_only) rather than deleting it outright, so previously issued, still-valid credentials remain verifiable through the rotation. - Preserve the audit trail for post-incident review: hash-chained, fail-closed audit records are the record a deployment reconstructs a request timeline from (REQ-SEC-G-008, REQ-SEC-G-009).
Verify
Section titled “Verify”- Start the service against your production config and confirm it starts (or fails closed as
expected for a deliberately unmet
startup_failgate). - Query
GET /admin/v1/postureand read thedeploymentobject: confirm the profile matches what you declared, and that no unwaived finding at or above your profile’s threshold is outstanding. - Send a request that should be audited and confirm a corresponding record lands in your configured
sink, not only
stdout. - Attempt an admin-listener request from outside the private network it is meant to be bound to, and confirm it is refused.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Cause | Fix |
|---|---|---|
Process refuses to start after declaring production or evidence_grade | A startup_fail gate tripped (for example missing audit sink or unsigned config) | Check the posture or startup log for the finding id, then fix the underlying condition; startup_fail gates cannot be waived |
Posture reports deployment.profile_undeclared | No deployment.profile set | Declare a profile explicitly; an omitted profile is not the same as local |
Posture reports deployment.waiver_expired | A waiver’s expires date passed | Re-review the finding and either fix it or issue a new waiver with a new expiry |