Skip to content

Lab 03 — Secure Private Container Registries

Item Details
Lab ID K8S-IMAGE-SECURITY-LAB-03
Difficulty Intermediate to Advanced
Estimated Time 4–6 Hours
Environment Local Workstation, Private Container Registry and Kubernetes Training Cluster
Supported Platforms Amazon ECR, Azure Container Registry, Google Artifact Registry, Harbor or OCI-Compatible Registry
Cost Local Registry Can Be Free / Cloud Registry Charges May Apply
Primary Role Cloud Security Engineer
Supporting Roles DevSecOps Engineer, Kubernetes Security Engineer, Platform Engineer, IAM Engineer
Module Kubernetes Container Image and Supply Chain Security
Previous Lab Lab 02 — Build Minimal and Secure Container Images
Next Lab Lab 04 — Sign and Verify Container Images

CloudNova Technologies currently stores application images across several public and private container registries.

A recent internal security review identified serious governance weaknesses:

  • Developers push images using shared administrator credentials.
  • Production repositories allow mutable image tags.
  • The latest tag is used in deployment manifests.
  • Registry vulnerability scanning is inconsistently enabled.
  • Old and vulnerable images remain indefinitely.
  • Kubernetes clusters use long-lived registry credentials.
  • Repository access is granted at registry-wide scope.
  • Image pull and push events are not centrally monitored.
  • Images are not consistently signed or verified.
  • Registry deletion controls are weak.
  • Repository ownership and data classification are unclear.

During one incident, an existing production tag was overwritten with a different image.

The Kubernetes deployment continued to reference the same tag, making it difficult for responders to determine which image version had actually been running.

CloudNova Technologies has directed the Cloud Security and DevSecOps teams to establish a secure private-container-registry standard.

Your mission is to configure and assess a private registry that supports:

  • Strong identity and access control
  • Separate push and pull permissions
  • Immutable image tags
  • Vulnerability scanning
  • Image retention and lifecycle management
  • Audit logging
  • Encryption
  • Kubernetes authentication
  • Image digest validation
  • Repository governance
  • Secure incident response
  • Future image-signing enforcement

By completing this lab, you will learn how to:

  • Explain the role of a private container registry
  • Design an enterprise registry architecture
  • Create secure repositories
  • Authenticate securely to a registry
  • Separate image-push and image-pull permissions
  • Implement least-privilege registry access
  • Prevent image-tag overwrites
  • Enable vulnerability scanning
  • Review image digests
  • Configure image lifecycle policies
  • Protect production repositories from deletion
  • Integrate a private registry with Kubernetes
  • Avoid long-lived registry credentials
  • Monitor image push, pull and delete events
  • Define repository naming and ownership standards
  • Produce an enterprise registry-security assessment
Developer Workstation
Short-Lived Identity
CI/CD Build Pipeline
┌────────────────┼────────────────┐
│ │ │
Image Build Image Scan SBOM Generation
│ │ │
└────────────────┼────────────────┘
Private Container Registry
┌───────────────┼────────────────┐
│ │ │
Development Staging Production
Repository Repository Repository
│ │ │
Mutable Tags Controlled Immutable Tags
Promotion
Kubernetes Platform
Workload Identity / Pull Role
Approved Image by Digest
Trusted Identity
Least-Privilege Repository Access
Secure Authentication
Vulnerability Scanning
Immutable Image Identity
Image Signing and Verification
Kubernetes Admission Control
Audit Logging and Monitoring

By the end of this lab, you will have:

  • Selected an enterprise registry platform
  • Created development and production repositories
  • Defined repository naming standards
  • Authenticated using approved credentials
  • Pushed a hardened image
  • Recorded its immutable digest
  • Enabled or validated vulnerability scanning
  • Configured tag immutability
  • Defined push and pull access roles
  • Configured retention or lifecycle policies
  • Reviewed audit events
  • Integrated the registry with Kubernetes
  • Deployed an image from the private registry
  • Validated image-pull permissions
  • Tested unauthorised access
  • Produced a registry-security assessment
  • Created an enterprise registry-governance report

Use only registries and cloud accounts that you are authorised to administer.

Do not:

  • Store registry passwords in scripts
  • Commit cloud credentials into Git
  • Use shared administrator accounts
  • Push vulnerable demonstration images into production repositories
  • Disable registry audit logging
  • Expose private repositories publicly
  • Delete production images without approved change control
  • Copy confidential images to public registries
  • Use long-lived credentials when short-lived identity is available

This lab can be completed using one of the following platforms:

Platform Registry Service
AWS Amazon Elastic Container Registry
Microsoft Azure Azure Container Registry
Google Cloud Artifact Registry
Self-Hosted Harbor
Local Training Docker Registry

The main workflow remains the same:

  1. Create a private repository.
  2. Authenticate securely.
  3. Push an approved image.
  4. Scan the image.
  5. record its digest.
  6. Configure access controls.
  7. Prevent tag overwrite.
  8. Apply retention controls.
  9. Integrate with Kubernetes.
  10. Validate logging and monitoring.

Before starting, ensure that you have:

  • Docker Desktop, Docker Engine or Podman
  • A hardened image from Lab 02
  • Trivy installed
  • kubectl installed
  • Access to a Kubernetes training cluster
  • Access to an authorised private registry
  • Cloud CLI installed for your selected platform
  • Permission to create repositories and access roles
  • Visual Studio Code
  • Git Bash or PowerShell
  • Basic understanding of IAM and Kubernetes Secrets

Recommended hardened image:

