Lab 04 — Sign and Verify Container Images
Mission Information
Section titled “Mission Information”| Item | Details |
|---|---|
| Lab ID | K8S-IMAGE-SECURITY-LAB-04 |
| Difficulty | Advanced |
| Estimated Time | 4–6 Hours |
| Environment | Local Workstation, Private OCI Registry and Kubernetes Training Cluster |
| Platform | Docker, Cosign, Trivy, Kubernetes and OCI-Compatible Registry |
| Supported Registries | Amazon ECR, Azure Container Registry, Google Artifact Registry, Harbor, GitHub Container Registry |
| Cost | Free for Local Tools / Registry and Cloud Charges May Apply |
| Primary Role | DevSecOps Engineer |
| Supporting Roles | Kubernetes Security Engineer, Cloud Security Engineer, Platform Engineer, Application Security Engineer |
| Module | Kubernetes Container Image and Supply Chain Security |
| Previous Lab | Lab 03 — Secure Private Container Registries |
| Next Lab | Lab 05 — Enforce Trusted Images with Admission Policies |
Mission Scenario
Section titled “Mission Scenario”CloudNova Technologies has implemented:
- Secure container builds
- Container-image vulnerability scanning
- Private registry controls
- Immutable production tags
- Digest-based Kubernetes deployments
- Registry audit logging
- Repository-level access controls
However, the security team has identified an important remaining gap.
The private registry can confirm where an image is stored, but the Kubernetes platform cannot yet determine:
- Who approved the image
- Who signed the image
- Whether the image was changed after approval
- Whether the image came from an authorised CI/CD pipeline
- Whether an SBOM belongs to the deployed image
- Whether required security checks were completed
- Whether the signing identity is trusted
- Whether the image signature is valid
- Whether the image meets production policy
During a recent internal assessment, an unauthorised image was pushed into a staging repository using compromised CI/CD credentials.
The image passed basic registry authentication but had not been:
- Signed by an approved identity
- Associated with verified build provenance
- Linked to an approved SBOM
- Validated through an admission policy
CloudNova Technologies has therefore introduced a mandatory software supply-chain trust requirement.
Every production container image must:
- Be stored in an approved private registry.
- Be identified using an immutable digest.
- Pass vulnerability and secret scanning.
- Have an approved SBOM.
- Be signed by an authorised identity.
- Have its signature independently verified.
- Include required attestations.
- Be rejected when signature verification fails.
- Be evaluated by Kubernetes admission policy before deployment.
Your mission is to establish this signed-image workflow using Cosign.
Learning Objectives
Section titled “Learning Objectives”By completing this lab, you will learn how to:
- Explain container-image signing
- Understand software-artifact integrity
- Install and validate Cosign
- Identify an image by immutable digest
- Generate a Cosign key pair
- Protect private signing keys
- Sign a container image using a local key
- Verify a key-based image signature
- Perform identity-based keyless signing
- Verify certificate identity and OIDC issuer
- Understand transparency-log records
- Generate an SBOM
- Create and attach attestations
- Verify image attestations
- Test invalid-signature scenarios
- Review signature metadata
- Define enterprise signing identities
- Prepare Kubernetes admission enforcement
- Produce an enterprise image-trust report
Enterprise Image-Trust Architecture
Section titled “Enterprise Image-Trust Architecture” Application Source Code
│
▼
Controlled CI/CD Pipeline
│
┌─────────────────┼─────────────────┐ │ │ │
Container Build Security Scanning SBOM Generation
│ │ │
└─────────────────┼─────────────────┘
│
▼
Approved Image by Digest
│
▼
Cosign Image Signature
│
┌─────────────────┼─────────────────┐ │ │ │
Signing Identity Attestation Transparency Record
│ │ │
└─────────────────┼─────────────────┘
│
▼
Private Container Registry
│
▼
Kubernetes Admission Verification
│
┌─────────────┴─────────────┐ │ │
Verified Unverified
│ │
▼ ▼
Deployment Allowed Deployment RejectedContainer Image Trust Model
Section titled “Container Image Trust Model”Trusted Source
│
▼
Controlled Build
│
▼
Security Scan
│
▼
Immutable Digest
│
▼
Verified Signature
│
▼
Approved Attestation
│
▼
Admission Enforcement
│
▼
Runtime MonitoringSignature Trust Principles
Section titled “Signature Trust Principles”This lab applies the following principles:
- Sign immutable image digests rather than mutable tags.
- Keep private signing keys protected.
- Prefer short-lived identity-based signing where appropriate.
- Validate both signature integrity and signer identity.
- Store signatures and attestations with OCI artifacts.
- Do not treat a valid signature as proof that software is vulnerability-free.
- Enforce signature verification before production deployment.
- Retain signing and verification evidence.
- Separate image builders, approvers and deployers.
- Revoke trust when a signing identity is compromised.
What an Image Signature Provides
Section titled “What an Image Signature Provides”A valid container-image signature can provide assurance that:
- The signed artifact has not changed.
- The image digest matches the signed artifact.
- The signer possessed an approved signing identity or key.
- Verification can be performed independently.
- The signature can be evaluated by automated policy.
A signature does not automatically prove that:
- The application is secure.
- The image has no vulnerabilities.
- The source code is trustworthy.
- The CI/CD system was not compromised.
- The signer made a correct approval decision.
- The running workload is securely configured.
Image signing must be combined with:
- Secure software development
- Vulnerability scanning
- Secret scanning
- SBOM generation
- Build provenance
- Registry security
- Admission control
- Kubernetes workload hardening
- Runtime monitoring
Lab Outcomes
Section titled “Lab Outcomes”By the end of this lab, you will have:
- Installed Cosign
- Validated the Cosign installation
- Identified an approved registry image by digest
- Generated a signing-key pair
- Protected the private signing key
- Signed an image using a local key
- Verified the image signature
- Tested verification with an incorrect key
- Performed keyless signing where supported
- Verified the signing identity
- Inspected signature metadata
- Generated a CycloneDX SBOM
- Attached an SBOM-related attestation
- Verified an attestation
- Created a vulnerability-scan attestation
- Tested unsigned-image verification
- Prepared a Kubernetes Deployment using the signed digest
- Designed an enterprise signature policy
- Produced an image-signing security report
Important Security Notice
Section titled “Important Security Notice”Use only container images, registries, cloud accounts and identities that you are authorised to manage.
Do not:
- Use production signing keys in a training environment
- Commit private signing keys to Git
- Store signing-key passwords in scripts
- Share signing keys between teams
- Sign unknown or unapproved images
- Sign images using mutable tags without first resolving the digest
- Publish confidential attestation data
- Expose OIDC identity tokens
- Disable signature verification to bypass deployment controls
- Delete signature evidence related to an incident
- Use test identities to approve production images
Prerequisites
Section titled “Prerequisites”Before starting, ensure that you have:
- Docker Desktop, Docker Engine or Podman
- Cosign installed or permission to install it
- Trivy installed
kubectlinstalledjqinstalled where possible- A Kubernetes training cluster
- Access to an authorised OCI-compatible registry
- A hardened image from Lab 02
- A secure private registry from Lab 03
- The image pushed to the private registry
- The immutable image digest recorded
- Permission to push signatures and attestations
- Visual Studio Code
- Git Bash or PowerShell
Recommended image reference:
<registry-endpoint>/<repository>@sha256:<approved-digest>Tools Used
Section titled “Tools Used”| Tool | Purpose |
|---|---|
| Cosign | Sign and verify images and attestations |
| Docker or Podman | Inspect, pull and manage images |
| Trivy | Scan images and generate SBOM data |
| kubectl | Prepare and validate Kubernetes deployment |
| jq | Review JSON verification output |
| OCI Registry | Store images, signatures and attestations |
| Git Bash / PowerShell | Execute commands |
| Visual Studio Code | Create policies, manifests and reports |
Recommended Lab File Structure
Section titled “Recommended Lab File Structure”lab-04-sign-and-verify-container-images/├── keys/│ ├── cosign.pub│ └── README.md├── attestations/│ ├── vulnerability-scan-predicate.json│ ├── build-review-predicate.json│ └── sbom-cyclonedx.json├── kubernetes/│ ├── namespace.yaml│ ├── signed-deployment.yaml│ ├── unsigned-deployment.yaml│ └── cluster-image-policy-example.yaml├── policies/│ ├── enterprise-signing-policy.md│ ├── trusted-identities.md│ ├── signing-key-rotation.md│ └── signing-incident-response.md├── reports/│ ├── image-scan.json│ ├── signature-verification.json│ ├── attestation-verification.json│ ├── image-trust-assessment.md│ └── image-signing-security-report.md└── evidence/ ├── cosign-version.txt ├── image-reference.txt ├── image-digest.txt ├── public-key.txt ├── signing-result.txt ├── verification-result.txt ├── failed-verification.txt ├── keyless-verification.txt ├── attestation-result.txt └── deployment-validation.txtTask 01 — Create the Lab Workspace
Section titled “Task 01 — Create the Lab Workspace”Git Bash
Section titled “Git Bash”mkdir -p lab-04-sign-and-verify-container-images/keysmkdir -p lab-04-sign-and-verify-container-images/attestationsmkdir -p lab-04-sign-and-verify-container-images/kubernetesmkdir -p lab-04-sign-and-verify-container-images/policiesmkdir -p lab-04-sign-and-verify-container-images/reportsmkdir -p lab-04-sign-and-verify-container-images/evidence
cd lab-04-sign-and-verify-container-imagesPowerShell
Section titled “PowerShell”New-Item -ItemType Directory -Force ` -Path lab-04-sign-and-verify-container-images\keys
New-Item -ItemType Directory -Force ` -Path lab-04-sign-and-verify-container-images\attestations
New-Item -ItemType Directory -Force ` -Path lab-04-sign-and-verify-container-images\kubernetes
New-Item -ItemType Directory -Force ` -Path lab-04-sign-and-verify-container-images\policies
New-Item -ItemType Directory -Force ` -Path lab-04-sign-and-verify-container-images\reports
New-Item -ItemType Directory -Force ` -Path lab-04-sign-and-verify-container-images\evidence
Set-Location lab-04-sign-and-verify-container-imagesVerify:
ls -RTask 02 — Install Cosign
Section titled “Task 02 — Install Cosign”Install Cosign using the approved method for your operating system.
After installation, validate it.
cosign versionSave the version.
Git Bash
Section titled “Git Bash”cosign version > evidence/cosign-version.txtPowerShell
Section titled “PowerShell”cosign version | Out-File evidence\cosign-version.txtRecord:
Cosign Version:
Git Version:
Build Date:
Go Version:
Operating System:
Installation Method:Task 03 — Verify the Cosign Binary Source
Section titled “Task 03 — Verify the Cosign Binary Source”Before using Cosign in an enterprise environment, validate:
- Download source
- Release version
- Release checksum
- Binary signature
- Package-manager source
- Approved software inventory
- Internal software-distribution policy
Document:
Installation Source:
Release Version:
Checksum Validated:
Signature Validated:
Security Approval:
Installed By:
Installation Date:Task 04 — Define the Approved Image Reference
Section titled “Task 04 — Define the Approved Image Reference”Set the image reference using its immutable digest.
Git Bash
Section titled “Git Bash”export IMAGE="<registry-endpoint>/<repository>@sha256:<approved-digest>"Verify:
echo "$IMAGE"PowerShell
Section titled “PowerShell”$IMAGE = "<registry-endpoint>/<repository>@sha256:<approved-digest>"Verify:
Write-Host $IMAGESave the reference.
Git Bash
Section titled “Git Bash”echo "$IMAGE" > evidence/image-reference.txtPowerShell
Section titled “PowerShell”$IMAGE | Out-File evidence\image-reference.txtTask 05 — Confirm Registry Authentication
Section titled “Task 05 — Confirm Registry Authentication”Authenticate using the approved registry method.
Examples include:
- Cloud CLI credential helper
- Workload identity
- Managed identity
- Short-lived access token
- Federated identity
Verify the image can be pulled.
docker pull "$IMAGE"PowerShell:
docker pull $IMAGEDo not place registry passwords directly in shell commands.
Task 06 — Verify the Image Digest
Section titled “Task 06 — Verify the Image Digest”Inspect the image.
docker image inspect "$IMAGE"Retrieve repository digests.
docker image inspect "$IMAGE" \ --format='{{json .RepoDigests}}'Save the digest.
Git Bash
Section titled “Git Bash”docker image inspect "$IMAGE" \ --format='{{json .RepoDigests}}' \ > evidence/image-digest.txtPowerShell
Section titled “PowerShell”docker image inspect $IMAGE ` --format='{{json .RepoDigests}}' | Out-File evidence\image-digest.txtConfirm:
- The digest matches Lab 03.
- The image exists in the approved registry.
- The image is not referenced only by a mutable tag.
- The image is the approved build artifact.
Task 07 — Re-Scan the Image Before Signing
Section titled “Task 07 — Re-Scan the Image Before Signing”Perform a final vulnerability scan.
trivy image \ --severity HIGH,CRITICAL \ "$IMAGE"Export the complete report.
trivy image \ --format json \ --output reports/image-scan.json \ "$IMAGE"Review:
- Critical vulnerabilities
- High vulnerabilities
- Fixed versions
- Unfixed vulnerabilities
- Secret findings
- Image configuration
- Scan time
- Scanner version
Do not sign an image merely because the signing command succeeds.
Signing must occur only after required security controls pass.
Task 08 — Define the Signing Approval Gate
Section titled “Task 08 — Define the Signing Approval Gate”Create an approval checklist.
| Control | Required Result |
|---|---|
| Approved source repository | Confirmed |
| Approved build pipeline | Confirmed |
| Immutable image digest | Recorded |
| Critical vulnerability review | Completed |
| High vulnerability review | Completed |
| Secret scan | Passed |
| Malware scan | Passed |
| SBOM generated | Completed |
| Licence review | Completed where required |
| Build provenance | Available |
| Registry destination | Approved |
| Security approval | Recorded |
Assign one of the following decisions:
- Approved for Signing
- Conditionally Approved
- Rejected
- Requires Further Investigation
Task 09 — Understand Signing Approaches
Section titled “Task 09 — Understand Signing Approaches”Cosign commonly supports two enterprise signing models.
Key-Based Signing
Section titled “Key-Based Signing”A private cryptographic key signs the artifact.
Advantages:
- Can operate with internal key-management systems
- Can support offline or private trust models
- Public key can be distributed to verifiers
Risks:
- Private key must be stored securely
- Key rotation is required
- Key compromise can affect all signed artifacts
- Shared keys weaken attribution
Identity-Based Keyless Signing
Section titled “Identity-Based Keyless Signing”The signer authenticates through an approved OIDC identity provider.
Advantages:
- No long-lived private signing key for the user
- Signature is associated with an identity
- Short-lived certificates can be used
- Suitable for CI/CD workload identity
Risks:
- Trust depends on the identity provider
- Verification must check the expected identity and issuer
- Identity compromise can result in unauthorised signing
- Public transparency records may expose non-secret metadata
Task 10 — Generate a Training Key Pair
Section titled “Task 10 — Generate a Training Key Pair”Use training keys only.
cosign generate-key-pairCosign creates:
cosign.keycosign.pubMove the public key into the lab directory.
Git Bash
Section titled “Git Bash”mv cosign.pub keys/cosign.pubPowerShell
Section titled “PowerShell”Move-Item cosign.pub keys\cosign.pubKeep the private key outside source control.
For example:
secure-key-storage/cosign.keyTask 11 — Protect the Private Key
Section titled “Task 11 — Protect the Private Key”Validate that the private key is not stored in the Git repository.
Create or update .gitignore.
cosign.key*.keysecure-key-storage/.envReview Git status.
git statusOn Linux or Git Bash, restrict file permissions where supported.
chmod 600 secure-key-storage/cosign.keyDocument:
Key Type:
Key Owner:
Key Location:
Password Protected:
File Permissions:
Backup Location:
Rotation Date:
Revocation Procedure:Task 12 — Review the Public Key
Section titled “Task 12 — Review the Public Key”Display the public key.
cat keys/cosign.pubPowerShell:
Get-Content keys\cosign.pubSave a copy as evidence.
Git Bash
Section titled “Git Bash”cp keys/cosign.pub evidence/public-key.txtPowerShell
Section titled “PowerShell”Copy-Item keys\cosign.pub evidence\public-key.txtThe public key can be distributed to authorised verifiers.
The private key must remain protected.
Task 13 — Sign the Image with the Private Key
Section titled “Task 13 — Sign the Image with the Private Key”Set the private-key location.
Git Bash
Section titled “Git Bash”export COSIGN_KEY="secure-key-storage/cosign.key"PowerShell
Section titled “PowerShell”$COSIGN_KEY = "secure-key-storage\cosign.key"Sign the immutable image reference.
Git Bash
Section titled “Git Bash”cosign sign \ --key "$COSIGN_KEY" \ "$IMAGE"PowerShell
Section titled “PowerShell”cosign sign ` --key $COSIGN_KEY ` $IMAGEEnter the key password securely when prompted.
Do not pass the password directly in shell history.
Task 14 — Record the Signing Result
Section titled “Task 14 — Record the Signing Result”Capture the signing result without exposing secret data.
Git Bash
Section titled “Git Bash”cosign sign \ --key "$COSIGN_KEY" \ "$IMAGE" \ > evidence/signing-result.txt 2>&1PowerShell
Section titled “PowerShell”cosign sign ` --key $COSIGN_KEY ` $IMAGE *> evidence\signing-result.txtRecord:
Image:
Digest:
Signing Method:
Signing Key Owner:
Signing Time:
Registry:
Signature Storage:
Approval Record:
Result:Task 15 — Verify the Key-Based Signature
Section titled “Task 15 — Verify the Key-Based Signature”Verify the image using the public key.
Git Bash
Section titled “Git Bash”cosign verify \ --key keys/cosign.pub \ "$IMAGE"PowerShell
Section titled “PowerShell”cosign verify ` --key keys\cosign.pub ` $IMAGEExpected result:
- Signature verification succeeds.
- The signed image digest matches.
- Signature payload information is returned.
Task 16 — Export Verification Results
Section titled “Task 16 — Export Verification Results”Export verification output in JSON format.
Git Bash
Section titled “Git Bash”cosign verify \ --key keys/cosign.pub \ --output json \ "$IMAGE" \ > reports/signature-verification.jsonPowerShell
Section titled “PowerShell”cosign verify ` --key keys\cosign.pub ` --output json ` $IMAGE | Out-File reports\signature-verification.jsonSave the human-readable result.
Git Bash
Section titled “Git Bash”cosign verify \ --key keys/cosign.pub \ "$IMAGE" \ > evidence/verification-result.txt 2>&1Task 17 — Inspect the Verification Output
Section titled “Task 17 — Inspect the Verification Output”Where jq is installed:
jq '.' reports/signature-verification.jsonReview:
- Critical image identity
- Docker reference
- Image digest
- Signature payload
- Certificate information where applicable
- Transparency-log data where applicable
- Verification status
Document:
Verified Image:
Verified Digest:
Signature Count:
Verification Key:
Certificate Identity:
Certificate Issuer:
Transparency Record:
Verification Result:Task 18 — Generate an Incorrect Test Key
Section titled “Task 18 — Generate an Incorrect Test Key”Create a separate key pair for negative testing.
mkdir -p test-keyscd test-keyscosign generate-key-pairReturn to the lab directory.
cd ..Do not replace the trusted signing key.
Task 19 — Test Verification with the Incorrect Public Key
Section titled “Task 19 — Test Verification with the Incorrect Public Key”Attempt verification using the incorrect public key.
cosign verify \ --key test-keys/cosign.pub \ "$IMAGE"Expected:
Verification failureSave the result.
Git Bash
Section titled “Git Bash”cosign verify \ --key test-keys/cosign.pub \ "$IMAGE" \ > evidence/failed-verification.txt 2>&1PowerShell:
cosign verify ` --key test-keys\cosign.pub ` $IMAGE *> evidence\failed-verification.txtConfirm that the command returns a non-zero exit code.
Git Bash
Section titled “Git Bash”echo $?PowerShell
Section titled “PowerShell”$LASTEXITCODETask 20 — Test Verification of an Unsigned Image
Section titled “Task 20 — Test Verification of an Unsigned Image”Select an authorised training image that has not been signed.
export UNSIGNED_IMAGE="<registry-endpoint>/<repository>@sha256:<unsigned-digest>"Attempt verification.
cosign verify \ --key keys/cosign.pub \ "$UNSIGNED_IMAGE"Expected:
- No valid signature is found.
- Verification fails.
- The image must not pass a signed-image admission policy.
Do not use an unknown public image for enterprise trust testing.
Task 21 — Understand Keyless Signing
Section titled “Task 21 — Understand Keyless Signing”In a supported environment, keyless signing uses an OIDC identity.
The signing identity may represent:
- A developer
- A release engineer
- A GitHub Actions workflow
- A GitLab pipeline
- A cloud workload identity
- An enterprise identity-provider user
- A controlled build service
The verifier must validate:
- Expected certificate identity
- Expected OIDC issuer
- Image digest
- Signature integrity
- Transparency information where required
Task 22 — Perform Keyless Signing
Section titled “Task 22 — Perform Keyless Signing”Use an authorised training identity.
cosign sign "$IMAGE"Follow the authentication workflow presented by Cosign.
Depending on the environment, this may involve:
- Browser-based OIDC authentication
- CI/CD identity token
- Cloud workload identity
- Device-code authentication
Record only non-sensitive information.
Signing Identity:
OIDC Issuer:
Signing Time:
Image Digest:
Transparency Entry:
Result:Task 23 — Verify the Keyless Signature
Section titled “Task 23 — Verify the Keyless Signature”Verify using the expected identity and issuer.
cosign verify "$IMAGE" \ --certificate-identity="<approved-identity>" \ --certificate-oidc-issuer="<approved-oidc-issuer>"Example identity forms may include:
release-engineer@example.comor an approved CI/CD workflow identity.
Do not use broad wildcard identities for production verification without a documented security justification.
Task 24 — Export Keyless Verification Evidence
Section titled “Task 24 — Export Keyless Verification Evidence”cosign verify "$IMAGE" \ --certificate-identity="<approved-identity>" \ --certificate-oidc-issuer="<approved-oidc-issuer>" \ --output json \ > evidence/keyless-verification.txtReview:
- Certificate subject
- Certificate issuer
- Image digest
- Signature time
- Transparency-log information
- Verification result
Task 25 — Test an Incorrect Signing Identity
Section titled “Task 25 — Test an Incorrect Signing Identity”Attempt verification using an identity that did not sign the image.
cosign verify "$IMAGE" \ --certificate-identity="unauthorised@example.com" \ --certificate-oidc-issuer="<approved-oidc-issuer>"Expected:
Verification failureThis demonstrates that verification must validate signer identity rather than only the presence of a signature.
Task 26 — Test an Incorrect OIDC Issuer
Section titled “Task 26 — Test an Incorrect OIDC Issuer”Use the correct identity but an incorrect issuer.
cosign verify "$IMAGE" \ --certificate-identity="<approved-identity>" \ --certificate-oidc-issuer="https://invalid-issuer.example.com"Expected:
Verification failureDocument:
| Test | Expected | Actual |
|---|---|---|
| Correct identity and issuer | Pass | |
| Incorrect identity | Fail | |
| Incorrect issuer | Fail | |
| Incorrect image digest | Fail | |
| Unsigned image | Fail |
Task 27 — Review Transparency Information
Section titled “Task 27 — Review Transparency Information”Review the verification output for transparency-related data.
Where supported, document:
Log Entry Identifier:
Integrated Time:
Signed Entry Timestamp:
Log Index:
Certificate Identity:
Certificate Issuer:
Image Digest:A transparency log can support:
- Auditability
- Detection of unexpected signatures
- Historical verification
- Incident investigation
- Software supply-chain monitoring
Do not store confidential application data in public transparency metadata.
Task 28 — Generate a CycloneDX SBOM
Section titled “Task 28 — Generate a CycloneDX SBOM”Generate an SBOM for the signed image.
trivy image \ --format cyclonedx \ --output attestations/sbom-cyclonedx.json \ "$IMAGE"Review:
jq '.' attestations/sbom-cyclonedx.jsonCount components where supported:
jq '.components | length' \ attestations/sbom-cyclonedx.jsonRecord:
SBOM Format:
Image:
Image Digest:
Generator:
Generation Time:
Component Count:
Storage Location:Task 29 — Validate the SBOM Before Attestation
Section titled “Task 29 — Validate the SBOM Before Attestation”Review the SBOM for:
- Image identity
- Package names
- Package versions
- Package identifiers
- Suppliers
- Licences
- Dependency relationships
- Creation timestamp
- Generator identity
Confirm that the SBOM belongs to the exact image digest being signed.
Task 30 — Create a Vulnerability-Scan Predicate
Section titled “Task 30 — Create a Vulnerability-Scan Predicate”Create:
attestations/vulnerability-scan-predicate.jsonExample:
{ "scanner": { "name": "Trivy", "version": "<trivy-version>" }, "image": { "reference": "<registry-endpoint>/<repository>", "digest": "sha256:<approved-digest>" }, "scan": { "completed": true, "scanTime": "<UTC-timestamp>", "criticalFindings": 0, "highFindings": 0, "secretFindings": 0, "policyResult": "passed" }, "approval": { "approvedBy": "<approved-security-role>", "ticket": "<change-or-approval-reference>" }}Replace placeholders with actual lab values.
Do not include confidential vulnerability details that are not approved for registry storage.
Task 31 — Create a Build-Review Predicate
Section titled “Task 31 — Create a Build-Review Predicate”Create:
attestations/build-review-predicate.jsonExample:
{ "build": { "repository": "<source-repository>", "commit": "<git-commit>", "pipeline": "<pipeline-name>", "buildId": "<build-id>", "builder": "<builder-identity>", "buildTime": "<UTC-timestamp>" }, "security": { "sourceReview": "passed", "dependencyScan": "passed", "imageScan": "passed", "secretScan": "passed", "sbomGenerated": true }, "release": { "environment": "training", "approved": true, "approvalReference": "<approval-reference>" }}Task 32 — Attach a Key-Based Attestation
Section titled “Task 32 — Attach a Key-Based Attestation”Create an attestation using the training private key.
cosign attest \ --key "$COSIGN_KEY" \ --predicate attestations/vulnerability-scan-predicate.json \ --type vulnerability-scan \ "$IMAGE"Record the result.
cosign attest \ --key "$COSIGN_KEY" \ --predicate attestations/vulnerability-scan-predicate.json \ --type vulnerability-scan \ "$IMAGE" \ > evidence/attestation-result.txt 2>&1Task 33 — Verify the Vulnerability Attestation
Section titled “Task 33 — Verify the Vulnerability Attestation”Verify using the trusted public key.
cosign verify-attestation \ --key keys/cosign.pub \ --type vulnerability-scan \ "$IMAGE"Export the result.
cosign verify-attestation \ --key keys/cosign.pub \ --type vulnerability-scan \ --output json \ "$IMAGE" \ > reports/attestation-verification.jsonTask 34 — Inspect the Attestation Payload
Section titled “Task 34 — Inspect the Attestation Payload”Review the verification output.
jq '.' reports/attestation-verification.jsonWhere required, decode the payload using the structure returned by your installed Cosign version.
Validate:
- Subject image digest
- Predicate type
- Predicate contents
- Signer
- Signature
- Verification result
Document:
Attested Image:
Attested Digest:
Predicate Type:
Scanner:
Policy Result:
Approver:
Verification Key:
Verification Result:Task 35 — Attach the Build-Review Attestation
Section titled “Task 35 — Attach the Build-Review Attestation”cosign attest \ --key "$COSIGN_KEY" \ --predicate attestations/build-review-predicate.json \ --type cloudnova-build-review \ "$IMAGE"Verify it.
cosign verify-attestation \ --key keys/cosign.pub \ --type cloudnova-build-review \ "$IMAGE"Task 36 — Associate SBOM Evidence
Section titled “Task 36 — Associate SBOM Evidence”The SBOM should be linked to the exact image digest.
Depending on the approved enterprise workflow, the SBOM may be:
- Stored as an OCI artifact
- Signed as a separate OCI artifact
- Referenced through an attestation
- Stored in an approved evidence repository
- Attached to the CI/CD release record
Create an SBOM attestation using the approved predicate type for your environment.
Example workflow:
cosign attest \ --key "$COSIGN_KEY" \ --predicate attestations/sbom-cyclonedx.json \ --type cyclonedx \ "$IMAGE"Verify:
cosign verify-attestation \ --key keys/cosign.pub \ --type cyclonedx \ "$IMAGE"Validate command behaviour against the installed Cosign version and enterprise policy before production use.
Task 37 — Sign a Separate SBOM OCI Artifact
Section titled “Task 37 — Sign a Separate SBOM OCI Artifact”Where the SBOM is stored as an independent OCI artifact, sign it separately.
Example conceptual reference:
<registry-endpoint>/<repository>-sbom@sha256:<sbom-digest>Sign:
cosign sign \ --key "$COSIGN_KEY" \ "<sbom-oci-reference>"Verify:
cosign verify \ --key keys/cosign.pub \ "<sbom-oci-reference>"This allows both the container image and its SBOM artifact to have independent integrity verification.
Task 38 — Review Registry Signature Artifacts
Section titled “Task 38 — Review Registry Signature Artifacts”Use registry tooling to inspect OCI artifacts associated with the image.
Depending on the platform, review:
- Signature artifacts
- Attestations
- SBOM artifacts
- Manifest references
- Artifact digests
- Creation timestamps
- Push identity
Document:
Image Digest:
Signature Artifact:
Attestation Artifact:
SBOM Artifact:
Registry:
Created Time:
Created By:Task 39 — Compare Signing and Attestation
Section titled “Task 39 — Compare Signing and Attestation”| Control | Purpose |
|---|---|
| Image signature | Proves integrity and association with a signing identity |
| Vulnerability attestation | States the result of a vulnerability assessment |
| Build attestation | Records build and pipeline information |
| SBOM attestation | Associates software inventory with the image |
| Admission policy | Evaluates trust requirements before deployment |
| Runtime monitoring | Detects suspicious behaviour after deployment |
A valid image signature does not automatically validate the truth of every attestation.
The attestation signer and predicate must also be trusted.
Task 40 — Define Trusted Signing Identities
Section titled “Task 40 — Define Trusted Signing Identities”Create:
policies/trusted-identities.mdExample:
Production Human Signers:
- release-security@example.com
Approved CI/CD Identities:
- GitHub Actions release workflow- Enterprise build-service workload identity- Controlled production release pipeline
Approved OIDC Issuers:
- Enterprise identity provider- Approved CI/CD identity provider
Prohibited Identities:
- Personal accounts- Shared accounts- Unmanaged external identities- Development pipelines- Forked repository workflows
Required Verification:
- Exact image digest- Approved certificate identity- Approved OIDC issuer- Approved repository- Required vulnerability attestation- Required SBOM attestationTask 41 — Define Separation of Duties
Section titled “Task 41 — Define Separation of Duties”Create an enterprise responsibility matrix.
| Activity | Developer | CI/CD | Security | Release Manager | Platform |
|---|---|---|---|---|---|
| Commit code | Yes | No | No | No | No |
| Build image | No | Yes | No | No | No |
| Scan image | No | Yes | Review | No | No |
| Generate SBOM | No | Yes | Review | No | No |
| Approve exception | No | No | Yes | Yes | No |
| Sign production image | No | Controlled | Controlled | Approve | No |
| Verify signature | No | Yes | Yes | Yes | Yes |
| Deploy image | No | Controlled | No | Approve | Yes |
| Change admission policy | No | No | Review | No | Yes |
Avoid allowing one uncontrolled identity to:
- Build
- Approve
- Sign
- Deploy
- Change verification policy
Task 42 — Create the Enterprise Signing Policy
Section titled “Task 42 — Create the Enterprise Signing Policy”Create:
policies/enterprise-signing-policy.mdInclude:
Policy Name:CloudNova Container Image Signing Policy
Scope:
Approved Registries:
Approved Repositories:
Approved Signing Methods:
Approved Signing Identities:
Approved OIDC Issuers:
Approved Key Management Systems:
Required Image Digest:
Required Vulnerability Attestation:
Required SBOM Attestation:
Required Build Provenance:
Maximum Signature Age:
Key-Rotation Period:
Certificate Verification Requirements:
Transparency Requirements:
Emergency Exception Process:
Revocation Process:
Incident Response:
Evidence Retention:Task 43 — Define Signing-Key Storage Requirements
Section titled “Task 43 — Define Signing-Key Storage Requirements”Production signing keys should be protected using approved services such as:
- Hardware Security Module
- Cloud Key Management Service
- Enterprise key vault
- Managed signing service
- Isolated release system
Production controls should include:
- Non-exportable private keys where possible
- MFA for key administrators
- Key-use audit logging
- Least-privilege access
- Dual approval
- Rotation
- Revocation
- Backup and recovery
- Incident response
Local files are suitable only for controlled training and development use.
Task 44 — Create a Signing-Key Rotation Procedure
Section titled “Task 44 — Create a Signing-Key Rotation Procedure”Create:
policies/signing-key-rotation.mdInclude:
Current Key Identifier:
Key Owner:
Key Creation Date:
Key Expiration Date:
Rotation Frequency:
New Key Generation Method:
Public Key Distribution:
Policy Update Procedure:
Old Signature Verification Period:
Old Key Revocation:
Compromise Response:
Evidence Retention:
Approval Requirements:Task 45 — Define Signing-Key Compromise Response
Section titled “Task 45 — Define Signing-Key Compromise Response”Create:
policies/signing-incident-response.mdRequired actions:
- Declare a software supply-chain security incident.
- Disable or revoke the compromised signing identity.
- Preserve key-usage logs.
- Identify every image signed by the affected identity.
- Block new deployments using the compromised trust root.
- Evaluate currently running workloads.
- Re-scan and rebuild trusted images.
- Sign approved replacement images with a new identity.
- Update admission policies.
- Notify application and platform owners.
- Document residual risk.
- Conduct a root-cause review.
Task 46 — Create the Kubernetes Namespace
Section titled “Task 46 — Create the Kubernetes Namespace”Create:
kubernetes/namespace.yamlapiVersion: v1kind: Namespacemetadata: name: signed-image-lab labels: environment: training owner: cloud-security pod-security.kubernetes.io/enforce: restricted pod-security.kubernetes.io/audit: restricted pod-security.kubernetes.io/warn: restrictedApply it.
kubectl apply \ -f kubernetes/namespace.yamlVerify:
kubectl get namespace signed-image-lab \ --show-labelsTask 47 — Create the Signed Image Deployment
Section titled “Task 47 — Create the Signed Image Deployment”Create:
kubernetes/signed-deployment.yamlapiVersion: apps/v1kind: Deploymentmetadata: name: signed-application namespace: signed-image-lab labels: app: signed-application environment: training owner: cloud-securityspec: replicas: 2 selector: matchLabels: app: signed-application template: metadata: labels: app: signed-application environment: training spec: automountServiceAccountToken: false securityContext: runAsNonRoot: true runAsUser: 10001 runAsGroup: 10001 fsGroup: 10001 seccompProfile: type: RuntimeDefault containers: - name: application image: <registry-endpoint>/<repository>@sha256:<signed-image-digest> imagePullPolicy: IfNotPresent ports: - name: http containerPort: 5000 securityContext: privileged: false allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: - ALL resources: requests: cpu: 50m memory: 64Mi limits: cpu: 250m memory: 256Mi readinessProbe: httpGet: path: / port: http initialDelaySeconds: 5 periodSeconds: 10 livenessProbe: httpGet: path: / port: http initialDelaySeconds: 15 periodSeconds: 20 volumeMounts: - name: temporary-files mountPath: /tmp volumes: - name: temporary-files emptyDir: {}Add an approved imagePullSecrets configuration only when native registry identity is unavailable.
Task 48 — Verify Before Deployment
Section titled “Task 48 — Verify Before Deployment”Before applying the Deployment, independently verify the image.
cosign verify \ --key keys/cosign.pub \ "$IMAGE"Verify required attestations.
cosign verify-attestation \ --key keys/cosign.pub \ --type vulnerability-scan \ "$IMAGE"cosign verify-attestation \ --key keys/cosign.pub \ --type cyclonedx \ "$IMAGE"Only continue when all required checks pass.
Task 49 — Validate the Kubernetes Manifest
Section titled “Task 49 — Validate the Kubernetes Manifest”kubectl apply \ --dry-run=client \ -f kubernetes/signed-deployment.yamlConfirm:
- Image uses an immutable digest.
- Digest matches the signed image.
- Image exists in the approved registry.
- Service Account token is disabled.
- Pod Security requirements are satisfied.
- Resources and probes are configured.
- Root filesystem is read-only.
- Capabilities are dropped.
Task 50 — Deploy the Signed Image
Section titled “Task 50 — Deploy the Signed Image”Apply the Deployment.
kubectl apply \ -f kubernetes/signed-deployment.yamlMonitor rollout.
kubectl rollout status \ deployment/signed-application \ -n signed-image-labReview Pods.
kubectl get pods \ -n signed-image-lab \ -o wideTask 51 — Validate the Runtime Image Identity
Section titled “Task 51 — Validate the Runtime Image Identity”Retrieve the configured image.
kubectl get pod \ <pod-name> \ -n signed-image-lab \ -o jsonpath='{.spec.containers[*].image}{"\n"}'Retrieve the runtime image ID.
kubectl get pod \ <pod-name> \ -n signed-image-lab \ -o jsonpath='{.status.containerStatuses[*].imageID}{"\n"}'Confirm:
- The image came from the approved registry.
- The configured digest matches the signature.
- The runtime image ID matches the approved digest.
Task 52 — Validate Runtime Hardening
Section titled “Task 52 — Validate Runtime Hardening”Check runtime identity.
kubectl exec \ <pod-name> \ -n signed-image-lab \ -- idReview security status.
kubectl exec \ <pod-name> \ -n signed-image-lab \ -- sh -c "grep -E 'NoNewPrivs|CapEff|Seccomp' /proc/1/status"Attempt to write to a protected path.
kubectl exec \ <pod-name> \ -n signed-image-lab \ -- touch /etc/signature-testExpected:
Read-only file systemTask 53 — Prepare an Unsigned Deployment Test
Section titled “Task 53 — Prepare an Unsigned Deployment Test”Create:
kubernetes/unsigned-deployment.yamlUse an authorised but unsigned training-image digest.
apiVersion: apps/v1kind: Deploymentmetadata: name: unsigned-application namespace: signed-image-labspec: replicas: 1 selector: matchLabels: app: unsigned-application template: metadata: labels: app: unsigned-application spec: automountServiceAccountToken: false securityContext: runAsNonRoot: true seccompProfile: type: RuntimeDefault containers: - name: application image: <registry-endpoint>/<repository>@sha256:<unsigned-image-digest> securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: - ALLDo not deploy the unsigned image into production.
Task 54 — Create an Admission-Policy Design
Section titled “Task 54 — Create an Admission-Policy Design”Create:
kubernetes/cluster-image-policy-example.yamlConceptual Sigstore Policy Controller example:
apiVersion: policy.sigstore.dev/v1beta1kind: ClusterImagePolicymetadata: name: cloudnova-signed-imagesspec: images: - glob: "<registry-endpoint>/<repository>**" authorities: - name: cloudnova-trusted-key key: data: | -----BEGIN PUBLIC KEY----- <PUBLIC-KEY-CONTENT> -----END PUBLIC KEY-----The exact API version and configuration must match the policy-controller version installed in the target cluster.
Do not apply an untested cluster-wide policy directly to production.
Task 55 — Define Admission Requirements
Section titled “Task 55 — Define Admission Requirements”The production admission policy should validate:
- Approved registry
- Approved repository
- Immutable image digest
- Valid image signature
- Approved signing key or identity
- Approved OIDC issuer
- Required vulnerability attestation
- Required SBOM attestation
- Required build provenance
- No prohibited emergency bypass
- Policy audit logging
Expected decisions:
| Image Condition | Admission Decision |
|---|---|
| Signed by approved identity | Allow |
| Signed by unapproved identity | Reject |
| Signature invalid | Reject |
| Image unsigned | Reject |
| Digest differs from signature | Reject |
| Required attestation missing | Reject |
| Registry not approved | Reject |
| Formal emergency exception | Controlled temporary decision |
Task 56 — Test Verification as a CI/CD Gate
Section titled “Task 56 — Test Verification as a CI/CD Gate”Create a verification script.
#!/usr/bin/env bash
set -euo pipefail
IMAGE="${1:?Usage: verify-image.sh <image-by-digest>}"
cosign verify \ --key keys/cosign.pub \ "$IMAGE"
cosign verify-attestation \ --key keys/cosign.pub \ --type vulnerability-scan \ "$IMAGE"
cosign verify-attestation \ --key keys/cosign.pub \ --type cyclonedx \ "$IMAGE"
echo "Image trust verification passed."Save as:
verify-image.shMake it executable.
chmod +x verify-image.shRun:
./verify-image.sh "$IMAGE"Task 57 — Validate CI/CD Failure Behaviour
Section titled “Task 57 — Validate CI/CD Failure Behaviour”Run the verification script against:
- Correct signed image
- Unsigned image
- Image signed by a different key
- Image without required attestation
- Incorrect digest
- Image from an unapproved registry
Record:
| Test | Expected Result | Actual Result |
|---|---|---|
| Approved signed image | Pass | |
| Unsigned image | Fail | |
| Incorrect signing key | Fail | |
| Missing vulnerability attestation | Fail | |
| Missing SBOM attestation | Fail | |
| Incorrect digest | Fail | |
| Unapproved registry | Fail |
Task 58 — Review Signature Revocation Challenges
Section titled “Task 58 — Review Signature Revocation Challenges”Image signatures are attached to immutable artifacts, but trust can change after signing.
Examples:
- Signing key compromised
- Signing identity disabled
- CI/CD pipeline compromised
- Image later found malicious
- New critical vulnerability discovered
- Approval granted incorrectly
- Registry account compromised
Enterprise controls should maintain:
- Denied image digest list
- Revoked signing-key list
- Revoked identity list
- Incident quarantine repository
- Admission-policy updates
- Runtime image inventory
- Emergency workload replacement procedure
Task 59 — Create an Image Denylist Procedure
Section titled “Task 59 — Create an Image Denylist Procedure”Document:
Image Digest:
Registry:
Repository:
Reason for Denial:
Incident ID:
Detection Time:
Affected Clusters:
Affected Workloads:
Signature Identity:
Required Containment:
Replacement Image:
Admission Policy Updated:
Owner:
Status:A previously valid signature must not override a current security decision to block a compromised image.
Task 60 — Perform the Enterprise Image-Trust Assessment
Section titled “Task 60 — Perform the Enterprise Image-Trust Assessment”Complete the assessment.
| Security Domain | Expected Control | Status |
|---|---|---|
| Approved registry | Image stored in trusted registry | |
| Immutable identity | Digest recorded | |
| Vulnerability scan | Passed | |
| Secret scan | Passed | |
| SBOM | Generated | |
| Signing approval | Recorded | |
| Image signature | Present | |
| Signature validity | Verified | |
| Signer identity | Approved | |
| OIDC issuer | Approved | |
| Public key | Trusted | |
| Vulnerability attestation | Verified | |
| SBOM attestation | Verified | |
| Build provenance | Available | |
| Transparency evidence | Reviewed | |
| Key storage | Protected | |
| Key rotation | Documented | |
| Revocation | Documented | |
| Admission enforcement | Designed or enabled | |
| Deployment digest | Matches signed image | |
| Runtime image | Matches approved digest | |
| Evidence | Retained |
Rate each control as:
- Effective
- Partially Effective
- Ineffective
- Not Applicable
Task 61 — Assign the Image-Trust Risk Rating
Section titled “Task 61 — Assign the Image-Trust Risk Rating”Critical Risk
Section titled “Critical Risk”Examples:
- Production image signed by a compromised key
- Malicious image signed and deployed
- Admission verification disabled
- Signing private key exposed
- Image digest does not match approved artifact
- Unauthorised identity trusted for production signing
- Registry signature artifacts tampered with or unavailable
High Risk
Section titled “High Risk”Examples:
- Production image is unsigned
- Signature is not independently verified
- Signer identity is not restricted
- OIDC issuer is not validated
- Shared signing key used by multiple teams
- Required attestation is missing
- Private key stored in source control
- No revocation procedure exists
- Mutable tag signed without digest control
Medium Risk
Section titled “Medium Risk”Examples:
- Key rotation overdue
- SBOM not signed
- Transparency monitoring absent
- Manual verification only
- Incomplete separation of duties
- Signature evidence-retention gap
- No automated denylist process
Low Risk
Section titled “Low Risk”Examples:
- Missing descriptive metadata
- Incomplete ownership label
- Reporting-format inconsistency
- Minor documentation gap
- Non-production policy warning
Task 62 — Create the Image Trust Assessment
Section titled “Task 62 — Create the Image Trust Assessment”Create:
reports/image-trust-assessment.mdInclude:
Assessment Name:Enterprise Container Image Trust Assessment
Assessment Date:
Assessor:
Application:
Business Owner:
Technical Owner:
Registry:
Repository:
Image Tag:
Image Digest:
Build Pipeline:
Source Commit:
Vulnerability Scan:
Secret Scan:
SBOM:
Signing Method:
Signing Identity:
Signing Key Identifier:
OIDC Issuer:
Signature Verification:
Transparency Evidence:
Vulnerability Attestation:
SBOM Attestation:
Build Attestation:
Admission Policy:
Deployment Manifest:
Runtime Image ID:
Critical Findings:
High Findings:
Medium Findings:
Low Findings:
Residual Risk:
Trust Decision:
Trusted
Conditionally Trusted
Untrusted
Requires Further InvestigationTask 63 — Create the Enterprise Signing Security Report
Section titled “Task 63 — Create the Enterprise Signing Security Report”Create:
reports/image-signing-security-report.mdReport Title:Enterprise Container Image Signing and Verification Report
Assessment Date:
Assessor:
Environment:
Application:
Application Owner:
Registry Platform:
Registry Endpoint:
Repository:
Image Reference:
Image Digest:
Image Build ID:
Source Commit:
Security Scan Status:
Critical Vulnerabilities:
High Vulnerabilities:
Secret Findings:
SBOM Format:
SBOM Digest:
Signing Method:
Key-Based
Identity-Based
Signing Identity:
Signing Key Identifier:
Certificate Identity:
OIDC Issuer:
Signing Time:
Signature Verification Result:
Transparency Log Result:
Vulnerability Attestation Result:
SBOM Attestation Result:
Build Attestation Result:
Admission Policy Status:
Kubernetes Deployment Result:
Runtime Image Digest:
Separation of Duties:
Key Protection:
Key Rotation:
Revocation Readiness:
Critical Findings:
High Findings:
Medium Findings:
Low Findings:
Required Remediation:
Residual Risk:
Overall Risk Rating:
Production Decision:
Approved
Conditionally Approved
Rejected
Approvals:
Application Security:
DevSecOps:
Cloud Security:
Kubernetes Security:
Platform Engineering:
Release Manager:Task 64 — Collect Evidence
Section titled “Task 64 — Collect Evidence”Collect evidence for:
- Cosign version
- Installation verification
- Image reference
- Image digest
- Image vulnerability scan
- Image signing approval
- Public signing key
- Private-key protection review
- Signing result
- Signature-verification result
- Incorrect-key verification failure
- Unsigned-image verification failure
- Keyless signing result
- Certificate identity
- OIDC issuer
- Transparency information
- CycloneDX SBOM
- Vulnerability predicate
- Build-review predicate
- Vulnerability attestation
- SBOM attestation
- Attestation verification
- Trusted identity policy
- Key-rotation policy
- Incident-response procedure
- Kubernetes Deployment
- Runtime image ID
- Admission-policy design
- CI/CD gate test
- Enterprise image-trust assessment
- Final signing security report
Suggested filenames:
01-cosign-version.txt02-cosign-installation-verification.txt03-image-reference.txt04-image-digest.txt05-image-scan.json06-signing-approval.md07-public-key.txt08-private-key-protection.md09-signing-result.txt10-signature-verification.json11-incorrect-key-failure.txt12-unsigned-image-failure.txt13-keyless-signing-result.txt14-certificate-identity.txt15-oidc-issuer.txt16-transparency-record.json17-sbom-cyclonedx.json18-vulnerability-predicate.json19-build-review-predicate.json20-vulnerability-attestation.json21-sbom-attestation.json22-attestation-verification.json23-trusted-identities.md24-key-rotation.md25-signing-incident-response.md26-signed-deployment.yaml27-runtime-image-id.txt28-admission-policy-example.yaml29-cicd-gate-results.txt30-image-trust-assessment.md31-image-signing-security-report.mdTask 65 — Clean Up Kubernetes Resources
Section titled “Task 65 — Clean Up Kubernetes Resources”Delete the training namespace.
kubectl delete namespace signed-image-labVerify:
kubectl get namespace signed-image-labExpected:
NotFoundTask 66 — Remove Test Keys
Section titled “Task 66 — Remove Test Keys”Delete only the disposable negative-test keys.
Git Bash
Section titled “Git Bash”rm -rf test-keysPowerShell
Section titled “PowerShell”Remove-Item -Recurse -Force test-keysDo not delete keys required for ongoing verification or evidence.
Task 67 — Secure or Destroy the Training Private Key
Section titled “Task 67 — Secure or Destroy the Training Private Key”When the training key is no longer required:
- Confirm no additional labs depend on it.
- Preserve the public key where required.
- Preserve verification evidence.
- Remove the private key using the approved secure-deletion procedure.
- Document the destruction.
- Do not place the private key in the evidence directory.
Create a destruction record:
Key Identifier:
Key Owner:
Key Location:
Destruction Date:
Destroyed By:
Destruction Method:
Approved By:
Evidence Reference:Enterprise Container Image Signing Checklist
Section titled “Enterprise Container Image Signing Checklist”| Control | Status |
|---|---|
| Image stored in approved registry | ☐ |
| Image referenced by immutable digest | ☐ |
| Image vulnerability scan completed | ☐ |
| Secret scan completed | ☐ |
| Signing approval recorded | ☐ |
| Cosign installation verified | ☐ |
| Private signing key protected | ☐ |
| Private key excluded from Git | ☐ |
| Public key distributed securely | ☐ |
| Image signature created | ☐ |
| Signature verified independently | ☐ |
| Incorrect-key verification tested | ☐ |
| Unsigned-image verification tested | ☐ |
| Approved signing identity defined | ☐ |
| Approved OIDC issuer defined | ☐ |
| Keyless verification tested | ☐ |
| Transparency information reviewed | ☐ |
| CycloneDX SBOM generated | ☐ |
| Vulnerability attestation created | ☐ |
| Vulnerability attestation verified | ☐ |
| SBOM attestation created | ☐ |
| SBOM attestation verified | ☐ |
| Build-review attestation created | ☐ |
| Signing identities documented | ☐ |
| Separation of duties implemented | ☐ |
| Key rotation documented | ☐ |
| Revocation procedure documented | ☐ |
| Signing incident procedure documented | ☐ |
| Kubernetes image uses signed digest | ☐ |
| Runtime image ID validated | ☐ |
| Admission policy prepared | ☐ |
| CI/CD verification gate tested | ☐ |
| Evidence retained | ☐ |
| Security report approved | ☐ |
Remediation Priorities
Section titled “Remediation Priorities”Immediate
Section titled “Immediate”- Revoke exposed signing keys.
- Block images signed by compromised identities.
- Reject unsigned production images.
- Require immutable digest references.
- Remove private keys from source repositories.
- Restrict trusted signing identities.
- Validate the OIDC issuer during verification.
- Preserve evidence relating to suspicious signatures.
Short-Term
Section titled “Short-Term”- Move signing keys into managed key storage.
- Implement automated verification in CI/CD.
- Require vulnerability attestations.
- Require SBOM attestations.
- Define signing-key rotation.
- Implement image-denylist controls.
- Separate build, signing and deployment duties.
- Monitor registry signature events.
Long-Term
Section titled “Long-Term”- Adopt workload-identity-based signing.
- Implement Kubernetes admission enforcement.
- Require build provenance.
- Integrate signature policy with GitOps.
- Monitor transparency records.
- Automate signing-identity revocation.
- Establish multi-cluster trust-policy management.
- Conduct regular software supply-chain incident exercises.
Skills Developed
Section titled “Skills Developed”By completing this lab, you will be able to:
- Explain container-image signing and verification
- Install and validate Cosign
- Identify images by immutable digest
- Generate and protect signing keys
- Sign images using a private key
- Verify images using a trusted public key
- Perform identity-based keyless signing
- Validate certificate identities and OIDC issuers
- Review transparency evidence
- Generate CycloneDX SBOMs
- Create signed attestations
- Verify vulnerability and SBOM attestations
- Test signature-verification failure
- Define trusted signing identities
- Implement separation of duties
- Design signing-key rotation and revocation
- Prepare Kubernetes admission policies
- Build CI/CD signature-verification gates
- Produce enterprise image-trust reports
Knowledge Check
Section titled “Knowledge Check”Question 1
Section titled “Question 1”Why should a container image be signed by digest rather than only by tag?
- A. Digests increase image size.
- B. A digest identifies immutable image content, while a tag can be changed.
- C. Tags automatically encrypt container images.
- D. Digests replace vulnerability scanning.
Answer: B
Question 2
Section titled “Question 2”What must be protected during key-based image signing?
- A. The public key
- B. The private signing key
- C. The image tag
- D. The Kubernetes namespace label
Answer: B
Question 3
Section titled “Question 3”What does signature verification confirm?
- A. The application has no vulnerabilities.
- B. The image matches the signed artifact and the signature was produced by a trusted key or identity.
- C. The Kubernetes cluster is fully secure.
- D. The image does not require runtime monitoring.
Answer: B
Question 4
Section titled “Question 4”Why must keyless verification check the certificate identity?
- A. To ensure the image was signed by the expected person or workload identity
- B. To increase Pod replicas
- C. To create a Kubernetes Secret
- D. To reduce container memory
Answer: A
Question 5
Section titled “Question 5”Why must the OIDC issuer also be verified?
- A. The same identity string could otherwise be accepted from an untrusted identity provider.
- B. The issuer controls container CPU.
- C. The issuer generates the SBOM.
- D. The issuer replaces the registry.
Answer: A
Question 6
Section titled “Question 6”What is the purpose of an attestation?
- A. To record a signed statement about an artifact, such as scan, build or SBOM information
- B. To replace the container image
- C. To create a Kubernetes node
- D. To disable image scanning
Answer: A
Question 7
Section titled “Question 7”Does a valid signature prove that the application is vulnerability-free?
- A. Yes
- B. No, signing confirms integrity and identity but does not guarantee application security.
- C. Yes, when Cosign is used.
- D. Yes, when the registry is private.
Answer: B
Question 8
Section titled “Question 8”What should happen when an image is signed by an unapproved identity?
- A. The image should automatically deploy.
- B. Verification policy should reject the image.
- C. The image should be tagged
latest. - D. The signature should replace the SBOM.
Answer: B
Question 9
Section titled “Question 9”Why should signing and deployment duties be separated?
- A. To prevent a single uncontrolled identity from building, approving, signing and deploying software
- B. To increase registry storage
- C. To disable audit logging
- D. To allow anonymous image pushes
Answer: A
Question 10
Section titled “Question 10”What should happen when a signing key is compromised?
- A. Continue trusting all signatures permanently.
- B. Revoke trust, identify affected images, block unsafe deployments and sign approved replacements using a new trusted identity.
- C. Delete all Kubernetes namespaces without investigation.
- D. Publish the private key for troubleshooting.
Answer: B
Lab Summary
Section titled “Lab Summary”In this lab, you implemented an enterprise container-image signing and verification workflow using Cosign.
You:
- Installed and validated Cosign
- Identified an approved image by immutable digest
- Re-scanned the image before signing
- Defined a signing approval gate
- Generated a training signing-key pair
- Protected the private signing key
- Signed the image using key-based signing
- Verified the signature using the public key
- Tested verification using an incorrect key
- Tested verification of an unsigned image
- Performed identity-based signing where supported
- Verified certificate identity and OIDC issuer
- Reviewed transparency information
- Generated a CycloneDX SBOM
- Created vulnerability and build-review predicates
- Attached signed attestations
- Verified image attestations
- Prepared a signed Kubernetes Deployment
- Designed an admission-policy workflow
- Built a CI/CD verification gate
- Defined trusted signing identities
- Documented key rotation and compromise response
- Produced an enterprise image-trust assessment
Container-image signing establishes a cryptographic trust relationship between:
- The image artifact
- Its immutable digest
- The signing identity
- Associated security evidence
- The deployment decision
A mature image-trust programme combines:
- Secure builds
- Image scanning
- Secret detection
- SBOM generation
- Image signing
- Identity verification
- Build provenance
- Registry governance
- Admission enforcement
- Runtime security
What’s Next?
Section titled “What’s Next?”Next Lab: Lab 05 — Enforce Trusted Images with Admission Policies
In the next lab, you will deploy or configure a Kubernetes admission-policy solution, define trusted image authorities, allow only approved registries, require valid image signatures, verify image attestations, reject unsigned workloads, test policy audit and enforcement modes, implement controlled exceptions, and produce an enterprise admission-security assessment.