Notary
Notary (https://notaryproject.dev/) 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. This quickstart guide provides a complete example of siging and verifying a container image using Notation: https://notaryproject.dev/docs/quickstart/.
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:
1---
2apiVersion: kyverno.io/v2beta1
3kind: ClusterPolicy
4metadata:
5 name: check-image-notary
6spec:
7 validationFailureAction: Enforce
8 webhookTimeoutSeconds: 30
9 failurePolicy: Fail
10 rules:
11 - name: verify-signature-notary
12 match:
13 any:
14 - resources:
15 kinds:
16 - Pod
17 verifyImages:
18 - type: Notary
19 imageReferences:
20 - "ghcr.io/kyverno/test-verify-image*"
21 attestors:
22 - count: 1
23 entries:
24 - certificates:
25 cert: |-
26 -----BEGIN CERTIFICATE-----
27 MIIDTTCCAjWgAwIBAgIJAPI+zAzn4s0xMA0GCSqGSIb3DQEBCwUAMEwxCzAJBgNV
28 BAYTAlVTMQswCQYDVQQIDAJXQTEQMA4GA1UEBwwHU2VhdHRsZTEPMA0GA1UECgwG
29 Tm90YXJ5MQ0wCwYDVQQDDAR0ZXN0MB4XDTIzMDUyMjIxMTUxOFoXDTMzMDUxOTIx
30 MTUxOFowTDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAldBMRAwDgYDVQQHDAdTZWF0
31 dGxlMQ8wDQYDVQQKDAZOb3RhcnkxDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3
32 DQEBAQUAA4IBDwAwggEKAoIBAQDNhTwv+QMk7jEHufFfIFlBjn2NiJaYPgL4eBS+
33 b+o37ve5Zn9nzRppV6kGsa161r9s2KkLXmJrojNy6vo9a6g6RtZ3F6xKiWLUmbAL
34 hVTCfYw/2n7xNlVMjyyUpE+7e193PF8HfQrfDFxe2JnX5LHtGe+X9vdvo2l41R6m
35 Iia04DvpMdG4+da2tKPzXIuLUz/FDb6IODO3+qsqQLwEKmmUee+KX+3yw8I6G1y0
36 Vp0mnHfsfutlHeG8gazCDlzEsuD4QJ9BKeRf2Vrb0ywqNLkGCbcCWF2H5Q80Iq/f
37 ETVO9z88R7WheVdEjUB8UrY7ZMLdADM14IPhY2Y+tLaSzEVZAgMBAAGjMjAwMAkG
38 A1UdEwQCMAAwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMA0G
39 CSqGSIb3DQEBCwUAA4IBAQBX7x4Ucre8AIUmXZ5PUK/zUBVOrZZzR1YE8w86J4X9
40 kYeTtlijf9i2LTZMfGuG0dEVFN4ae3CCpBst+ilhIndnoxTyzP+sNy4RCRQ2Y/k8
41 Zq235KIh7uucq96PL0qsF9s2RpTKXxyOGdtp9+HO0Ty5txJE2txtLDUIVPK5WNDF
42 ByCEQNhtHgN6V20b8KU2oLBZ9vyB8V010dQz0NRTDLhkcvJig00535/LUylECYAJ
43 5/jn6XKt6UYCQJbVNzBg/YPGc1RF4xdsGVDBben/JXpeGEmkdmXPILTKd9tZ5TC0
44 uOKpF5rWAruB5PCIrquamOejpXV9aQA/K2JQDuc0mcKz
45 -----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
Kyverno does not support verifying attestations signed by Notary. This feature is being implemented and scheduled for the next minor release.