secure-demo:v2
Tool Purpose
Docker or Podman Tag, push, pull and inspect images
Trivy Scan registry images
kubectl Integrate the registry with Kubernetes
AWS CLI / Azure CLI / gcloud Manage cloud registries
Harbor CLI or Web Interface Manage a self-hosted registry
jq Parse JSON output
Visual Studio Code Create policies and reports
Git Bash / PowerShell Execute commands
lab-03-secure-private-container-registries/
├── registry/
│ ├── repository-standard.md
│ ├── access-control-matrix.md
│ ├── lifecycle-policy.json
│ ├── registry-security-baseline.md
│ └── incident-response-procedure.md
├── kubernetes/
│ ├── namespace.yaml
│ ├── deployment.yaml
│ ├── service.yaml
│ └── image-pull-secret-example.yaml
├── reports/
│ ├── registry-image-scan.json
│ ├── image-inventory.json
│ ├── access-review.md
│ ├── lifecycle-review.md
│ └── registry-security-report.md
└── evidence/
├── registry-details.txt
├── repository-details.txt
├── authentication-method.txt
├── pushed-image-digest.txt
├── scan-summary.txt
├── audit-events.txt
└── kubernetes-deployment-result.txt

Choose one registry platform.

Document:

Registry Platform:
Cloud Provider or Hosting Model:
Region:
Registry Endpoint:
Repository Name:
Business Owner:
Technical Owner:
Data Classification:
Environment:
Authentication Method:
Scanning Capability:
Tag Immutability Capability:
Audit Logging Capability:
Encryption Capability:

Task 02 — Define the Repository Naming Standard

Section titled “Task 02 — Define the Repository Naming Standard”

Create registry/repository-standard.md.

Example naming standard:

<organisation>/<business-unit>/<application>/<component>

Example:

cloudnova/payments/payment-api

Recommended environment separation:

cloudnova-development/payment-api
cloudnova-staging/payment-api
cloudnova-production/payment-api

Repository names should communicate:

  • Organisation
  • Business unit
  • Application
  • Component
  • Environment where applicable
  • Ownership

Avoid names such as:

test
new-app
image1
temporary
latest-app

Task 03 — Define Repository Classification

Section titled “Task 03 — Define Repository Classification”

Classify repositories.

Classification Example Required Controls
Development Feature and test images Scanning and developer access
Staging Release candidates Controlled promotion and scanning
Production Approved release images Immutable tags, restricted push and audit logging
Restricted Regulated or sensitive workloads Enhanced monitoring, encryption and approval
Quarantine Rejected or suspicious images No Kubernetes deployment access

Task 04 — Create the Registry Repository

Section titled “Task 04 — Create the Registry Repository”

Use the commands for your selected platform.

Set variables.

Terminal window
export AWS_REGION=<region>
export REPOSITORY_NAME=cloudnova/payment-api

Create the repository.

Terminal window
aws ecr create-repository \
--repository-name "$REPOSITORY_NAME" \
--region "$AWS_REGION"

Review the repository.

Terminal window
aws ecr describe-repositories \
--repository-names "$REPOSITORY_NAME" \
--region "$AWS_REGION"

Set variables.

Terminal window
RESOURCE_GROUP=<resource-group>
REGISTRY_NAME=<unique-registry-name>
LOCATION=<location>

Create the registry.

Terminal window
az acr create \
--resource-group "$RESOURCE_GROUP" \
--name "$REGISTRY_NAME" \
--sku Standard \
--location "$LOCATION"

Review the registry.

Terminal window
az acr show \
--resource-group "$RESOURCE_GROUP" \
--name "$REGISTRY_NAME"

Set variables.

Terminal window
PROJECT_ID=<project-id>
REGION=<region>
REPOSITORY_NAME=cloudnova-production

Create a Docker repository.

Terminal window
gcloud artifacts repositories create "$REPOSITORY_NAME" \
--repository-format=docker \
--location="$REGION" \
--project="$PROJECT_ID" \
--description="CloudNova production container images"

Review the repository.

Terminal window
gcloud artifacts repositories describe "$REPOSITORY_NAME" \
--location="$REGION" \
--project="$PROJECT_ID"

Start a local registry for training.

Terminal window
docker run -d \
--name cloudnova-registry \
-p 5000:5000 \
registry:2

Verify it.

Terminal window
docker ps

A local unencrypted registry is suitable only for isolated lab use unless TLS and authentication are added.

Save the registry endpoint.

Example:

<account>.dkr.ecr.<region>.amazonaws.com
<registry-name>.azurecr.io
<region>-docker.pkg.dev
localhost:5000

Save evidence.

Terminal window
echo "<registry-endpoint>" \
> evidence/registry-details.txt

Validate whether the registry supports encryption:

  • In transit
  • At rest
  • Customer-managed encryption keys
  • Key rotation
  • Key-access logging

Document:

Control Status
TLS enforced
Images encrypted at rest
Customer-managed key required
Key rotation enabled
Key access monitored

For production registries, insecure HTTP access should not be permitted.

Task 07 — Define the Registry Access Model

Section titled “Task 07 — Define the Registry Access Model”

Create registry/access-control-matrix.md.

Role Pull Push Delete Change Policy View Scan Results
Developer Yes Development only No No Yes
CI Build Role Yes Yes No No Yes
Release Role Yes Production promotion No No Yes
Kubernetes Pull Role Yes No No No No
Security Analyst Yes No No No Yes
Registry Administrator Yes Yes Controlled Yes Yes

Apply:

  • Least privilege
  • Separation of duties
  • Short-lived identity
  • Repository-level scoping
  • No shared credentials
  • No direct production push from developer accounts

Task 08 — Review Existing Registry Identity

Section titled “Task 08 — Review Existing Registry Identity”

For the selected cloud platform, identify the current principal.

Terminal window
aws sts get-caller-identity
Terminal window
az account show
Terminal window
gcloud auth list

