Homelab Academy / Modules
Learn: instruction, vocabulary, worked example.
Module: Compose Operations & IaC
Activity type: Reading (Learn)
Objective: Explain why a mutable tag is unsuitable as the final deployment identity.
| Term | Meaning |
|---|---|
| tag | A human-friendly and generally mutable image reference such as stable or 1.4. A registry operator can move a tag to a different object. |
| channel | An operational release stream, such as stable, that this lab maps to an image index. A channel is mutable and is not itself an immutable deployment identity. |
| image index | A multi-platform object containing descriptors for one or more platform-specific image manifests. A client selects a descriptor matching its requested operating system and architecture. |
| platform manifest | The manifest selected from an image index for one exact platform, such as linux/amd64. Its digest, rather than the channel name, becomes the deployment pin in this lab. |
| descriptor | Metadata pointing to content by digest and, when applicable, identifying the operating system and architecture for which that content was built. |
| digest pin | An immutable reference of the form repository@sha256:hexadecimal-value. The pin used here is the digest of the selected platform manifest. |
| out-of-band approval | An expected channel, platform, and digest supplied independently of the registry catalog being evaluated. In production this may come from a reviewed release record, deployment controller, or signed policy system. |
| fail closed | Refusing promotion when required input is missing, malformed, ambiguous, inconsistent, unapproved, or unverifiable. |
| audit linkage | A record that explicitly connects the digest deployed before an operation to the digest deployed after it. |
Container tags are convenient names, but they are usually mutable pointers. If a deployment records only academy/demo:stable, the bytes selected tomorrow may differ from the bytes selected today even though the text of the deployment reference has not changed. Digest pinning changes the final identity to a content-addressed reference such as academy/demo@sha256:ba7816bf..., making an unnoticed tag move insufficient to alter the deployed identity.
Multi-platform images add an important distinction. A channel or tag commonly resolves to an OCI image index. The index is not the same object as the image manifest used by a linux/amd64 node. The index contains descriptors for multiple platforms, and the client selects one matching the requested operating system and architecture. A policy intended to approve the runnable linux/amd64 artifact must therefore compare the digest of the selected linux/amd64 manifest, not merely a tag and not an unrelated platform descriptor. The lab registry models this explicitly: stable points to index-v2, index-v2 points to linux/amd64 and linux/arm64 manifests, and the deployment pin uses the selected linux/amd64 manifest digest.
Content hashing and authorization answer different questions. Recomputing a catalog-provided digest can detect accidental corruption when the declared digest and bytes no longer agree, but a party able to replace both the content and the digest can create a new self-consistent pair. A local policy file stored beside the catalog also does not solve that boundary if the same party can edit both files. For that reason, update.py requires an expected channel, platform, and digest supplied independently at invocation time. It checks the requested tuple, resolves the catalog index, selects exactly one matching platform descriptor, verifies the selected blob against the descriptor, compares the selected digest with the out-of-band expected digest, and then confirms local policy approval. Any mismatch is rejected before deployment, backup, or audit state is written.
The lab uses the published SHA-256 test vectors for the exact bytes abc, hello, and the empty byte string. Their literal golden values are included in the lesson and verification commands. This avoids relying solely on values generated by the setup code or by update.py. The dry-run and rejection tests also compare complete deployment and audit files before and after each attempt. A successful promotion creates a retained backup, atomically replaces deployment.json, and appends an audit event linking the previous digest to the new digest. Rollback copies the failed deployment aside, validates the retained backup against both an out-of-band rollback digest and local approval, copies rather than moves the backup into place, verifies the restored state, and only then appends the rollback event.
All generated and mutated files are confined to /opt/lab-classroom/class81/.
The stable channel resolves to index-v2 in registry.json.
index-v2 contains separate linux/amd64 and linux/arm64 descriptors.
The requested linux/amd64 platform selects the descriptor whose manifest blob is the exact byte sequence abc.
The selected descriptor digest is compared with the independently supplied expected digest.
The selected tuple is checked against policy.json.
The deployment is written as registry.lab/academy/demo@sha256:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad.
A successful update retains deployment.backup.json and appends an audit record with from_digest and to_digest.
registry.json and its blobs represent registry-controlled data and are not trusted merely because they agree with one another.
policy.json represents local authorization but is deliberately tested as mutable within the same lab boundary.
The command-line expected channel, platform, and digest model independently reviewed release approval.
The lesson's literal golden digest values are independently published expectations and are not generated by setup.py or update.py.
hello
sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
abc
sha256:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
test
sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08