Lab 03 — Secure Private Container Registries
Mission Information
Section titled “Mission Information”| 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 |
Mission Scenario
Section titled “Mission Scenario”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
latesttag 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
Learning Objectives
Section titled “Learning Objectives”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
Enterprise Registry Architecture
Section titled “Enterprise Registry Architecture” 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 DigestRegistry Security Model
Section titled “Registry Security Model”Trusted Identity
│
▼
Least-Privilege Repository Access
│
▼
Secure Authentication
│
▼
Vulnerability Scanning
│
▼
Immutable Image Identity
│
▼
Image Signing and Verification
│
▼
Kubernetes Admission Control
│
▼
Audit Logging and MonitoringLab Outcomes
Section titled “Lab Outcomes”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
Important Security Notice
Section titled “Important Security Notice”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
Supported Lab Approaches
Section titled “Supported Lab Approaches”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:
- Create a private repository.
- Authenticate securely.
- Push an approved image.
- Scan the image.
- record its digest.
- Configure access controls.
- Prevent tag overwrite.
- Apply retention controls.
- Integrate with Kubernetes.
- Validate logging and monitoring.
Prerequisites
Section titled “Prerequisites”Before starting, ensure that you have:
- Docker Desktop, Docker Engine or Podman
- A hardened image from Lab 02
- Trivy installed
kubectlinstalled- 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:v2Tools Used
Section titled “Tools Used”| 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 |
Recommended Lab File Structure
Section titled “Recommended Lab File Structure”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.txtTask 01 — Select the Registry Platform
Section titled “Task 01 — Select the Registry Platform”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-apiRecommended environment separation:
cloudnova-development/payment-apicloudnova-staging/payment-apicloudnova-production/payment-apiRepository names should communicate:
- Organisation
- Business unit
- Application
- Component
- Environment where applicable
- Ownership
Avoid names such as:
testnew-appimage1temporarylatest-appTask 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.
Option A — Amazon ECR
Section titled “Option A — Amazon ECR”Set variables.
export AWS_REGION=<region>export REPOSITORY_NAME=cloudnova/payment-apiCreate the repository.
aws ecr create-repository \ --repository-name "$REPOSITORY_NAME" \ --region "$AWS_REGION"Review the repository.
aws ecr describe-repositories \ --repository-names "$REPOSITORY_NAME" \ --region "$AWS_REGION"Option B — Azure Container Registry
Section titled “Option B — Azure Container Registry”Set variables.
RESOURCE_GROUP=<resource-group>REGISTRY_NAME=<unique-registry-name>LOCATION=<location>Create the registry.
az acr create \ --resource-group "$RESOURCE_GROUP" \ --name "$REGISTRY_NAME" \ --sku Standard \ --location "$LOCATION"Review the registry.
az acr show \ --resource-group "$RESOURCE_GROUP" \ --name "$REGISTRY_NAME"Option C — Google Artifact Registry
Section titled “Option C — Google Artifact Registry”Set variables.
PROJECT_ID=<project-id>REGION=<region>REPOSITORY_NAME=cloudnova-productionCreate a Docker repository.
gcloud artifacts repositories create "$REPOSITORY_NAME" \ --repository-format=docker \ --location="$REGION" \ --project="$PROJECT_ID" \ --description="CloudNova production container images"Review the repository.
gcloud artifacts repositories describe "$REPOSITORY_NAME" \ --location="$REGION" \ --project="$PROJECT_ID"Option D — Local Docker Registry
Section titled “Option D — Local Docker Registry”Start a local registry for training.
docker run -d \ --name cloudnova-registry \ -p 5000:5000 \ registry:2Verify it.
docker psA local unencrypted registry is suitable only for isolated lab use unless TLS and authentication are added.
Task 05 — Record Registry Details
Section titled “Task 05 — Record Registry Details”Save the registry endpoint.
Example:
<account>.dkr.ecr.<region>.amazonaws.com<registry-name>.azurecr.io<region>-docker.pkg.devlocalhost:5000Save evidence.
echo "<registry-endpoint>" \ > evidence/registry-details.txtTask 06 — Review Encryption Controls
Section titled “Task 06 — Review Encryption Controls”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.
aws sts get-caller-identityaz account showGoogle Cloud
Section titled “Google Cloud”gcloud auth listRecord:
- 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”Amazon ECR
Section titled “Amazon ECR”aws ecr get-login-password \ --region "$AWS_REGION" \ | docker login \ --username AWS \ --password-stdin \ <account-id>.dkr.ecr.<region>.amazonaws.comAzure Container Registry
Section titled “Azure Container Registry”az acr login \ --name "$REGISTRY_NAME"Google Artifact Registry
Section titled “Google Artifact Registry”gcloud auth configure-docker \ <region>-docker.pkg.devLocal Registry
Section titled “Local Registry”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:
docker login \ --username admin \ --password my-secret-passwordPreferred methods include:
- Password through standard input
- Workload identity
- Cloud CLI credential helper
- Short-lived token
- Federated identity
- Managed identity
Check Docker credential storage.
cat ~/.docker/config.jsonDo not include credential values in lab reports.
Task 11 — Tag the Hardened Image
Section titled “Task 11 — Tag the Hardened Image”Verify the hardened image from Lab 02.
docker images secure-demoTag it for the registry.
Generic example:
docker tag \ secure-demo:v2 \ <registry-endpoint>/<repository>:1.0.0Amazon ECR example:
docker tag \ secure-demo:v2 \ <account-id>.dkr.ecr.<region>.amazonaws.com/cloudnova/payment-api:1.0.0Azure example:
docker tag \ secure-demo:v2 \ <registry-name>.azurecr.io/cloudnova/payment-api:1.0.0Google example:
docker tag \ secure-demo:v2 \ <region>-docker.pkg.dev/<project-id>/cloudnova-production/payment-api:1.0.0Task 12 — Review the Image Before Push
Section titled “Task 12 — Review the Image Before Push”Inspect the image.
docker image inspect secure-demo:v2Scan it again.
trivy image \ --severity HIGH,CRITICAL \ secure-demo:v2Confirm:
- 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.
Task 13 — Push the Image
Section titled “Task 13 — Push the Image”Push the tagged image.
docker push \ <registry-endpoint>/<repository>:1.0.0Observe:
- Layer upload
- Existing-layer reuse
- Manifest upload
- Image digest
Save the command output where practical.
docker push \ <registry-endpoint>/<repository>:1.0.0 \ > evidence/image-push-result.txt 2>&1Task 14 — Verify the Registry Image Inventory
Section titled “Task 14 — Verify the Registry Image Inventory”Amazon ECR
Section titled “Amazon ECR”aws ecr describe-images \ --repository-name "$REPOSITORY_NAME" \ --region "$AWS_REGION"Azure Container Registry
Section titled “Azure Container Registry”az acr repository show-tags \ --name "$REGISTRY_NAME" \ --repository cloudnova/payment-api \ --detailGoogle Artifact Registry
Section titled “Google Artifact Registry”gcloud artifacts docker images list \ <region>-docker.pkg.dev/<project-id>/<repository> \ --include-tagsLocal Registry
Section titled “Local Registry”curl http://localhost:5000/v2/_catalogTask 15 — Record the Immutable Image Digest
Section titled “Task 15 — Record the Immutable Image Digest”Retrieve the digest.
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.
echo "<registry-endpoint>/<repository>@sha256:<digest>" \ > evidence/pushed-image-digest.txtTask 16 — Pull the Image by Digest
Section titled “Task 16 — Pull the Image by Digest”Remove the local tagged copy where safe.
docker image rm \ <registry-endpoint>/<repository>:1.0.0Pull the image by digest.
docker pull \ <registry-endpoint>/<repository>@sha256:<digest>Confirm that the immutable artifact can be retrieved.
Task 17 — Enable Vulnerability Scanning
Section titled “Task 17 — Enable Vulnerability Scanning”Configure the registry to scan images during or after push.
Amazon ECR Basic Scanning Example
Section titled “Amazon ECR Basic Scanning Example”aws ecr put-image-scanning-configuration \ --repository-name "$REPOSITORY_NAME" \ --image-scanning-configuration scanOnPush=true \ --region "$AWS_REGION"Start a manual scan where required.
aws ecr start-image-scan \ --repository-name "$REPOSITORY_NAME" \ --image-id imageTag=1.0.0 \ --region "$AWS_REGION"Azure Container Registry
Section titled “Azure Container Registry”Use the security capabilities available in the configured Azure environment.
Validate integration with:
- Microsoft Defender for Cloud
- Registry vulnerability assessment
- Central security findings
Google Artifact Registry
Section titled “Google Artifact Registry”Validate integration with:
- Artifact Analysis
- Vulnerability scanning
- Container Analysis findings
Harbor
Section titled “Harbor”Enable a scanner such as Trivy and configure scan-on-push.
Task 18 — Review Registry Scan Results
Section titled “Task 18 — Review Registry Scan Results”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.jsonTask 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.
Amazon ECR
Section titled “Amazon ECR”aws ecr put-image-tag-mutability \ --repository-name "$REPOSITORY_NAME" \ --image-tag-mutability IMMUTABLE \ --region "$AWS_REGION"Validate.
aws ecr describe-repositories \ --repository-names "$REPOSITORY_NAME" \ --region "$AWS_REGION"Azure Container Registry
Section titled “Azure Container Registry”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
Google Artifact Registry
Section titled “Google Artifact Registry”Use repository permissions and release governance to prevent unauthorised overwrites.
Harbor
Section titled “Harbor”Enable tag immutability rules for production repositories.
Task 21 — Test Tag Immutability
Section titled “Task 21 — Test Tag Immutability”Build or retag a different image using the existing tag.
docker tag \ alpine:3.20 \ <registry-endpoint>/<repository>:1.0.0Attempt to push it.
docker push \ <registry-endpoint>/<repository>:1.0.0Expected result:
Push rejected because the tag is immutableDo 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.01.0.12026.07.30build-1042git-a1b2c3drelease-2026-07Avoid production use of:
latestnewfinalfinal2testworkingRecommended 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
Task 25 — Test Unauthorised Push Access
Section titled “Task 25 — Test Unauthorised Push Access”Use a pull-only identity where available.
Attempt to push an image.
docker push \ <registry-endpoint>/<repository>:unauthorised-testExpected:
Access deniedRecord:
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 deniedDo not delete the approved production image.
Confirm that pull-only and push-only identities cannot delete images.
Task 27 — Configure a Lifecycle Policy
Section titled “Task 27 — Configure a Lifecycle Policy”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.
Task 28 — Review Lifecycle Risks
Section titled “Task 28 — Review Lifecycle Risks”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 daysTask 29 — Configure Deletion Protection
Section titled “Task 29 — Configure Deletion Protection”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.
Task 30 — Review Registry Audit Logging
Section titled “Task 30 — Review Registry Audit Logging”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.txtTask 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: v1kind: Namespacemetadata: 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: restrictedApply it.
kubectl apply -f kubernetes/namespace.yamlVerify.
kubectl get namespace registry-security-lab \ --show-labelsTask 35 — Select the Kubernetes Registry Authentication Method
Section titled “Task 35 — Select the Kubernetes Registry Authentication Method”Preferred authentication order:
- Kubernetes workload identity or node identity
- Managed identity
- Cloud-provider registry integration
- Short-lived registry token
- Kubernetes image-pull Secret
- 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.
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.
kubectl get secret registry-credentials \ -n registry-security-labDo 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.
kubectl get secret registry-credentials \ -n registry-security-lab \ -o jsonpath='{.type}{"\n"}'Expected:
kubernetes.io/dockerconfigjsonValidate:
- 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.
Task 38 — Create the Secure Deployment
Section titled “Task 38 — Create the Secure Deployment”Create kubernetes/deployment.yaml.
apiVersion: apps/v1kind: Deploymentmetadata: name: registry-demo namespace: registry-security-lab labels: app: registry-demo environment: training owner: cloud-securityspec: 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.
kubectl apply \ --dry-run=client \ -f kubernetes/deployment.yamlReview:
- Image is referenced by digest.
- No
latesttag 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.
kubectl apply \ -f kubernetes/deployment.yamlMonitor rollout.
kubectl rollout status \ deployment/registry-demo \ -n registry-security-labReview Pods.
kubectl get pods \ -n registry-security-lab \ -o wideTask 41 — Investigate Image-Pull Failure
Section titled “Task 41 — Investigate Image-Pull Failure”If the Pod reports ImagePullBackOff, review it.
kubectl describe pod \ <pod-name> \ -n registry-security-labCommon 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.
kubectl get events \ -n registry-security-lab \ --sort-by=.metadata.creationTimestampTask 42 — Verify the Running Image Digest
Section titled “Task 42 — Verify the Running Image Digest”Review the configured image.
kubectl get pod \ <pod-name> \ -n registry-security-lab \ -o jsonpath='{.spec.containers[*].image}{"\n"}'Review the runtime image ID.
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.
Task 43 — Validate Runtime Security
Section titled “Task 43 — Validate Runtime Security”Check runtime identity.
kubectl exec \ <pod-name> \ -n registry-security-lab \ -- idExpected:
uid=10001Review privilege settings.
kubectl exec \ <pod-name> \ -n registry-security-lab \ -- sh -c "grep -E 'NoNewPrivs|CapEff|Seccomp' /proc/1/status"Attempt to modify a protected path.
kubectl exec \ <pod-name> \ -n registry-security-lab \ -- touch /etc/registry-testExpected:
Read-only file systemTask 44 — Validate Pull-Only Access
Section titled “Task 44 — Validate Pull-Only Access”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-existApply only in the training namespace.
Review the resulting event.
Expected:
ImagePullBackOffRestore 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.
kubectl auth can-i get secrets \ -n registry-security-labTest a specific identity where authorised.
kubectl auth can-i get secrets \ --as=<user-or-service-account> \ -n registry-security-labTask 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 CauseTask 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.
Critical Risk
Section titled “Critical Risk”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
High Risk
Section titled “High Risk”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
Medium Risk
Section titled “Medium Risk”Examples:
- Missing lifecycle policy
- Excessive image retention
- No private endpoint
- SBOMs not retained
- Incomplete alerting
- Weak repository naming
- Manual access reviews
Low Risk
Section titled “Low Risk”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:Task 55 — Collect Evidence
Section titled “Task 55 — Collect Evidence”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.txt02-repository-details.json03-encryption-settings.txt04-access-control-matrix.md05-authenticated-identity.txt06-authentication-method.txt07-image-tag.txt08-image-digest.txt09-image-push-result.txt10-vulnerability-scan.json11-tag-immutability.txt12-immutability-test.txt13-lifecycle-policy.json14-delete-protection.txt15-audit-events.txt16-kubernetes-pull-method.txt17-kubernetes-deployment.yaml18-runtime-image-id.txt19-access-denied-tests.txt20-registry-assessment.md21-registry-security-report.mdTask 56 — Clean Up Kubernetes Resources
Section titled “Task 56 — Clean Up Kubernetes Resources”Delete the training namespace.
kubectl delete namespace registry-security-labVerify.
kubectl get namespace registry-security-labExpected:
NotFoundTask 57 — Remove Local Registry Credentials
Section titled “Task 57 — Remove Local Registry Credentials”Log out where required.
docker logout <registry-endpoint>Review local Docker configuration.
cat ~/.docker/config.jsonDo not delete credential-helper configuration required for other authorised workloads.
Task 58 — Clean Up Registry Resources
Section titled “Task 58 — Clean Up Registry Resources”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:
docker stop cloudnova-registrydocker rm cloudnova-registryEnterprise 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 | ☐ |
Remediation Priorities
Section titled “Remediation Priorities”Immediate
Section titled “Immediate”- 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.
Short-Term
Section titled “Short-Term”- 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.
Long-Term
Section titled “Long-Term”- 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.
Skills Developed
Section titled “Skills Developed”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
Knowledge Check
Section titled “Knowledge Check”Question 1
Section titled “Question 1”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
Question 2
Section titled “Question 2”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
Question 3
Section titled “Question 3”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
Question 4
Section titled “Question 4”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
Question 5
Section titled “Question 5”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
Question 6
Section titled “Question 6”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
Question 7
Section titled “Question 7”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
Question 8
Section titled “Question 8”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
Question 9
Section titled “Question 9”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
Question 10
Section titled “Question 10”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
Lab Summary
Section titled “Lab Summary”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.
What’s Next?
Section titled “What’s Next?”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.