Versioned archive. You are viewing v0.38.0. For the latest released guidance, use Latest release. Report archive issues on GitHub.
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 package 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 package 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 -> /etc/registry-evidence/package 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 package 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>:/etc/registry-evidence/package: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 \ check --runtime-config /etc/registry-evidence/runtime.yaml --require-runtime-dependenciesIt prints one line and exits zero:
Evidence package <package-digest> passed check (<count> requirements)The digest is your own package’s, and the count is the number of requirements in that package, so the line will not match anyone else’s.
Both forms of the command compile the verified package, 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: the Transit provider did not answer on the configured Unix socket (missing socket, refused connection, or timeout).
--require-runtime-dependencies adds the dependencies a served request would need. It opens the
configured audit writer exactly as serve would: creating the audit file and its lock if they are
not already there, and deleting any sealed file already past audit.retainDays. It fetches the
access-token issuer key set fail-closed and resolves every configured source credential. It appends
no audit event of its own, but run beside a running service it refuses instead, because the writer
is a single-writer destination and the running service already holds its lock.
Opening the audit path takes its single-writer lock, so a candidate that shares that path with a
running instance is refused with another process holds the single-writer lock beside the audit file. To
check the candidate before cutover without stopping that instance, add --without-audit-lock. The
audit hash key is still checked, and the audit directory and files are still checked for
ownership, mode, write access, and a complete final entry. The lock stays with the running
instance.
Changing only the container runtime does not change the governed package, so it does not require the fixture suite to run again. Run fixtures again when the package changes.
Start the service
Section titled “Start the service”docker compose up -ddocker compose psThe maintained image’s default command is serve --runtime-config /etc/registry-evidence/runtime.yaml, the path the runtime file is mounted at. 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 package digest, 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 package and requirement digests distinct
Section titled “Keep package and requirement digests distinct”The package digest covers the exact SHA256SUMS bytes and remains the same in host and Compose
deployments. Runtime paths, listener bindings, trust files, secrets, and audit contents remain
outside that package identity. A configuration revision is narrower than the package digest: it
covers one requirement’s own configuration and artifacts. Signed assertions carry the revision of
the requirement they answer as configurationRevision, never the whole-package digest. Neither
digest 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 log survives the stop:
docker compose downdocker volume ls | grep evidence-auditThe volume is still listed. Starting the service again appends to the same audit file rather than beginning a new one.
docker compose down -v deletes that volume with everything else. Unless you shipped the audit
files to append-only storage first, the history is gone and cannot be reconstructed. Shipping and
retention beyond the volume remain operator responsibilities.