Staged Docker repository authentication
deployctl verify-repository accepts strict JSON with directory (absolute trusted
staging directory), suite, architecture, and versions (exact version strings
for docker-ce, docker-ce-cli, containerd.io, docker-buildx-plugin and
docker-compose-plugin). It does not select a latest version or resolve dependencies.
The directory must contain docker.asc, Release, Release.gpg and uncompressed
Packages. The caller obtains these from the Docker Ubuntu repository. No runtime
network request is performed by this command. Limits are 1 MiB, 1 MiB, 64 KiB and
16 MiB respectively. Files must be nonempty regular files; symlinks are rejected.
Trusted ancestors and absence of concurrent writers are required. This is not an
atomic filesystem snapshot against hostile writers. Additional staging files are
ignored, never executed.
Trust and verification
- Exact armored key SHA-256 is pinned in source. Initial trust was bootstrapped
from
https://download.docker.com/linux/ubuntu/gpg, not supplied by the request. Primary fingerprint:9DC858229FC7DD38854AE2D88D81803C0EBFCD88. Rotation or formatting changes require a reviewed source update; fail closed. - Linux
/usr/bin/gpgdearmors into a new private temporary directory;/usr/bin/gpgvverifies the detached signature against the copied Release bytes, with that keyring and isolated homedir. No shell, ambient GnuPG config or personal keyring. Each child has a 15-second timeout and bounded output. Errors do not expose raw GnuPG diagnostics or metadata. Non-Linux or missing tools fail closed. - Successful process exit and a single accepted primary-fingerprint signature are required; weak digests, expired/revoked/bad signatures and unknown status types fail closed. SHA-256/384/512 are accepted.
- Authenticated Release must describe Docker CE and the requested supported Ubuntu suite, architecture and stable component. Date must be within 30 days and no more than 10 minutes in the future; Valid-Until is enforced when present.
- The exact uncompressed stable Packages entry's SHA-256 and byte size must match. Five explicitly requested versions are resolved to authenticated index records; the derived lock is checked by installplan's source/path/version constraints.
The machine clock, OS and installed GnuPG are trusted. This is not a persistent anti-rollback ledger: an older authentic Release inside the freshness window can pass, and a missing Valid-Until is governed by the local 30-day policy. No online key revocation lookup is performed. Key pin maintenance is an operator responsibility.
Result boundaries
repositoryAuthenticated: true attests to these metadata bytes at verifiedAt.
For verify-repository, packageBytesVerified: false and executable: false remain explicit: no deb bytes,
Ubuntu dependency repository, dependency closure, installation scripts, system
compatibility or service behavior have been verified. The result is not a signed
capability. plan-environment still treats a supplied lock as untrusted and does
not accept a caller's authentication claim to clear its trust blockers.
Signature scratch data is removed on normal return; a killed process can leave its own
private temporary directory. Deployment writes remain disabled. writesEnabled
in version refers to deployment writes, not verification scratch files.
scripts/probe-docker-repository.sh /absolute/path/to/deployctl is an optional
local online integration check. It downloads public metadata over HTTPS into a
new temporary directory, tests real authentication and rejects tampering. Versions
selected by this test are fixtures, not recommended installation versions. It
does not install packages, alter APT, use SSH or touch application data.
Verify actual deb bytes
verify-artifacts requires the same request fields as verify-repository, plus
artifactDirectory: an absolute trusted directory containing exactly the five deb
files named by the basename of each authenticated Filename. No other entries,
subdirectories, symlinks or special files are accepted. The two directories must
not be concurrently modified. Repository signatures and metadata are verified
anew in the same call; the command accepts neither a supplied lock nor trust flags.
Each file is streamed through SHA-256 with a 64 KiB copy buffer and its signed index size as the read bound (plus one overflow-detection byte). The existing lock policy caps each file at 512 MiB and requires exactly five files. A last-file failure rejects the entire result. No partial successful report is emitted. The verifier never unpacks a deb or executes its contents. It does not change the staged files. Metadata identity checks supplement, not replace, the trusted directory/no concurrent writer requirement.
Only verify-artifacts may set packageBytesVerified: true; executable stays
false. This verifies the selected five Docker package bytes, not the complete
Ubuntu dependency closure, package-internal safety or installation compatibility.
It is a point-in-time observation: do not reuse this JSON to authorize later
execution of paths that may have changed. A future installer must recheck or
own immutable verified snapshots under its operation lock.
Set DEPLOYCTL_ONLINE_ARTIFACT_PROBE=1 along with
DEPLOYCTL_ONLINE_REPOSITORY_PROBE=1 when running scripts/verify-linux.sh to
also download the five real public deb fixtures into a new local temporary
directory. The optional probe verifies all files, then changes one byte without
changing length and asserts rejection. It retains test files for inspection;
they are not installed and one is intentionally damaged by the negative test.