Record:

  • Principal
  • Account or subscription
  • Project
  • Role
  • Authentication type
  • Whether MFA or federated access is used

Task 09 — Authenticate to the Registry Securely

Section titled “Task 09 — Authenticate to the Registry Securely”
Terminal window
aws ecr get-login-password \
--region "$AWS_REGION" \
| docker login \
--username AWS \
--password-stdin \
<account-id>.dkr.ecr.<region>.amazonaws.com
Terminal window
az acr login \
--name "$REGISTRY_NAME"
Terminal window
gcloud auth configure-docker \
<region>-docker.pkg.dev

No authentication is configured by default.

For enterprise use, configure:

  • TLS
  • Authentication
  • Authorisation
  • Audit logs

Task 10 — Verify That Credentials Are Not Exposed

Section titled “Task 10 — Verify That Credentials Are Not Exposed”

Review shell history carefully.

Do not use commands such as:

Terminal window
docker login \
--username admin \
--password my-secret-password

Preferred methods include:

  • Password through standard input
  • Workload identity
  • Cloud CLI credential helper
  • Short-lived token
  • Federated identity
  • Managed identity

Check Docker credential storage.

Terminal window
cat ~/.docker/config.json

Do not include credential values in lab reports.

Verify the hardened image from Lab 02.

Terminal window
docker images secure-demo

Tag it for the registry.

Generic example:

Terminal window
docker tag \
secure-demo:v2 \
<registry-endpoint>/<repository>:1.0.0

Amazon ECR example:

Terminal window
docker tag \
secure-demo:v2 \
<account-id>.dkr.ecr.<region>.amazonaws.com/cloudnova/payment-api:1.0.0

Azure example:

Terminal window
docker tag \
secure-demo:v2 \
<registry-name>.azurecr.io/cloudnova/payment-api:1.0.0

Google example:

Terminal window
docker tag \
secure-demo:v2 \
<region>-docker.pkg.dev/<project-id>/cloudnova-production/payment-api:1.0.0

Inspect the image.

Terminal window
docker image inspect secure-demo:v2

Scan it again.

Terminal window
trivy image \
--severity HIGH,CRITICAL \
secure-demo:v2

Confirm:

  • Image came from the approved build.
  • No embedded credentials were found.
  • Critical findings have been reviewed.
  • The image runs as a non-root user.
  • The image has an approved version tag.
  • The image is ready for registry upload.

Push the tagged image.

Terminal window
docker push \
<registry-endpoint>/<repository>:1.0.0

Observe:

  • Layer upload
  • Existing-layer reuse
  • Manifest upload
  • Image digest

Save the command output where practical.

Terminal window
docker push \
<registry-endpoint>/<repository>:1.0.0 \
> evidence/image-push-result.txt 2>&1

Task 14 — Verify the Registry Image Inventory

Section titled “Task 14 — Verify the Registry Image Inventory”
Terminal window
aws ecr describe-images \
--repository-name "$REPOSITORY_NAME" \
--region "$AWS_REGION"
Terminal window
az acr repository show-tags \
--name "$REGISTRY_NAME" \
--repository cloudnova/payment-api \
--detail
Terminal window
gcloud artifacts docker images list \
<region>-docker.pkg.dev/<project-id>/<repository> \
--include-tags
Terminal window
curl http://localhost:5000/v2/_catalog

Task 15 — Record the Immutable Image Digest

Section titled “Task 15 — Record the Immutable Image Digest”

Retrieve the digest.

Terminal window
docker image inspect \
<registry-endpoint>/<repository>:1.0.0 \
--format='{{json .RepoDigests}}'

Alternatively, retrieve it from the registry.

Record:

Repository:
Tag:
Digest:
Push Time:
Pushed By:
Source Build:
Scan Status:

Save the digest.

Terminal window
echo "<registry-endpoint>/<repository>@sha256:<digest>" \
> evidence/pushed-image-digest.txt

Remove the local tagged copy where safe.

Terminal window
docker image rm \
<registry-endpoint>/<repository>:1.0.0

Pull the image by digest.

Terminal window
docker pull \
<registry-endpoint>/<repository>@sha256:<digest>

Confirm that the immutable artifact can be retrieved.

Configure the registry to scan images during or after push.

Terminal window
aws ecr put-image-scanning-configuration \
--repository-name "$REPOSITORY_NAME" \
--image-scanning-configuration scanOnPush=true \
--region "$AWS_REGION"

Start a manual scan where required.

Terminal window
aws ecr start-image-scan \
--repository-name "$REPOSITORY_NAME" \
--image-id imageTag=1.0.0 \
--region "$AWS_REGION"

Use the security capabilities available in the configured Azure environment.

Validate integration with:

  • Microsoft Defender for Cloud
  • Registry vulnerability assessment
  • Central security findings

Validate integration with:

  • Artifact Analysis
  • Vulnerability scanning
  • Container Analysis findings

Enable a scanner such as Trivy and configure scan-on-push.

Review:

  • Scan completion status
  • Critical findings
  • High findings
  • Package name
  • Installed version
  • Fixed version
  • Image digest
  • Scan timestamp

Create a summary.

Image:
Digest:
Scanner:
Scan Time:
Critical Findings:
High Findings:
Medium Findings:
Low Findings:
Fixed Findings:
Unfixed Findings:
Deployment Decision:

Save results to:

reports/registry-image-scan.json

Task 19 — Compare Local and Registry Scan Results

Section titled “Task 19 — Compare Local and Registry Scan Results”

Compare:

Field Local Scan Registry Scan
Image digest
Scanner
Database date
Critical
High
Medium
Fixed versions
Overall result

Differences may occur because:

  • Scanner databases differ.
  • Scan times differ.
  • Severity sources differ.
  • Registry scanning uses a different engine.
  • Package detection methods differ.

