Signing and verifying Container Registry Docker images in Managed Service for Kubernetes
This tutorial describes how to sign Docker images using Cosign
To sign Docker images and set up their verification:
If you no longer need these resources, delete them.
Getting started
Prepare the infrastructure
- Create a Managed Service for Kubernetes cluster and a node group.
- Create a registry in Container Registry.
Before you start working with the Managed Service for Kubernetes cluster
Add multiple Docker images to the Container Registry registry
- Authenticate in Container Registry.
- Create multiple Docker images. One image will be signed using Cosign, while others will remain unsigned.
- Push Docker images to the Container Registry registry.
Sign a Docker image using Cosign
-
Generate a key pair using Cosign:
cosign generate-key-pair
Set a private key's password and enter it twice.
Result:
Enter password for private key: Enter password for private key again: Private key written to cosign.key Public key written to cosign.pub
-
Sign the Docker image in the Container Registry registry:
cosign sign --key cosign.key cr.ai.nebius.cloud/<registry ID>/<Docker image name>:<tag>
The signed image will be used when checking results.
Enter the password for the private key. Result:
Enter password for private key: Pushing signature to: cr.ai.nebius.cloud/<registry ID>/<Docker image name>
A second object with the
sha256-....sig
tag and thecr.ai.nebius.cloud/<registry ID>/<Docker image name>@sha256:...
hash should appear in the Container Registry registry. -
Check that the signature is valid manually:
cosign verify --key cosign.pub cr.ai.nebius.cloud/<registry ID>/<Docker image name>:<tag>
Result:
Verification for cr.ai.nebius.cloud/<registry ID>/<Docker image name>:<tag> -- The following checks were performed on each of these signatures: - The cosign claims were validated - The signatures were verified against the specified public key [{"critical":{"identity":{"docker-reference":"cr.ai.nebius.cloud/<registry ID>/<Docker image name>"},"image":{"docker-manifest-digest":"sha256:..."},"type":"cosign container image signature"},"optional":null}]
Create a policy for signature verification
-
Create an authorized key for the
k8s-nodegroups-sa
service account attached to the cluster's nodes and save it to the file:ncp iam key create \ --service-account-name=k8s-nodegroups-sa \ --output=authorized-key.json
-
Install the Kyverno
app to the Managed Service for Kubernetes cluster. You need it to create a policy for verifying Docker image signatures.-
Add the
kyverno
repository:helm repo add kyverno https://kyverno.github.io/kyverno/
Result:
"kyverno" has been added to your repositories
-
Install the Kyverno app to the
kyverno
namespace:helm install kyverno kyverno/kyverno \ --namespace kyverno \ --create-namespace \ --set replicaCount=1 \ --set imagePullSecrets.regcred.registry=cr.ai.nebius.cloud \ --set imagePullSecrets.regcred.username=json_key \ --set-file imagePullSecrets.regcred.password=./authorized-key.json
Result:
NAME: kyverno LAST DEPLOYED: Thu Sep 8 10:43:00 2022 NAMESPACE: kyverno STATUS: deployed ...
-
-
Create a policy:
-
Save the specification for
ClusterPolicy
creation in a YAML file namedpolicy.yaml
:apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: check-image spec: validationFailureAction: enforce background: false webhookTimeoutSeconds: 30 failurePolicy: Fail rules: - name: check-image match: any: - resources: kinds: - Pod verifyImages: - imageReferences: - "cr.ai.nebius.cloud/<registry ID>/*" attestors: - count: 1 entries: - keys: publicKeys: |- <cosign.pub contents>
Sample filled out policy.yaml fileapiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: check-image spec: validationFailureAction: enforce background: false webhookTimeoutSeconds: 30 failurePolicy: Fail rules: - name: check-image match: any: - resources: kinds: - Pod verifyImages: - imageReferences: - "cr.ai.nebius.cloud/crpd2f2bnrlb2i7ltssl/*" attestors: - count: 1 entries: - keys: publicKeys: |- -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1jTu/9rJZZvUFi4bGhlvgMQdIY97 7NuGl2zzpV7olAyIu/WiywxI7Fny5tk6JmNPIFvSAtys3c08gfEcVV3D1Q== -----END PUBLIC KEY-----
-
Run the following command:
kubectl apply -f ./policy.yaml
Result:
clusterpolicy.kyverno.io/check-image configured
-
Check the results
-
Create a pod from the signed Docker image:
kubectl run pod --image=cr.ai.nebius.cloud/<registry ID>/<Docker image name>:<tag>
Result:
pod/pod created
-
Create a pod from an unsigned Docker image:
kubectl run pod2 --image=cr.ai.nebius.cloud/<registry ID>/<name of the unsigned Docker image>:<tag>
Result:
Error from server: admission webhook "mutate.kyverno.svc-fail" denied the request: resource Pod/default/pod2 was blocked due to the following policies check-image: check-image: failed to verify signature for cr.ai.nebius.cloud/crpsere9njsadcq6fgm2/alpine:2.0: .attestors[0].entries[0].keys: no matching signatures:
Delete the resources you created
Some resources are not free of charge. Delete the resources you no longer need to stop paying for them:
- Delete the Managed Service for Kubernetes cluster.
- Delete all the Docker images from the Container Registry registry.
- Delete the Container Registry registry.