Notary
Notary is a CNCF project that provides a specification and tooling for securing software supply chains.
The Notation CLI can be used to sign images and attestations in a CI/CD pipeline. A quick start guide providing a complete example of signing and verifying a container image using Notation can be found here.
The Notation CLI can also be used to inspect details of the container image signature.
1notation inspect ghcr.io/kyverno/test-verify-image@sha256:b31bfb4d0213f254d361e0079deaaebefa4f82ba7aa76ef82e90b4935ad5b105
2Inspecting all signatures for signed artifact
3ghcr.io/kyverno/test-verify-image@sha256:b31bfb4d0213f254d361e0079deaaebefa4f82ba7aa76ef82e90b4935ad5b105
4└── application/vnd.cncf.notary.signature
5 └── sha256:7f870420d92765b42cec0f71ee8e25bf39b692f64d95d6f6607e9e6e54300265
6 ├── media type: application/jose+json
7 ├── signature algorithm: RSASSA-PSS-SHA-256
8 ├── signed attributes
9 │ ├── signingScheme: notary.x509
10 │ └── signingTime: Mon May 22 14:45:04 2023
11 ├── user defined attributes
12 │ └── (empty)
13 ├── unsigned attributes
14 │ └── signingAgent: Notation/1.0.0
15 ├── certificates
16 │ └── SHA256 fingerprint: da1f2d7d648dfacc7ebd59f98a9f35c753c331d80ca4280bb94060f4af4a5357
17 │ ├── issued to: CN=test,O=Notary,L=Seattle,ST=WA,C=US
18 │ ├── issued by: CN=test,O=Notary,L=Seattle,ST=WA,C=US
19 │ └── expiry: Thu May 19 21:15:18 2033
20 └── signed artifact
21 ├── media type: application/vnd.docker.distribution.manifest.v2+json
22 ├── digest: sha256:b31bfb4d0213f254d361e0079deaaebefa4f82ba7aa76ef82e90b4935ad5b105
23 └── size: 938
You can also use an OCI registry client to discover signatures and attestations for an image.
1oras discover ghcr.io/kyverno/test-verify-image:signed -o tree
2ghcr.io/kyverno/test-verify-image:signed
3├── application/vnd.cncf.notary.signature
4│ └── sha256:7f870420d92765b42cec0f71ee8e25bf39b692f64d95d6f6607e9e6e54300265
5├── vulnerability-scan
6│ └── sha256:f89cb7a0748c63a674d157ca84d725ff3ac09cc2d4aee9d0ec4315e0fe92a5fd
7│ └── application/vnd.cncf.notary.signature
8│ └── sha256:ec45844601244aa08ac750f44def3fd48ddacb736d26b83dde9f5d8ac646c2f3
9└── sbom/cyclone-dx
10 └── sha256:8cad9bd6de426683424a204697dd48b55abcd6bb6b4930ad9d8ade99ae165414
11 └── application/vnd.cncf.notary.signature
12 └── sha256:61f3e42f017b72f4277c78a7a42ff2ad8f872811324cd984830dfaeb4030c322
Verifying Image Signatures
The following policy checks whether an image is signed with a valid X.509 key that matches the provided public certificate.
1apiVersion: kyverno.io/v2beta1
2kind: ClusterPolicy
3metadata:
4 name: check-image-notary
5spec:
6 validationFailureAction: Enforce
7 webhookTimeoutSeconds: 30
8 failurePolicy: Fail
9 rules:
10 - name: verify-signature-notary
11 match:
12 any:
13 - resources:
14 kinds:
15 - Pod
16 verifyImages:
17 - type: Notary
18 imageReferences:
19 - "ghcr.io/kyverno/test-verify-image*"
20 attestors:
21 - count: 1
22 entries:
23 - certificates:
24 cert: |-
25 -----BEGIN CERTIFICATE-----
26 MIIDTTCCAjWgAwIBAgIJAPI+zAzn4s0xMA0GCSqGSIb3DQEBCwUAMEwxCzAJBgNV
27 BAYTAlVTMQswCQYDVQQIDAJXQTEQMA4GA1UEBwwHU2VhdHRsZTEPMA0GA1UECgwG
28 Tm90YXJ5MQ0wCwYDVQQDDAR0ZXN0MB4XDTIzMDUyMjIxMTUxOFoXDTMzMDUxOTIx
29 MTUxOFowTDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAldBMRAwDgYDVQQHDAdTZWF0
30 dGxlMQ8wDQYDVQQKDAZOb3RhcnkxDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3
31 DQEBAQUAA4IBDwAwggEKAoIBAQDNhTwv+QMk7jEHufFfIFlBjn2NiJaYPgL4eBS+
32 b+o37ve5Zn9nzRppV6kGsa161r9s2KkLXmJrojNy6vo9a6g6RtZ3F6xKiWLUmbAL
33 hVTCfYw/2n7xNlVMjyyUpE+7e193PF8HfQrfDFxe2JnX5LHtGe+X9vdvo2l41R6m
34 Iia04DvpMdG4+da2tKPzXIuLUz/FDb6IODO3+qsqQLwEKmmUee+KX+3yw8I6G1y0
35 Vp0mnHfsfutlHeG8gazCDlzEsuD4QJ9BKeRf2Vrb0ywqNLkGCbcCWF2H5Q80Iq/f
36 ETVO9z88R7WheVdEjUB8UrY7ZMLdADM14IPhY2Y+tLaSzEVZAgMBAAGjMjAwMAkG
37 A1UdEwQCMAAwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMA0G
38 CSqGSIb3DQEBCwUAA4IBAQBX7x4Ucre8AIUmXZ5PUK/zUBVOrZZzR1YE8w86J4X9
39 kYeTtlijf9i2LTZMfGuG0dEVFN4ae3CCpBst+ilhIndnoxTyzP+sNy4RCRQ2Y/k8
40 Zq235KIh7uucq96PL0qsF9s2RpTKXxyOGdtp9+HO0Ty5txJE2txtLDUIVPK5WNDF
41 ByCEQNhtHgN6V20b8KU2oLBZ9vyB8V010dQz0NRTDLhkcvJig00535/LUylECYAJ
42 5/jn6XKt6UYCQJbVNzBg/YPGc1RF4xdsGVDBben/JXpeGEmkdmXPILTKd9tZ5TC0
43 uOKpF5rWAruB5PCIrquamOejpXV9aQA/K2JQDuc0mcKz
44 -----END CERTIFICATE-----
With this policy configured, Kyverno will verify matching container image signatures and only allow the pod to be configured if the signatures are valid.
1kubectl run test --image=ghcr.io/kyverno/test-verify-image:signed --dry-run=server
2pod/test created (server dry run)
Kyverno will also mutate the pod to replace the image tag with its digest.
1kubectl run test --image=ghcr.io/kyverno/test-verify-image:signed --dry-run=server -o yaml | grep "image: "
2 - image: ghcr.io/kyverno/test-verify-image:signed@sha256:b31bfb4d0213f254d361e0079deaaebefa4f82ba7aa76ef82e90b4935ad5b105
Attempting to run a pod with an unsigned image will be blocked.
1kubectl run test --image=ghcr.io/kyverno/test-verify-image:unsigned --dry-run=server
2Error from server: admission webhook "mutate.kyverno.svc-fail" denied the request:
3
4resource Pod/default/test was blocked due to the following policies
5
6check-image-notary:
7 verify-signature-notary: 'failed to verify image ghcr.io/kyverno/test-verify-image:unsigned:
8 .attestors[0].entries[0]: failed to verify ghcr.io/kyverno/test-verify-image@sha256:74a98f0e4d750c9052f092a7f7a72de7b20f94f176a490088f7a744c76c53ea5:
9 no signature is associated with "ghcr.io/kyverno/test-verify-image@sha256:74a98f0e4d750c9052f092a7f7a72de7b20f94f176a490088f7a744c76c53ea5",
10 make sure the image was signed successfully'
Tip
You can manage public keys and certificates as external data in a ConfigMap. See Variables from ConfigMaps for details.Verifying Image Attestations
Consider the following image: ghcr.io/kyverno/test-verify-image:signed
ghcr.io/kyverno/test-verify-image:signed
├── application/vnd.cncf.notary.signature
│ └── sha256:7f870420d92765b42cec0f71ee8e25bf39b692f64d95d6f6607e9e6e54300265
├── vulnerability-scan
│ └── sha256:f89cb7a0748c63a674d157ca84d725ff3ac09cc2d4aee9d0ec4315e0fe92a5fd
│ └── application/vnd.cncf.notary.signature
│ └── sha256:ec45844601244aa08ac750f44def3fd48ddacb736d26b83dde9f5d8ac646c2f3
└── sbom/cyclone-dx
└── sha256:8cad9bd6de426683424a204697dd48b55abcd6bb6b4930ad9d8ade99ae165414
└── application/vnd.cncf.notary.signature
└── sha256:61f3e42f017b72f4277c78a7a42ff2ad8f872811324cd984830dfaeb4030c322
This image has:
- A notary signature.
- A vulnerability scan report, signed using notary.
- A CycloneDX SBOM, signed using notary.
This policy checks the signature in the repo
ghcr.io/kyverno/test-verify-image
and ensures that it has been signed by verifying its signature against the provided certificates:
1apiVersion: kyverno.io/v1
2kind: ClusterPolicy
3metadata:
4 name: check-image-attestation
5spec:
6 validationFailureAction: Enforce
7 webhookTimeoutSeconds: 30
8 failurePolicy: Fail
9 rules:
10 - name: verify-attestation-notary
11 match:
12 any:
13 - resources:
14 kinds:
15 - Pod
16 context:
17 - name: keys
18 configMap:
19 name: keys
20 namespace: kyverno
21 verifyImages:
22 - type: Notary
23 imageReferences:
24 - "ghcr.io/kyverno/test-verify-image*"
25 attestations:
26 - type: sbom/cyclone-dx
27 attestors:
28 - entries:
29 - certificates:
30 cert: |-
31 -----BEGIN CERTIFICATE-----
32 MIIDTTCCAjWgAwIBAgIJAPI+zAzn4s0xMA0GCSqGSIb3DQEBCwUAMEwxCzAJBgNV
33 BAYTAlVTMQswCQYDVQQIDAJXQTEQMA4GA1UEBwwHU2VhdHRsZTEPMA0GA1UECgwG
34 Tm90YXJ5MQ0wCwYDVQQDDAR0ZXN0MB4XDTIzMDUyMjIxMTUxOFoXDTMzMDUxOTIx
35 MTUxOFowTDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAldBMRAwDgYDVQQHDAdTZWF0
36 dGxlMQ8wDQYDVQQKDAZOb3RhcnkxDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3
37 DQEBAQUAA4IBDwAwggEKAoIBAQDNhTwv+QMk7jEHufFfIFlBjn2NiJaYPgL4eBS+
38 b+o37ve5Zn9nzRppV6kGsa161r9s2KkLXmJrojNy6vo9a6g6RtZ3F6xKiWLUmbAL
39 hVTCfYw/2n7xNlVMjyyUpE+7e193PF8HfQrfDFxe2JnX5LHtGe+X9vdvo2l41R6m
40 Iia04DvpMdG4+da2tKPzXIuLUz/FDb6IODO3+qsqQLwEKmmUee+KX+3yw8I6G1y0
41 Vp0mnHfsfutlHeG8gazCDlzEsuD4QJ9BKeRf2Vrb0ywqNLkGCbcCWF2H5Q80Iq/f
42 ETVO9z88R7WheVdEjUB8UrY7ZMLdADM14IPhY2Y+tLaSzEVZAgMBAAGjMjAwMAkG
43 A1UdEwQCMAAwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMA0G
44 CSqGSIb3DQEBCwUAA4IBAQBX7x4Ucre8AIUmXZ5PUK/zUBVOrZZzR1YE8w86J4X9
45 kYeTtlijf9i2LTZMfGuG0dEVFN4ae3CCpBst+ilhIndnoxTyzP+sNy4RCRQ2Y/k8
46 Zq235KIh7uucq96PL0qsF9s2RpTKXxyOGdtp9+HO0Ty5txJE2txtLDUIVPK5WNDF
47 ByCEQNhtHgN6V20b8KU2oLBZ9vyB8V010dQz0NRTDLhkcvJig00535/LUylECYAJ
48 5/jn6XKt6UYCQJbVNzBg/YPGc1RF4xdsGVDBben/JXpeGEmkdmXPILTKd9tZ5TC0
49 uOKpF5rWAruB5PCIrquamOejpXV9aQA/K2JQDuc0mcKz
50 -----END CERTIFICATE-----
51 conditions:
52 - all:
53 - key: "{{ components[].licenses[].expression }}"
54 operator: AllIn
55 value: ["GPL-3.0"]
56
After this policy is applied, Kyverno will verify the signature on the sbom/cyclone-dx attestation and check if the license version of all the components in the SBOM is GPL-3.0
.
1kubectl run test --image=ghcr.io/kyverno/test-verify-image:signed --dry-run=server
2pod/test created (server dry run)
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.