Do not assume one scanner is automatically authoritative for all findings.

Task 20 — Configure Immutable Image Tags

Section titled “Task 20 — Configure Immutable Image Tags”

Production repositories should prevent existing tags from being overwritten.

Terminal window
aws ecr put-image-tag-mutability \
--repository-name "$REPOSITORY_NAME" \
--image-tag-mutability IMMUTABLE \
--region "$AWS_REGION"

Validate.

Terminal window
aws ecr describe-repositories \
--repository-names "$REPOSITORY_NAME" \
--region "$AWS_REGION"

Use repository and manifest controls to protect approved images and release tags.

Validate the selected platform’s controls for:

  • Tag locking
  • Manifest locking
  • Delete protection
  • Write restrictions

Use repository permissions and release governance to prevent unauthorised overwrites.

Enable tag immutability rules for production repositories.

Build or retag a different image using the existing tag.

Terminal window
docker tag \
alpine:3.20 \
<registry-endpoint>/<repository>:1.0.0

Attempt to push it.

Terminal window
docker push \
<registry-endpoint>/<repository>:1.0.0

Expected result:

Push rejected because the tag is immutable

Do not perform this test against an uncontrolled production repository.

Record the result.

Tag:
Original Digest:
Replacement Digest:
Push Result:
Immutability Control:

Task 22 — Define the Image-Tagging Standard

Section titled “Task 22 — Define the Image-Tagging Standard”

Create a tagging policy.

Approved examples:

1.0.0
1.0.1
2026.07.30
build-1042
git-a1b2c3d
release-2026-07

Avoid production use of:

latest
new
final
final2
test
working

Recommended production reference:

<registry>/<repository>@sha256:<digest>

Task 23 — Configure Repository-Level Access

Section titled “Task 23 — Configure Repository-Level Access”

Restrict access to the specific repository.

The CI/CD role should have only the permissions needed to:

  • Authenticate
  • Upload layers
  • Push manifests
  • Read scan status

The Kubernetes runtime identity should have only the permissions needed to:

  • Authenticate
  • Download layers
  • Pull manifests

It should not be able to:

  • Push images
  • Delete images
  • Change repository policies
  • Disable scanning
  • Change immutability
  • View unrelated repositories

Task 24 — Create an Access-Control Assessment

Section titled “Task 24 — Create an Access-Control Assessment”

Complete the matrix.

Identity Repository Required Access Actual Access Risk
Developer Development Push and pull
CI/CD Build Role Build repository Push and pull
Release Role Production Controlled push
Kubernetes Role Production Pull only
Security Analyst All approved Read and scan
Registry Administrator Registry management Administrative

Identify:

  • Excess permissions
  • Shared accounts
  • Permanent credentials
  • Cross-environment access
  • Registry-wide access
  • Missing separation of duties

Use a pull-only identity where available.

Attempt to push an image.

Terminal window
docker push \
<registry-endpoint>/<repository>:unauthorised-test

Expected:

Access denied

Record:

Test Identity:
Repository:
Attempted Action:
Expected Result:
Actual Result:
Control Effective:

Task 26 — Test Unauthorised Delete Access

Section titled “Task 26 — Test Unauthorised Delete Access”

Using a non-administrative identity, attempt an authorised safe test against a non-production image.

Expected:

Delete operation denied

Do not delete the approved production image.

Confirm that pull-only and push-only identities cannot delete images.

Create registry/lifecycle-policy.json.

Example lifecycle objectives:

  • Retain all production release images.
  • Retain the latest 20 development images.
  • Delete untagged development images after 14 days.
  • Retain images referenced by active deployments.
  • Preserve images associated with incidents.
  • Preserve images under legal hold.
  • Prevent deletion of signed production releases.

Example conceptual policy:

{
"rules": [
{
"priority": 1,
"description": "Remove old untagged development images",
"match": {
"tagStatus": "untagged",
"olderThanDays": 14
},
"action": "expire"
},
{
"priority": 2,
"description": "Retain the latest development builds",
"match": {
"tagPrefix": "dev-",
"retainCount": 20
},
"action": "retain"
},
{
"priority": 3,
"description": "Retain production releases",
"match": {
"tagPrefix": "release-"
},
"action": "retain"
}
]
}

Adapt the syntax to the selected registry platform.

Lifecycle policies must not delete:

  • Images used by active Kubernetes workloads
  • Images required for rollback
  • Images associated with open incidents
  • Images required for audits
  • Legally retained images
  • Signed production artifacts
  • Images referenced by disaster-recovery procedures

Document the rollback-retention period.

Example:

Production Image Retention: 365 days
Staging Image Retention: 90 days
Development Image Retention: 30 days
Untagged Image Retention: 14 days

Where supported, configure:

  • Repository deletion protection
  • Manifest locking
  • Retention policies
  • Restricted delete permissions
  • Multi-party approval
  • Backup or replication
  • Alerting on delete actions

Confirm that only authorised registry administrators can remove production images.

Identify the audit-log source.

Possible sources:

  • AWS CloudTrail
  • Azure Activity Log
  • Google Cloud Audit Logs
  • Harbor audit logs
  • SIEM-integrated registry logs

Review events for:

  • Repository creation
  • Repository deletion
  • Image push
  • Image pull
  • Image delete
  • Policy modification
  • Tag immutability change
  • Scan configuration change
  • Failed authentication
  • Access denied
  • Administrative login

Task 31 — Create an Audit-Event Baseline

Section titled “Task 31 — Create an Audit-Event Baseline”

Document expected registry activities.

