Enforce SBOM attestation with Policy Controller

Enforce SBOM attestation with Policy Controller
  4 min read

This guide demonstrates how to use the Sigstore Policy Controller to verify image attestations before admitting an image into a Kubernetes cluster. In this guide, you will create a ClusterImagePolicy that checks the existence of a SBOM attestation attached to a container image, and then test the admission controller by running a registry.enforce.dev/chainguard/node image with SBOM attestations.

Prerequisites

To follow along with this guide, you will need the following:

Once you have everything in place you can continue to the first step and confirm that the Policy Controller is working as expected.

Step 1 - Checking the Policy Controller is Denying Admission

Before creating a ClusterImagePolicy, check that the Policy Controller is deployed and that your default namespace is labeled correctly. Run the following to check that the deployment is complete:

kubectl -n cosign-system wait --for=condition=Available deployment/policy-controller-webhook && \
kubectl -n cosign-system wait --for=condition=Available deployment/policy-controller-policy-webhook

When both deployments are finished, verify the default namespace is using the Policy Controller:

kubectl get ns -l policy.sigstore.dev/include=true

You should receive output like the following:

NAME      STATUS   AGE
default   Active   24s

Once you are sure that the Policy Controller is deployed and your default namespace is configured to use it, run a pod to make sure admission requests are handled and denied by default:

kubectl run --image k8s.gcr.io/pause:3.9 test

Since there is no ClusterImagePolicy defined yet, the Policy Controller will deny the admission request with a message like the following:

Error from server (BadRequest): admission webhook "policy.sigstore.dev" denied the request: validation failed: no matching policies: spec.containers[0].image
k8s.gcr.io/pause@sha256:7031c1b283388d2c2e09b57badb803c05ebed362dc88d84b480cc47f72a21097

In the next step, you will define a policy that verifies Chainguard Containers have a SBOM attestation and apply it to your cluster.

Step 2 — Creating a ClusterImagePolicy

Now that you have the Policy Controller running in your cluster, and have the default namespace configured to use it, you can now define a ClusterImagePolicy to admit images.

Open a new file with nano or your preferred editor:

nano /tmp/cip.yaml

Copy the following policy to the /tmp/cip.yaml file:

# Copyright 2022 Chainguard, Inc.
# SPDX-License-Identifier: Apache-2.0
apiVersion: policy.sigstore.dev/v1beta1
kind: ClusterImagePolicy
metadata:
  name: must-have-spdx-cue
  annotations:
    catalog.chainguard.dev/title: Enforce SBOM attestation
    catalog.chainguard.dev/description: Enforce a signed SPDX SBOM attestation from a custom key
    catalog.chainguard.dev/labels: attestation,cue
spec:
  images:
    - glob: "**"
  authorities:
    - name: my-authority
      keyless:
        identities:
          - issuer: "https://token.actions.githubusercontent.com"
            subject: "https://github.com/chainguard-images/images/.github/workflows/release.yaml@refs/heads/main"
      attestations:
        - name: must-have-spdx-attestation
          predicateType: https://spdx.dev/Document
          policy:
            type: cue
            data: |
              predicateType: "https://spdx.dev/Document"

The glob: ** line, working in combination with the authorities and policy sections, will allow any image that has at least a SBOM attestation with predicate type https://spdx.dev/Document to be admitted into your cluster.

Save the file and then apply the policy:

kubectl apply -f /tmp/cip.yaml

You will receive output showing the policy is created:

clusterimagepolicy.policy.sigstore.dev/must-have-spdx-cue created

Now run the k8s.gcr.io/pause:3.9 image which does not have a SBOM attestation:

kubectl run --image k8s.gcr.io/pause:3.9 noattestedimage

Since the image does not contain any attached SBOM, you will receive a message that the pod was rejected:

Error from server (BadRequest): admission webhook "policy.sigstore.dev" denied the request: validation failed: failed policy: demo: spec.containers[0].image
k8s.gcr.io/pause:3.9 no matching attestations with type https://spdx.dev/Document

Finally, we run registry.enforce.dev/chainguard/node image which contains a SBOM attestation of type https://spdx.dev/Document:

kubectl run --image registry.enforce.dev/chainguard/node mysbomattestedimage

Since the image has now a SBOM attestation, you will receive a message that the pod was created successfully:

pod/mysbomattestedimage created

Delete the pod once you’re done experimenting with it:

kubectl delete pod mysbomattestedimage

To learn more about how the Policy Controller uses Cosign to verify and admit images, review the Cosign Sigstore documentation.

Last updated: 2024-05-10 13:11