CKA Certification Course - Certified Kubernetes Administrator

Security

Solution Image Security

In this guide, we will walk through a hands-on lab focusing on securing container images within a Kubernetes environment. We will cover how to correctly use a Docker registry secret and update a deployment to pull an image from a private registry.

Choosing the Right Secret Type for a Docker Registry

Kubernetes supports three types of secrets: Docker registry, generic, and TLS. For our use case, as we need to authenticate with a Docker registry, we will be using the Docker registry secret.

Below is the help output for the secret creation command:

root@controlplane:/# kubectl create secret
Create a secret using specified subcommand.

Available Commands:
  docker-registry   Create a secret for use with a Docker registry
  generic           Create a secret from a local file, directory or literal value
  tls               Create a TLS secret

Usage:
  kubectl create secret [flags] [options]

Use "kubectl <command> --help" for more information about a given command.
Use "kubectl options" for a list of global command-line options (applies to all commands).
root@controlplane:/#

Checking the Current Deployment

We begin by examining our cluster’s web application deployment. Running the following command shows that the deployment named web is running two replicas with the nginx:alpine image:

root@controlplane:/# kubectl get deploy
NAME   READY   UP-TO-DATE   AVAILABLE   AGE
web    2/2     2            2           48s

Since our goal is to pull the image from an internal private registry, we need to update the deployment to use an image hosted at myprivateregistry.com:5000 instead of the default Docker Hub image.

Inspecting the Deployment Configuration

To understand the current state of the deployment, inspect its detailed configuration with:

root@controlplane:/# k describe deploy web
Name:                   web
Namespace:              default
CreationTimestamp:      Mon, 18 Apr 2022 01:22:13 +0000
Labels:                 app=web
Annotations:            deployment.kubernetes.io/revision: 1
Selector:               app=web
Replicas:               2 desired | 2 updated | 2 total | 2 available | 0 unavailable
StrategyType:          RollingUpdate
MinReadySeconds:       0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
  Labels:  app=web
  Containers:
   nginx:
    Image:         nginx:alpine
    Port:          <none>
    Host Port:     <none>
    Environment:   <none>
    Mounts:        <none>
  Volumes:        <none>
Conditions:
  Type           Status  Reason
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  <none>
NewReplicaSet:   web-bd975bd87 (2/2 replicas created)
Events:
  Type    Reason                  Age   From                     Message
  ----    ------                  ----  ----                     -------
  Normal  ScalingReplicaSet       47s   deployment-controller    Scaled up replica set web-bd975bd87 to 2
root@controlplane:/#

Updating the Deployment to Use a Private Registry Image

Edit the deployment configuration to specify the new image and prepare to add the required image pull secret. Below is an excerpt of the updated configuration (parts that remain unchanged have been omitted for brevity):

annotations:
  deployment.kubernetes.io/revision: "1"
creationTimestamp: "2022-04-18T01:22:13Z"
generation: 1
labels:
  app: web
name: web
namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        imagePullPolicy: IfNotPresent
        resources: {}
        terminationMessagePath: /dev/termination-log
      restartPolicy: Always
      dnsPolicy: ClusterFirst
      schedulerName: default-scheduler

After saving the updated deployment, verify that the new image name is set. As part of the rolling update process, a new replica set is created:

root@controlplane:/# k describe deploy web
Name:               web
Namespace:          default
Labels:             app=web
Annotations:        deployment.kubernetes.io/revision: 2
Selector:           app: web
Replicas:           2 desired | 1 updated | 3 total | 2 available | 1 unavailable
StrategyType:       RollingUpdate
MinReadySeconds:    0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
  Labels:           app: web
  Containers:
   nginx:
    Image:        myprivateregistry.com:5000/nginx:alpine
    Port:         <none>
    Host Port:    <none>
    Environment:   <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type           Status  Reason
  Available      True    MinimumReplicasAvailable
  Progressing    True    ReplicaSetUpdated
OldReplicaSets:  web-bd975bd87 (2/2 replicas created)
NewReplicaSet:   web-85fcf65896 (1/1 replicas created)
Events:
  Type    Reason             Age   From                           Message
  Normal  ScalingReplicaSet  1065s deployment-controller          Scaled up replica set web-bd975bd87 to 2
  Normal  ScalingReplicaSet  6s    deployment-controller          Scaled up replica set web-85fcf65896 to 1

Troubleshooting: ImagePullBackOff Error

When checking the pods, you may notice that while the old pods remain active, the new pod reports an ImagePullBackOff error:

root@controlplane:/# k get pods
NAME                          READY   STATUS              RESTARTS   AGE
web-85fcf65896-rbsmq         0/1     ImagePullBackOff    0          20s
web-bd975bd87-jjbnx          1/1     Running             0          2m
web-bd975bd87-mf9vg          1/1     Running             0          2m
root@controlplane:/#

Inspect the pod details to reveal an error message indicating an authentication failure when pulling the image:

State:                Waiting
Reason:               ErrImagePull
...
Warning Failed:       Failed to pull image "myprivateregistry.com:5000/nginx:alpine": rpc error: code = Unknown desc = Error response from daemon: Get http://myprivateregistry.com:5000/v2/: net/http: HTTP/1.1 transport connection broken: malformed HTTP response “\x15\x03\x01”

Warning

The error indicates that the credentials for accessing your private registry are missing. Without valid credentials, Kubernetes will not be able to pull the image.

Creating the Docker Registry Secret

To resolve this issue, create a secret containing the necessary credentials. Replace the placeholders with your actual registry information:

kubectl create secret docker-registry my-secret --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL

For example, to create the secret for our private registry, run:

kubectl create secret docker-registry private-reg-cred --docker-server=myprivateregistry.com --docker-username=dock_user --docker-password=dock_password [email protected]

Updating the Pod Template for Image Pull Secrets

After successfully creating the secret, update the deployment’s pod template to include the image pull secret. According to the Kubernetes Documentation, add the following block under the pod specification:

imagePullSecrets:
- name: private-reg-cred

Below is a complete example of a pod configuration that pulls an image from a private registry:

apiVersion: v1
kind: Pod
metadata:
  name: private-reg
spec:
  containers:
  - name: private-reg-container
    image: <your-private-image>
  imagePullSecrets:
  - name: regcred

Edit the deployment with the following command to include the image pull secret:

k edit deploy web

After saving your changes, Kubernetes will update the deployment by terminating old pods and creating new ones that use the private registry image along with the correct authentication.

Final Verification

Ensure that all pods are updated and running with the new image and the secret is applied correctly. Use the following command to verify:

root@controlplane:/# kubectl get pods

Once you confirm that all pods have successfully pulled the image and are running, the lab is complete. Enjoy the enhanced security and efficiency of your Kubernetes deployments!

Note

For more information on securing Kubernetes deployments and managing Docker registry secrets, refer to the Kubernetes Documentation.

Watch Video

Watch video content

Previous
Image Security