Activity Expected Identity Expected Source Alert Priority
Development image push CI/CD role Build network Low
Production release push Release role Controlled pipeline Medium
Kubernetes image pull Cluster identity Cluster network Low
Repository deletion Registry administrator Admin network Critical
Immutability disabled Registry administrator Admin network Critical
Public access enabled None Any Critical
Failed administrator login Administrator Approved network High
Image delete Approved cleanup role Automation High

Task 32 — Search for Suspicious Registry Events

Section titled “Task 32 — Search for Suspicious Registry Events”

Review for:

  • Push from an unknown identity
  • Push outside deployment windows
  • Tag overwrite attempts
  • Repeated authentication failures
  • Image deletion
  • Registry-policy changes
  • Scan-on-push disabled
  • Unusual pull volume
  • Pull from unknown regions
  • Cross-account access
  • Public-access changes

Save relevant evidence.

evidence/audit-events.txt

Task 33 — Define Registry Security Alerts

Section titled “Task 33 — Define Registry Security Alerts”

Create alerts for:

  • Repository made public
  • Production tag overwrite attempt
  • Production image deletion
  • Immutability disabled
  • Vulnerability scanning disabled
  • Critical vulnerability detected
  • Administrator access from unknown source
  • Repeated failed login attempts
  • Unsigned image pushed
  • Image pulled from a restricted repository
  • Unexpected cross-account access

Task 34 — Create the Kubernetes Namespace

Section titled “Task 34 — Create the Kubernetes Namespace”

Create kubernetes/namespace.yaml.

apiVersion: v1
kind: Namespace
metadata:
name: registry-security-lab
labels:
environment: training
owner: cloud-security
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io-audit: restricted
pod-security.kubernetes.io-warn: restricted

Apply it.

Terminal window
kubectl apply -f kubernetes/namespace.yaml

Verify.

Terminal window
kubectl get namespace registry-security-lab \
--show-labels

Task 35 — Select the Kubernetes Registry Authentication Method

Section titled “Task 35 — Select the Kubernetes Registry Authentication Method”

Preferred authentication order:

  1. Kubernetes workload identity or node identity
  2. Managed identity
  3. Cloud-provider registry integration
  4. Short-lived registry token
  5. Kubernetes image-pull Secret
  6. Long-lived static credential only as a last resort

Document:

Authentication Method:
Credential Lifetime:
Identity:
Repository Scope:
Rotation Method:
Secret Storage:
Audit Source:

Task 36 — Create an Image-Pull Secret Where Required

Section titled “Task 36 — Create an Image-Pull Secret Where Required”

Use this task only when workload identity or native cloud integration is unavailable.

Create the Secret without writing the password into a manifest.

Terminal window
kubectl create secret docker-registry registry-credentials \
--namespace registry-security-lab \
--docker-server=<registry-endpoint> \
--docker-username=<username> \
--docker-password=<temporary-token> \
--docker-email=<email>

Review metadata only.

Terminal window
kubectl get secret registry-credentials \
-n registry-security-lab

Do not print or decode the Secret value in screenshots or reports.

Task 37 — Inspect the Image-Pull Secret Safely

Section titled “Task 37 — Inspect the Image-Pull Secret Safely”

Review only the Secret type and metadata.

Terminal window
kubectl get secret registry-credentials \
-n registry-security-lab \
-o jsonpath='{.type}{"\n"}'

Expected:

kubernetes.io/dockerconfigjson

Validate:

  • Secret exists only in the required namespace.
  • Access is limited through RBAC.
  • The credential is short-lived.
  • Rotation is documented.
  • The Secret is not stored in Git.

Create kubernetes/deployment.yaml.

apiVersion: apps/v1
kind: Deployment
metadata:
name: registry-demo
namespace: registry-security-lab
labels:
app: registry-demo
environment: training
owner: cloud-security
spec:
replicas: 2
selector:
matchLabels:
app: registry-demo
template:
metadata:
labels:
app: registry-demo
environment: training
spec:
automountServiceAccountToken: false
imagePullSecrets:
- name: registry-credentials
securityContext:
runAsNonRoot: true
runAsUser: 10001
runAsGroup: 10001
fsGroup: 10001
seccompProfile:
type: RuntimeDefault
containers:
- name: application
image: <registry-endpoint>/<repository>@sha256:<approved-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: {}

Remove the imagePullSecrets section when using native cloud or workload identity integration.

Task 39 — Validate the Deployment Manifest

Section titled “Task 39 — Validate the Deployment Manifest”

Perform a client-side validation.

Terminal window
kubectl apply \
--dry-run=client \
-f kubernetes/deployment.yaml

Review:

  • Image is referenced by digest.
  • No latest tag is used.
  • Service Account token is disabled.
  • Container runs as non-root.
  • Root filesystem is read-only.
  • Linux capabilities are dropped.
  • Resources are configured.
  • Health probes are present.

Task 40 — Deploy the Private Registry Image

Section titled “Task 40 — Deploy the Private Registry Image”

Apply the Deployment.

Terminal window
kubectl apply \
-f kubernetes/deployment.yaml

Monitor rollout.

Terminal window
kubectl rollout status \
deployment/registry-demo \
-n registry-security-lab

Review Pods.

Terminal window
kubectl get pods \
-n registry-security-lab \
-o wide

Task 41 — Investigate Image-Pull Failure

Section titled “Task 41 — Investigate Image-Pull Failure”

If the Pod reports ImagePullBackOff, review it.

Terminal window
kubectl describe pod \
<pod-name> \
-n registry-security-lab

Common causes include:

  • Invalid registry endpoint
  • Incorrect repository name
  • Missing pull permission
  • Expired token
  • Incorrect image digest
  • Missing image-pull Secret
  • Registry network restriction
  • TLS trust failure
  • Architecture mismatch
  • Image does not exist

