Unreleased documentation. These pages follow the main branch and can change before the next release. For supported guidance, use v0.26.1.
Start with the approved candidate created in
Build and deploy an Evidence Gateway project. This guide runs that
candidate in an existing Docker Compose application. Compose is an operator-owned deployment
adapter, not output from evidencectl package. The candidate bundle stays unchanged across host and
container deployments.
Before you start
Section titled “Before you start”You need an approved candidate, a container image whose provenance and digest you have reviewed, an owner-only secret mount, a workload-local Transit proxy, and persistent storage for the audit chain. Do not use repository development images as released production artifacts.
Prepare a container-specific runtime document. It names the same bundle content but container paths, a private Compose-network listener, secret root, audit path, and any required private CA files.
Add the Transit proxy boundary
Section titled “Add the Transit proxy boundary”Production and evidence-grade candidates require a workload-local Vault or OpenBao Transit proxy.
Run one proxy for Evidence Gateway on the host or in an operator-owned sidecar. Give the proxy a
dedicated host directory in which to create transit-proxy.sock, then bind-mount that directory at
/run/registry-evidence in the Evidence Gateway container. Make the directory searchable but not
writable by the Evidence Gateway identity. The proxy owns the directory and creates a mode 0660
socket whose group admits only that identity.
The proxy owns its provider auto-auth credential, provider trust file, and reviewed HCL
configuration. Do not mount those inputs into Evidence Gateway. The proxy configuration must force
its auto-auth token, require the X-Vault-Request header, disable request retries, and set socket
ownership for the Evidence Gateway process. Use
Configure Transit signing for Evidence Gateway
and the maintained deployment-target templates for the exact boundary.
The Git-managed proxy HCL is nonsecret. Provider credentials and generated tokens remain outside Git and outside the Evidence Gateway container. If Compose also owns the sidecar, replace the host bind with a dedicated named volume shared only by the proxy and Evidence Gateway.
Mount the deployment inputs
Section titled “Mount the deployment inputs”The Evidence Gateway service mounts five independently owned paths:
candidate/bundle -> /etc/registry-evidence/bundle read-onlyruntime.docker.yaml -> /etc/registry-evidence/runtime.yaml read-onlyEvidence secret root -> /run/secrets/registry-evidence read-onlyEvidence audit volume -> /var/lib/registry-evidence writableTransit socket directory -> /run/registry-evidence socket accessKeep the bundle and runtime read-only. A read-only mount establishes their immutability, but does
not waive secret ownership or mode validation. The maintained Evidence Gateway image runs as UID and GID
65532; pin that identity in the Compose file and make every secret file acceptable to it with the
required owner-only permissions. A different reviewed image requires an explicitly reviewed UID
and matching ownership.
Prepare the persistent audit volume for that same identity before startup. Do not run Evidence Gateway as
root to compensate for an audit volume with the wrong owner.
# Mounts and service identity only. This is not a complete service definition;# the note below this block names what it leaves out.services: evidence: image: <reviewed-evidence-image-by-digest> user: "65532:65532" read_only: true volumes: - <candidate>/bundle:/etc/registry-evidence/bundle:ro - ./runtime.docker.yaml:/etc/registry-evidence/runtime.yaml:ro - <evidence-secret-root>:/run/secrets/registry-evidence:ro - evidence-audit:/var/lib/registry-evidence - <transit-socket-directory>:/run/registry-evidence:roThat snippet shows the mounts and the service identity only. The maintained adapter at
docker/compose/docker-compose.yaml in the Registry Stack repository carries the rest of the
service posture, including dropped capabilities, no-new-privileges, and a read-only /dev/shm
that replaces the writable one Docker adds by default. Start from that file rather than from the
mounts alone.
Bind Evidence Gateway to a private Compose-network address. Put TLS termination and public routing in an operator-controlled service ahead of that listener.
Validate in the container context
Section titled “Validate in the container context”Start the Transit proxy, then run evidence check in the target execution context after mounts,
ownership, paths, and trust files are in place:
docker compose run --rm evidence \ --runtime /etc/registry-evidence/runtime.yaml check --require-runtime-dependenciesIt prints one line and exits zero:
Evidence deployment <bundle-revision> / <runtime-revision> passed check (<count> requirements)Both revisions are your own candidate’s, and the count is the number of requirements in your bundle, so the line will not match anyone else’s.
Both forms of the command compile the bundle, compile the source plans, refuse a mounted extract
already older than its source allows, validate the mounted secret material, and initialize the
configured signer, which signs a self-test message through the Transit proxy and verifies it
against the governed public JWK. That is why the proxy starts first: without a reachable socket
either form stops at evidence: runtime signing initialization failed.
--require-runtime-dependencies adds the dependencies a served request would need. It opens the
configured audit path, fetches the access-token issuer key set fail-closed, and resolves every
configured source credential. It appends no audit event in either form, so a check that fails
leaves the chain exactly as it found it.
Changing only the container runtime does not change the governed bundle, so it does not require the fixture suite to run again. Run fixtures again when the bundle changes.
Start the service
Section titled “Start the service”docker compose up -ddocker compose psThe service reads its runtime from REGISTRY_EVIDENCE_RUNTIME, which the maintained image already
points at /etc/registry-evidence/runtime.yaml, and its default command is serve. No further
arguments are needed.
Evidence Gateway writes line-delimited JSON to stdout. It announces the listener only after every listener is bound, so the announcement means the port is this deployment’s and not something else’s:
docker compose logs evidence | grep 'evidence service listening'That record carries the bundle revision, the runtime revision, the bind host, and the port. If no such line appears, read the whole log: startup failures are reported there, and the container will have exited.
The runtime in this guide binds a Compose-network address with no published ports, so /health is
reachable from another service on the same Compose network and not from your host. Publish a port
only behind the TLS-terminating service you control.
Keep revisions distinct
Section titled “Keep revisions distinct”The bundle revision covers exact bundle bytes and remains the same in host and Compose deployments.
The runtime revision covers exact runtime bytes and bound private CA files, so it changes with
container paths, listener bindings, or trust files. A configuration revision is narrower than either:
it covers one requirement’s own configuration and artifacts. Signed assertions carry the revision of
the requirement they answer as configurationRevision, never the runtime or bundle revision. No
revision contains secret values or audit contents.
Stop without deleting the audit history
Section titled “Stop without deleting the audit history”docker compose down removes the containers and the network it created. It leaves named volumes
alone, so the audit chain survives the stop:
docker compose downdocker volume ls | grep evidence-auditThe volume is still listed. Starting the service again appends to the same chain rather than beginning a new one.
docker compose down -v deletes that volume with everything else. The audit chain is
hash-linked and has no second copy, so the history is gone and cannot be reconstructed. Retention
and audit-chain verification remain operator responsibilities.