You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I thought I'd submit this after running into an issue and banging my head trying to figure out why my strict signature policy was not working during bootc upgrade after switching to my custom image. The cosign v2 vs v3 behavior drove me crazy for a while. So, with some AI assistance to make it easier to read and verify reference links, here is something that might help others. I'd be happy to write additional documentation or patches if people agree it would be helpful. This is probably too advanced for a basic user, but if you are going to use a custom repo as the source of truth for a production box, I think strict signature policy, similar in spirit to how Universal Blue protects its own images, is worthwhile. Troubleshooting signature issues is NOT FUN! ;) Honestly, we could skip all this too and just recommend people use BlueBuild if they want the strict stuff without the additional bits added here (they make a good product), but...here it is.
Summary
The current image-template signing flow is good for producing signed custom images, but it does not appear to document the additional steps needed when a user wants their installed bootc system to strictly enforce signatures for their own custom image repository on future upgrades.
The template already handles CI signing well. The missing advanced documentation is about installed-system enforcement: baking repo-specific trust policy into the custom image so future bootc upgrade operations reject unsigned or improperly signed updates.
That distinction matters because an image can be signed and manually verifiable without the installed system requiring signatures later.
Why this matters
The template currently signs published images with cosign, and the README tells users to generate a keypair, commit cosign.pub, store cosign.key as SIGNING_SECRET, and switch with:
sudo bootc switch ghcr.io/<username>/<image_name>
That is a much smoother default path, and it is probably the right beginner experience.
However, users who expect stricter production-style behavior may assume that because CI signs the image, their installed machine will require those signatures during future bootc upgrade operations. That requires more than CI signing. The image also needs to install the public key and write container signature policy/discovery config inside the OS.
Without those extra steps, the image is signed, but the installed system has no policy that requires future updates to be signed by that custom repo key.
Suggested documentation addition
Add an advanced section such as:
Optional: enforce signatures for your custom image during bootc upgrade
It could explain that strict enforcement requires:
Copying the repo's cosign.pub into the image, for example:
/etc/pki/containers/<image_name>.pub
Writing a repository-specific /etc/containers/policy.json rule using sigstoreSigned, for example:
Documenting that after booting into the custom image family, future updates should normally be:
sudo bootc upgrade
Cosign compatibility gotcha (what I ran into after upgrading cosign to v3)
If the optional strict-policy path uses use-sigstore-attachments: true, docs should also mention that the signer needs to produce signatures in the format that bootc/containers-image policy can discover. Otherwise, a future cosign v3-based signing flow may produce signatures that default cosign verify can find, while the bootc/containers-image policy path reports:
A signature was required, but no signature exists
That can happen when the signature is stored in a newer bundle/referrer format but the installed policy expects legacy sigstore attachments through use-sigstore-attachments.
For strict bootc policy compatibility with that discovery path, docs should tell users how to verify the same signature format that bootc policy will discover.
For example, with cosign v3 this may require signing with flags like:
The current template appears to install cosign v2.6.1, so this may not affect the template today. But it is worth documenting before the template or users move to cosign v3, because default cosign verify passing is not always the same thing as bootc policy being able to discover the signature.
Possible implementation options
This could be added in one of a few ways:
Documentation-only advanced section.
Optional helper script in build_files/ that writes policy files when users opt in.
Optional Containerfile snippet users can uncomment.
A note pointing users to BlueBuild's signing module if that is the preferred supported path for strict policy generation.
Why not make this the default?
I do not think this necessarily has to be the default for all image-template users. Strict enforcement has real operational sharp edges:
key rotation must be planned carefully,
users need to use the policy-enforcing first switch command,
repo renames affect the trust policy scope,
local unsigned builds are not accepted by strict policy,
signature storage format matters.
But documenting the distinction would help users who want to run custom images as a production system and expect the installed machine to reject future unsigned updates.
Note
I thought I'd submit this after running into an issue and banging my head trying to figure out why my strict signature policy was not working during
bootc upgradeafter switching to my custom image. The cosign v2 vs v3 behavior drove me crazy for a while. So, with some AI assistance to make it easier to read and verify reference links, here is something that might help others. I'd be happy to write additional documentation or patches if people agree it would be helpful. This is probably too advanced for a basic user, but if you are going to use a custom repo as the source of truth for a production box, I think strict signature policy, similar in spirit to how Universal Blue protects its own images, is worthwhile. Troubleshooting signature issues is NOT FUN! ;) Honestly, we could skip all this too and just recommend people use BlueBuild if they want the strict stuff without the additional bits added here (they make a good product), but...here it is.Summary
The current image-template signing flow is good for producing signed custom images, but it does not appear to document the additional steps needed when a user wants their installed bootc system to strictly enforce signatures for their own custom image repository on future upgrades.
The template already handles CI signing well. The missing advanced documentation is about installed-system enforcement: baking repo-specific trust policy into the custom image so future
bootc upgradeoperations reject unsigned or improperly signed updates.That distinction matters because an image can be signed and manually verifiable without the installed system requiring signatures later.
Why this matters
The template currently signs published images with cosign, and the README tells users to generate a keypair, commit
cosign.pub, storecosign.keyasSIGNING_SECRET, and switch with:That is a much smoother default path, and it is probably the right beginner experience.
However, users who expect stricter production-style behavior may assume that because CI signs the image, their installed machine will require those signatures during future
bootc upgradeoperations. That requires more than CI signing. The image also needs to install the public key and write container signature policy/discovery config inside the OS.Without those extra steps, the image is signed, but the installed system has no policy that requires future updates to be signed by that custom repo key.
Suggested documentation addition
Add an advanced section such as:
It could explain that strict enforcement requires:
Copying the repo's
cosign.pubinto the image, for example:Writing a repository-specific
/etc/containers/policy.jsonrule usingsigstoreSigned, for example:{ "transports": { "docker": { "ghcr.io/<username>/<image_name>": [ { "type": "sigstoreSigned", "keyPath": "/etc/pki/containers/<image_name>.pub", "signedIdentity": {"type": "matchRepository"} } ] } } }Writing a matching
/etc/containers/registries.d/file so containers/image can discover cosign signatures:Recommending the explicit policy-enforcing form for the first switch into the custom image:
Documenting that after booting into the custom image family, future updates should normally be:
Cosign compatibility gotcha (what I ran into after upgrading cosign to v3)
If the optional strict-policy path uses
use-sigstore-attachments: true, docs should also mention that the signer needs to produce signatures in the format that bootc/containers-image policy can discover. Otherwise, a future cosign v3-based signing flow may produce signatures that defaultcosign verifycan find, while the bootc/containers-image policy path reports:That can happen when the signature is stored in a newer bundle/referrer format but the installed policy expects legacy sigstore attachments through
use-sigstore-attachments.For strict bootc policy compatibility with that discovery path, docs should tell users how to verify the same signature format that bootc policy will discover.
For example, with cosign v3 this may require signing with flags like:
And verifying with:
The current template appears to install cosign
v2.6.1, so this may not affect the template today. But it is worth documenting before the template or users move to cosign v3, because defaultcosign verifypassing is not always the same thing as bootc policy being able to discover the signature.Possible implementation options
This could be added in one of a few ways:
build_files/that writes policy files when users opt in.Why not make this the default?
I do not think this necessarily has to be the default for all image-template users. Strict enforcement has real operational sharp edges:
But documenting the distinction would help users who want to run custom images as a production system and expect the installed machine to reject future unsigned updates.
References
sigstoreSigneddocs: https://github.com/containers/image/blob/main/docs/containers-policy.json.5.md