Review events.

Terminal window
kubectl get events \
-n registry-security-lab \
--sort-by=.metadata.creationTimestamp

Task 42 — Verify the Running Image Digest

Section titled “Task 42 — Verify the Running Image Digest”

Review the configured image.

Terminal window
kubectl get pod \
<pod-name> \
-n registry-security-lab \
-o jsonpath='{.spec.containers[*].image}{"\n"}'

Review the runtime image ID.

Terminal window
kubectl get pod \
<pod-name> \
-n registry-security-lab \
-o jsonpath='{.status.containerStatuses[*].imageID}{"\n"}'

Confirm that:

  • The configured digest is approved.
  • The runtime image ID matches the approved artifact.
  • The image came from the private registry.

Check runtime identity.

Terminal window
kubectl exec \
<pod-name> \
-n registry-security-lab \
-- id

Expected:

uid=10001

Review privilege settings.

Terminal window
kubectl exec \
<pod-name> \
-n registry-security-lab \
-- sh -c "grep -E 'NoNewPrivs|CapEff|Seccomp' /proc/1/status"

Attempt to modify a protected path.

Terminal window
kubectl exec \
<pod-name> \
-n registry-security-lab \
-- touch /etc/registry-test

Expected:

Read-only file system

Confirm that the Kubernetes identity can:

  • Authenticate to the registry
  • Pull the approved image
  • Download image layers

Confirm that it cannot:

  • Push a new image
  • Delete an image
  • Change repository settings
  • Disable scanning
  • Modify tag immutability

Document the validation.

Task 45 — Simulate an Invalid Image Reference

Section titled “Task 45 — Simulate an Invalid Image Reference”

Create a temporary test using a non-existent tag.

image: <registry-endpoint>/<repository>:does-not-exist

Apply only in the training namespace.

Review the resulting event.

Expected:

ImagePullBackOff

Restore the approved digest after validation.

Task 46 — Review Kubernetes Secret Exposure Risk

Section titled “Task 46 — Review Kubernetes Secret Exposure Risk”

Where an image-pull Secret is used, assess:

  • Who can read Secrets in the namespace?
  • Can developers create Pods referencing the Secret?
  • Is the credential registry-wide?
  • Can the credential push or delete images?
  • Is it rotated?
  • Is it stored in CI/CD logs?
  • Is it synchronised from an external secret store?
  • Is encryption at rest enabled for Kubernetes Secrets?

Create an access review.

Terminal window
kubectl auth can-i get secrets \
-n registry-security-lab

Test a specific identity where authorised.

Terminal window
kubectl auth can-i get secrets \
--as=<user-or-service-account> \
-n registry-security-lab

Task 47 — Review Registry Network Security

Section titled “Task 47 — Review Registry Network Security”

Assess:

  • Private endpoint availability
  • Firewall rules
  • Approved source networks
  • Internet exposure
  • Kubernetes cluster connectivity
  • CI/CD connectivity
  • DNS configuration
  • TLS certificate validation
  • Cross-region or cross-account access

Complete:

Network Control Status
Registry uses TLS
Public access restricted
Private endpoint available
CI/CD source restricted
Kubernetes source restricted
Administrative access restricted
DNS resolution validated
Network logs retained

Task 48 — Review Cross-Account or Cross-Project Access

Section titled “Task 48 — Review Cross-Account or Cross-Project Access”

Where multiple cloud accounts, subscriptions or projects are used, review:

  • Trusted principals
  • Repository resource policies
  • External identities
  • Organisation boundaries
  • Environment separation
  • Production pull access
  • Third-party access
  • Expiry dates

External access must be:

  • Explicit
  • Time-bound
  • Repository-scoped
  • Audited
  • Approved by the repository owner

Task 49 — Create the Registry Incident Response Procedure

Section titled “Task 49 — Create the Registry Incident Response Procedure”

Create registry/incident-response-procedure.md.

Include procedures for:

  • Suspected malicious image
  • Compromised registry credential
  • Unauthorised image push
  • Production tag overwrite attempt
  • Image deletion
  • Public exposure
  • Critical vulnerability discovery
  • Compromised CI/CD pipeline
  • Image-signature failure

Example response workflow:

Detect
Identify Image Digest
Block Deployment
Disable Push Identity
Preserve Audit Evidence
Identify Affected Clusters
Replace or Roll Back Workloads
Rebuild and Re-Scan Image
Document Root Cause

Task 50 — Define Image Quarantine Controls

Section titled “Task 50 — Define Image Quarantine Controls”

A suspicious image should be:

  • Tagged or classified as quarantined
  • Removed from deployment allowlists
  • Blocked by admission policy
  • Preserved for investigation
  • Restricted from standard developers
  • Scanned again
  • Analysed by the security team
  • Referenced by immutable digest

Do not immediately delete suspicious images before preserving required evidence.

Task 51 — Create the Registry Security Baseline

Section titled “Task 51 — Create the Registry Security Baseline”

Create registry/registry-security-baseline.md.

Minimum controls:

Private Access:
TLS Enforced:
Encryption at Rest:
Repository-Level IAM:
Separate Push and Pull Identities:
Short-Lived Authentication:
MFA for Administrators:
Tag Immutability:
Vulnerability Scanning:
SBOM Retention:
Image Signing:
Lifecycle Policy:
Delete Protection:
Audit Logging:
SIEM Integration:
Production Digest Pinning:
Incident Response Procedure:

Task 52 — Perform the Enterprise Registry Assessment

Section titled “Task 52 — Perform the Enterprise Registry Assessment”

Complete the assessment.

Security Domain Expected Control Status
Registry ownership Business and technical owners assigned
Repository classification Environment and data class documented
Private access Public access disabled
Authentication Short-lived or managed identity
Authorisation Repository-level least privilege
Push access CI/CD and release roles only
Pull access Kubernetes identity only
Administrator access MFA and restricted
Encryption In transit and at rest
Tag immutability Enabled for production
Vulnerability scanning Enabled
Digest recording Required
Image retention Lifecycle policy configured
Delete protection Production images protected
Audit logging Enabled
SIEM monitoring Registry events integrated
Kubernetes integration Secure pull mechanism
Secret exposure No long-lived credentials
Incident response Procedure documented
Image signing Planned or implemented

Rate each area as:

  • Effective
  • Partially Effective
  • Ineffective
  • Not Applicable

Task 53 — Assign the Registry Risk Rating

Section titled “Task 53 — Assign the Registry Risk Rating”

Use the following model.

Examples:

  • Production repository is publicly writable
  • Registry administrator credentials exposed
  • Malicious image pushed to production
  • Image integrity cannot be established
  • Production image deleted without recovery option
  • Kubernetes pull identity can push or delete images

Examples:

  • Mutable production tags
  • Shared administrator credentials
  • Vulnerability scanning disabled
  • Public pull access to confidential images
  • Long-lived registry credentials
  • Missing audit logging
  • Registry-wide push access
  • Unsupported registry platform

Examples:

  • Missing lifecycle policy
  • Excessive image retention
  • No private endpoint
  • SBOMs not retained
  • Incomplete alerting
  • Weak repository naming
  • Manual access reviews

Examples:

  • Missing descriptive metadata
  • Documentation gap
  • Inconsistent labels
  • Minor retention-policy improvement

Task 54 — Create the Enterprise Registry Security Report

Section titled “Task 54 — Create the Enterprise Registry Security Report”

Create reports/registry-security-report.md.

Assessment Title:
Enterprise Private Container Registry Security Assessment
Assessment Date:
Assessor:
Registry Platform:
Registry Endpoint:
Region:
Cloud Account / Subscription / Project:
Repository:
Environment:
Business Owner:
Technical Owner:
Data Classification:
Authentication Method:
Administrator Controls:
Repository Access Model:
Developer Permissions:
CI/CD Permissions:
Kubernetes Pull Permissions:
Encryption in Transit:
Encryption at Rest:
Customer-Managed Key:
Tag Immutability:
Vulnerability Scanning:
Latest Scan Date:
Critical Findings:
High Findings:
Image Digest:
SBOM Status:
Image Signing Status:
Lifecycle Policy:
Delete Protection:
Audit Logging:
SIEM Integration:
Private Network Access:
Kubernetes Integration:
Credential Rotation:
Incident Response Readiness:
Critical Risks:
High Risks:
Medium Risks:
Low Risks:
Required Remediation:
Residual Risk:
Overall Risk Rating:
Production Decision:
Approved
Conditionally Approved
Rejected
Approvals:
Cloud Security:
DevSecOps:
Platform Engineering:
Application Owner:

Collect evidence for:

  • Registry creation
  • Repository configuration
  • Registry endpoint
  • Encryption settings
  • Access-control policy
  • Current authenticated identity
  • Authentication method
  • Image tag
  • Image digest
  • Image-push result
  • Vulnerability scan
  • Tag-immutability configuration
  • Immutability test
  • Lifecycle policy
  • Delete-protection configuration
  • Audit events
  • Kubernetes image-pull configuration
  • Kubernetes Deployment
  • Runtime image ID
  • Access-denied tests
  • Final registry assessment
  • Registry security report

Suggested filenames:

01-registry-details.txt
02-repository-details.json
03-encryption-settings.txt
04-access-control-matrix.md
05-authenticated-identity.txt
06-authentication-method.txt
07-image-tag.txt
08-image-digest.txt
09-image-push-result.txt
10-vulnerability-scan.json
11-tag-immutability.txt
12-immutability-test.txt
13-lifecycle-policy.json
14-delete-protection.txt
15-audit-events.txt
16-kubernetes-pull-method.txt
17-kubernetes-deployment.yaml
18-runtime-image-id.txt
19-access-denied-tests.txt
20-registry-assessment.md
21-registry-security-report.md

Delete the training namespace.

Terminal window
kubectl delete namespace registry-security-lab

Verify.

Terminal window
kubectl get namespace registry-security-lab

Expected:

NotFound

Task 57 — Remove Local Registry Credentials

Section titled “Task 57 — Remove Local Registry Credentials”

Log out where required.

Terminal window
docker logout <registry-endpoint>

Review local Docker configuration.

Terminal window
cat ~/.docker/config.json

Do not delete credential-helper configuration required for other authorised workloads.

Do not delete the repository when it is part of an ongoing learning environment or shared platform.

For temporary lab repositories:

  • Confirm no active workloads use the image.
  • Preserve required evidence.
  • Retain the approved report.
  • Remove temporary images.
  • Delete temporary access roles.
  • Remove short-lived Secrets.
  • Delete the repository only with authorisation.

For the local Docker Registry:

Terminal window
docker stop cloudnova-registry
Terminal window
docker rm cloudnova-registry

Enterprise Private Registry Security Checklist

Section titled “Enterprise Private Registry Security Checklist”
Control Status
Registry is privately accessible
TLS is enforced
Images are encrypted at rest
Repository ownership is documented
Environment repositories are separated
Repository naming standard is applied
Administrator access uses MFA
Shared credentials are prohibited
Short-lived authentication is used
Push and pull permissions are separated
Repository-level least privilege is enforced
Developers cannot push directly to production
Kubernetes identity has pull-only access
Production tags are immutable
Production images are pinned by digest
Vulnerability scanning is enabled
Critical findings block deployment
SBOM is generated and retained
Image-signing capability is planned
Lifecycle policy is configured
Rollback images are retained
Production deletion is protected
Registry audit logging is enabled
Security events are sent to the SIEM
Suspicious images can be quarantined
Incident-response procedure is documented
Access reviews are performed regularly
Evidence is retained
Security report is approved
  • Disable public write access.
  • Revoke exposed registry credentials.
  • Remove shared administrator accounts.
  • Enable tag immutability for production.
  • Enable vulnerability scanning.
  • Restrict Kubernetes identities to pull-only access.
  • Preserve evidence for suspicious image activity.
  • Block malicious or untrusted image digests.
  • Separate development and production repositories.
  • Implement repository-level IAM.
  • Replace long-lived credentials with managed identity.
  • Enable central audit logging.
  • Configure lifecycle and retention policies.
  • Add production deletion controls.
  • Deploy registry security alerts.
  • Require immutable digest references.
  • Implement image signing.
  • Enforce signature verification through admission control.
  • Generate and retain SBOMs.
  • Implement build provenance.
  • Use private endpoints.
  • Automate access reviews.
  • Integrate registry findings with vulnerability management.
  • Establish cross-region replication and recovery.
  • Implement automated image quarantine.

By completing this lab, you will be able to:

  • Design an enterprise private-registry architecture
  • Create and secure container repositories
  • Authenticate securely to private registries
  • Tag and push hardened images
  • Retrieve immutable image digests
  • Enable registry vulnerability scanning
  • Configure production tag immutability
  • Separate registry push and pull permissions
  • Apply repository-level least privilege
  • Configure lifecycle and retention controls
  • Review registry audit logs
  • Integrate private registries with Kubernetes
  • Troubleshoot image-pull failures
  • Validate runtime image identity
  • Assess registry network security
  • Develop registry incident-response procedures
  • Produce enterprise registry-security reports

Why should production image tags be immutable?

  • A. To increase container memory
  • B. To prevent an existing release tag from being overwritten with different image content
  • C. To disable vulnerability scanning
  • D. To allow every developer to push images

Answer: B

Why should Kubernetes use a pull-only registry identity?

  • A. Kubernetes must be able to delete old images.
  • B. Kubernetes generally requires only permission to retrieve approved images.
  • C. Pull-only access allows the cluster to change registry policies.
  • D. Pull-only access automatically signs images.

Answer: B

Why is an image digest safer than a mutable tag?

  • A. A digest identifies immutable image content.
  • B. A digest creates a registry administrator.
  • C. A digest removes all vulnerabilities.
  • D. A digest disables image layers.

Answer: A

What is the preferred authentication method for a cloud registry?

  • A. Shared administrator password
  • B. Long-lived password stored in Git
  • C. Managed identity, workload identity or short-lived token
  • D. Public anonymous access

Answer: C

What should happen when a registry detects a critical exploitable vulnerability?

  • A. The image should automatically be promoted to production.
  • B. Deployment should be blocked until the vulnerability is remediated or formally risk accepted.
  • C. The vulnerability report should be deleted.
  • D. The image should be renamed latest.

Answer: B

Why should registry push and pull permissions be separated?

  • A. To ensure workload identities cannot modify or delete registry content
  • B. To increase image size
  • C. To disable audit logging
  • D. To create public repositories

Answer: A

What is a major risk of storing a registry credential in a Kubernetes Secret?

  • A. The image becomes smaller.
  • B. Users with permission to read the Secret may obtain registry access.
  • C. The registry automatically becomes immutable.
  • D. Kubernetes disables networking.

Answer: B

Why are lifecycle policies required?

  • A. To retain every image forever
  • B. To remove obsolete images while preserving production, rollback, audit and incident artifacts
  • C. To replace image scanning
  • D. To disable image digests

Answer: B

Which registry event should normally generate a critical alert?

  • A. An approved development image pull
  • B. A production repository being made public
  • C. A successful vulnerability scan
  • D. A normal Kubernetes image pull

Answer: B

Does a secure private registry replace Kubernetes workload hardening?

  • A. Yes
  • B. No, registry security protects image storage and distribution, while Kubernetes workload hardening protects deployed containers.
  • C. Yes, when immutable tags are enabled.
  • D. Yes, when the registry is private.

Answer: B

In this lab, you implemented and assessed the core controls required to secure an enterprise private container registry.

You:

  • Selected a registry platform
  • Created a private repository
  • Defined repository naming and classification standards
  • Authenticated using an approved mechanism
  • Tagged and pushed a hardened image
  • Recorded the immutable image digest
  • Enabled or validated vulnerability scanning
  • Configured production tag immutability
  • Tested tag-overwrite protection
  • Defined repository-level access controls
  • Separated push and pull identities
  • Configured image-retention requirements
  • Reviewed registry audit events
  • Defined registry security alerts
  • Integrated the private registry with Kubernetes
  • Deployed an approved image by digest
  • Validated runtime image identity
  • Reviewed image-pull credential risk
  • Created an incident-response procedure
  • Produced an enterprise registry-security assessment

A secure private registry provides more than image storage.

It acts as a critical supply-chain security boundary by controlling:

  • Who can publish images
  • Which images can be deployed
  • Whether image identities can change
  • How vulnerabilities are discovered
  • How artifacts are retained
  • How registry events are investigated
  • How Kubernetes receives approved software

Registry security must be combined with secure builds, image scanning, SBOM generation, image signing, admission enforcement and runtime monitoring.

Next Lab: Lab 04 — Sign and Verify Container Images

In the next lab, you will create a container-image signing workflow, sign an approved image using Cosign, verify its signature, associate attestations and SBOM data with the image, test verification failure, and prepare Kubernetes admission policies that allow only trusted signed images.