Skip to content

Commit 55a2cdb

Browse files
authored
Merge pull request #1075 from JasonTheDeveloper/feat/notation
feat(notation): add support for notation in HelmChart and OCIRepository configuration
2 parents 565f6ee + 553945a commit 55a2cdb

30 files changed

+2755
-249
lines changed

DEVELOPMENT.md

+4-3
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ make run
5858

5959
### Building the container image
6060

61-
Set the name of the container image to be created from the source code. This will be used
61+
Set the name of the container image to be created from the source code. This will be used
6262
when building, pushing and referring to the image on YAML files:
6363

6464
```sh
@@ -79,7 +79,7 @@ make docker-push
7979
```
8080

8181
Alternatively, the three steps above can be done in a single line:
82-
82+
8383
```sh
8484
IMG=registry-path/source-controller TAG=latest BUILD_ARGS=--push \
8585
make docker-build
@@ -128,7 +128,8 @@ Create a `.vscode/launch.json` file:
128128
"type": "go",
129129
"request": "launch",
130130
"mode": "auto",
131-
"program": "${workspaceFolder}/main.go"
131+
"program": "${workspaceFolder}/main.go",
132+
"args": ["--storage-adv-addr=:0", "--storage-path=${workspaceFolder}/bin/data"]
132133
}
133134
]
134135
}

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ and is a core component of the [GitOps toolkit](https://fluxcd.io/flux/component
2727
## Features
2828

2929
* authenticates to sources (SSH, user/password, API token, Workload Identity)
30-
* validates source authenticity (PGP, Cosign)
30+
* validates source authenticity (PGP, Cosign, Notation)
3131
* detects source changes based on update policies (semver)
3232
* fetches resources on-demand and on-a-schedule
3333
* packages the fetched resources into a well-known format (tar.gz, yaml)

api/v1beta2/ocirepository_types.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ type OCILayerSelector struct {
182182
// OCIRepositoryVerification verifies the authenticity of an OCI Artifact
183183
type OCIRepositoryVerification struct {
184184
// Provider specifies the technology used to sign the OCI Artifact.
185-
// +kubebuilder:validation:Enum=cosign
185+
// +kubebuilder:validation:Enum=cosign;notation
186186
// +kubebuilder:default:=cosign
187187
Provider string `json:"provider"`
188188

config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,7 @@ spec:
468468
OCI Artifact.
469469
enum:
470470
- cosign
471+
- notation
471472
type: string
472473
secretRef:
473474
description: |-

config/crd/bases/source.toolkit.fluxcd.io_ocirepositories.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ spec:
224224
OCI Artifact.
225225
enum:
226226
- cosign
227+
- notation
227228
type: string
228229
secretRef:
229230
description: |-
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
---
2+
apiVersion: source.toolkit.fluxcd.io/v1beta2
3+
kind: HelmRepository
4+
metadata:
5+
name: podinfo-notation
6+
spec:
7+
url: oci://ghcr.io/stefanprodan/charts
8+
type: "oci"
9+
interval: 1m
10+
---
11+
apiVersion: source.toolkit.fluxcd.io/v1beta2
12+
kind: HelmChart
13+
metadata:
14+
name: podinfo-notation
15+
spec:
16+
chart: podinfo
17+
sourceRef:
18+
kind: HelmRepository
19+
name: podinfo-notation
20+
version: '6.6.0'
21+
interval: 1m
22+
verify:
23+
provider: notation
24+
secretRef:
25+
name: notation-config
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
apiVersion: source.toolkit.fluxcd.io/v1beta2
3+
kind: OCIRepository
4+
metadata:
5+
name: podinfo-deploy-signed-with-notation
6+
spec:
7+
interval: 5m
8+
url: oci://ghcr.io/stefanprodan/podinfo-deploy
9+
ref:
10+
semver: "6.6.x"
11+
verify:
12+
provider: notation
13+
secretRef:
14+
name: notation-config

docs/spec/v1beta2/helmcharts.md

+60-6
Original file line numberDiff line numberDiff line change
@@ -252,15 +252,20 @@ For practical information, see
252252

253253
**Note:** This feature is available only for Helm charts fetched from an OCI Registry.
254254

255-
`.spec.verify` is an optional field to enable the verification of [Cosign](https://github.com/sigstore/cosign)
255+
`.spec.verify` is an optional field to enable the verification of [Cosign](https://github.com/sigstore/cosign) or [Notation](https://github.com/notaryproject/notation)
256256
signatures. The field offers three subfields:
257257

258-
- `.provider`, to specify the verification provider. Only supports `cosign` at present.
258+
- `.provider`, to specify the verification provider. The supported options are `cosign` and `notation` at present.
259259
- `.secretRef.name`, to specify a reference to a Secret in the same namespace as
260-
the HelmChart, containing the Cosign public keys of trusted authors.
261-
- `.matchOIDCIdentity`, to specify a list of OIDC identity matchers. Please see
260+
the HelmChart, containing the public keys of trusted authors. For Notation this Secret should also include the [trust policy](https://github.com/notaryproject/specifications/blob/v1.0.0/specs/trust-store-trust-policy.md#trust-policy) in
261+
addition to the CA certificate.
262+
- `.matchOIDCIdentity`, to specify a list of OIDC identity matchers (only supported when using `cosign` as the verification provider). Please see
262263
[Keyless verification](#keyless-verification) for more details.
263264

265+
#### Cosign
266+
267+
The `cosign` provider can be used to verify the signature of an OCI artifact using either a known public key or via the [Cosign Keyless](https://github.com/sigstore/cosign/blob/main/KEYLESS.md) procedure.
268+
264269
```yaml
265270
---
266271
apiVersion: source.toolkit.fluxcd.io/v1beta2
@@ -281,7 +286,7 @@ following attributes to the HelmChart's `.status.conditions`:
281286
- `status: "True"`
282287
- `reason: Succeeded`
283288

284-
#### Public keys verification
289+
##### Public keys verification
285290

286291
To verify the authenticity of HelmChart hosted in an OCI Registry, create a Kubernetes
287292
secret with the Cosign public keys:
@@ -303,7 +308,7 @@ Note that the keys must have the `.pub` extension for Flux to make use of them.
303308
Flux will loop over the public keys and use them to verify a HelmChart's signature.
304309
This allows for older HelmCharts to be valid as long as the right key is in the secret.
305310

306-
#### Keyless verification
311+
##### Keyless verification
307312

308313
For publicly available HelmCharts, which are signed using the
309314
[Cosign Keyless](https://github.com/sigstore/cosign/blob/main/KEYLESS.md) procedure,
@@ -362,6 +367,55 @@ instance hosted at [rekor.sigstore.dev](https://rekor.sigstore.dev/).
362367
Note that keyless verification is an **experimental feature**, using
363368
custom root CAs or self-hosted Rekor instances are not currently supported.
364369

370+
#### Notation
371+
372+
The `notation` provider can be used to verify the signature of an OCI artifact using known
373+
trust policy and CA certificate.
374+
375+
```yaml
376+
---
377+
apiVersion: source.toolkit.fluxcd.io/v1beta2
378+
kind: HelmChart
379+
metadata:
380+
name: podinfo
381+
spec:
382+
verify:
383+
provider: notation
384+
secretRef:
385+
name: notation-config
386+
```
387+
388+
When the verification succeeds, the controller adds a Condition with the
389+
following attributes to the HelmChart's `.status.conditions`:
390+
391+
- `type: SourceVerified`
392+
- `status: "True"`
393+
- `reason: Succeeded`
394+
395+
To verify the authenticity of an OCI artifact, create a Kubernetes secret
396+
containing Certificate Authority (CA) root certificates and the a `trust policy`
397+
398+
```yaml
399+
---
400+
apiVersion: v1
401+
kind: Secret
402+
metadata:
403+
name: notation-config
404+
type: Opaque
405+
data:
406+
certificate1.pem: <BASE64>
407+
certificate2.crt: <BASE64>
408+
trustpolicy.json: <BASE64>
409+
```
410+
411+
Note that the CA certificates must have either `.pem` or `.crt` extension and your trust policy must
412+
be named `trustpolicy.json` for Flux to make use of them.
413+
414+
For more information on the signing and verification process see [Signing and Verification Workflow](https://github.com/notaryproject/specifications/blob/v1.0.0/specs/signing-and-verification-workflow.md).
415+
416+
Flux will loop over the certificates and use them to verify an artifact's signature.
417+
This allows for older artifacts to be valid as long as the right certificate is in the secret.
418+
365419
## Working with HelmCharts
366420

367421
### Triggering a reconcile

docs/spec/v1beta2/ocirepositories.md

+66-8
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ patches:
237237
target:
238238
kind: Deployment
239239
name: source-controller
240-
```
240+
```
241241

242242
When using pod-managed identity on an AKS cluster, AAD Pod Identity
243243
has to be used to give the `source-controller` pod access to the ACR.
@@ -279,7 +279,7 @@ patches:
279279
target:
280280
kind: ServiceAccount
281281
name: source-controller
282-
```
282+
```
283283

284284
The Artifact Registry service uses the permission `artifactregistry.repositories.downloadArtifacts`
285285
that is located under the Artifact Registry Reader role. If you are using
@@ -454,7 +454,7 @@ metadata:
454454
spec:
455455
ref:
456456
digest: "sha256:<SHA-value>"
457-
```
457+
```
458458

459459
This field takes precedence over all other fields.
460460

@@ -501,14 +501,23 @@ for more information.
501501
### Verification
502502

503503
`.spec.verify` is an optional field to enable the verification of [Cosign](https://github.com/sigstore/cosign)
504+
or [Notation](https://github.com/notaryproject/notation)
504505
signatures. The field offers three subfields:
505506

506-
- `.provider`, to specify the verification provider. Only supports `cosign` at present.
507+
- `.provider`, to specify the verification provider. The supported options are `cosign` and `notation` at present.
507508
- `.secretRef.name`, to specify a reference to a Secret in the same namespace as
508-
the OCIRepository, containing the Cosign public keys of trusted authors.
509-
- `.matchOIDCIdentity`, to specify a list of OIDC identity matchers. Please see
509+
the OCIRepository, containing the Cosign public keys of trusted authors. For Notation this Secret should also
510+
include the [trust policy](https://github.com/notaryproject/specifications/blob/v1.0.0/specs/trust-store-trust-policy.md#trust-policy) in
511+
addition to the CA certificate.
512+
- `.matchOIDCIdentity`, to specify a list of OIDC identity matchers (only supported when using `cosign` as the
513+
verification provider). Please see
510514
[Keyless verification](#keyless-verification) for more details.
511515

516+
#### Cosign
517+
518+
The `cosign` provider can be used to verify the signature of an OCI artifact using either a known public key
519+
or via the [Cosign Keyless](https://github.com/sigstore/cosign/blob/main/KEYLESS.md) procedure.
520+
512521
```yaml
513522
---
514523
apiVersion: source.toolkit.fluxcd.io/v1beta2
@@ -529,7 +538,7 @@ following attributes to the OCIRepository's `.status.conditions`:
529538
- `status: "True"`
530539
- `reason: Succeeded`
531540

532-
#### Public keys verification
541+
##### Public keys verification
533542

534543
To verify the authenticity of an OCI artifact, create a Kubernetes secret
535544
with the Cosign public keys:
@@ -551,7 +560,7 @@ Note that the keys must have the `.pub` extension for Flux to make use of them.
551560
Flux will loop over the public keys and use them to verify an artifact's signature.
552561
This allows for older artifacts to be valid as long as the right key is in the secret.
553562

554-
#### Keyless verification
563+
##### Keyless verification
555564

556565
For publicly available OCI artifacts, which are signed using the
557566
[Cosign Keyless](https://github.com/sigstore/cosign/blob/main/KEYLESS.md) procedure,
@@ -593,6 +602,55 @@ instance hosted at [rekor.sigstore.dev](https://rekor.sigstore.dev/).
593602
Note that keyless verification is an **experimental feature**, using
594603
custom root CAs or self-hosted Rekor instances are not currently supported.
595604

605+
#### Notation
606+
607+
The `notation` provider can be used to verify the signature of an OCI artifact using known
608+
trust policy and CA certificate.
609+
610+
```yaml
611+
---
612+
apiVersion: source.toolkit.fluxcd.io/v1beta2
613+
kind: OCIRepository
614+
metadata:
615+
name: <repository-name>
616+
spec:
617+
verify:
618+
provider: notation
619+
secretRef:
620+
name: notation-config
621+
```
622+
623+
When the verification succeeds, the controller adds a Condition with the
624+
following attributes to the OCIRepository's `.status.conditions`:
625+
626+
- `type: SourceVerified`
627+
- `status: "True"`
628+
- `reason: Succeeded`
629+
630+
To verify the authenticity of an OCI artifact, create a Kubernetes secret
631+
containing Certificate Authority (CA) root certificates and the a `trust policy`
632+
633+
```yaml
634+
---
635+
apiVersion: v1
636+
kind: Secret
637+
metadata:
638+
name: notation-config
639+
type: Opaque
640+
data:
641+
certificate1.pem: <BASE64>
642+
certificate2.crt: <BASE64>
643+
trustpolicy.json: <BASE64>
644+
```
645+
646+
Note that the CA certificates must have either `.pem` or `.crt` extension and your trust policy must
647+
be named `trustpolicy.json` for Flux to make use of them.
648+
649+
For more information on the signing and verification process see [Signing and Verification Workflow](https://github.com/notaryproject/specifications/blob/v1.0.0/specs/signing-and-verification-workflow.md).
650+
651+
Flux will loop over the certificates and use them to verify an artifact's signature.
652+
This allows for older artifacts to be valid as long as the right certificate is in the secret.
653+
596654
### Suspend
597655

598656
`.spec.suspend` is an optional field to suspend the reconciliation of a

go.mod

+10-1
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,12 @@ require (
4444
github.com/google/go-containerregistry/pkg/authn/k8schain v0.0.0-20231202142526-55ffb0092afd
4545
github.com/google/uuid v1.6.0
4646
github.com/minio/minio-go/v7 v7.0.66
47+
github.com/notaryproject/notation-core-go v1.0.2
48+
github.com/notaryproject/notation-go v1.1.0
4749
github.com/onsi/gomega v1.31.1
4850
github.com/opencontainers/go-digest v1.0.0
4951
github.com/opencontainers/go-digest/blake3 v0.0.0-20231025023718-d50d2fec9c98
52+
github.com/opencontainers/image-spec v1.1.0
5053
github.com/ory/dockertest/v3 v3.10.0
5154
github.com/otiai10/copy v1.14.0
5255
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5
@@ -64,6 +67,7 @@ require (
6467
k8s.io/apimachinery v0.28.6
6568
k8s.io/client-go v0.28.6
6669
k8s.io/utils v0.0.0-20231127182322-b307cd553661
70+
oras.land/oras-go/v2 v2.3.1
6771
sigs.k8s.io/controller-runtime v0.16.3
6872
sigs.k8s.io/yaml v1.4.0
6973
)
@@ -87,6 +91,7 @@ require (
8791
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
8892
github.com/Azure/go-autorest/logger v0.2.1 // indirect
8993
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
94+
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
9095
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 // indirect
9196
github.com/BurntSushi/toml v1.3.2 // indirect
9297
github.com/MakeNowJust/heredoc v1.0.0 // indirect
@@ -169,11 +174,14 @@ require (
169174
github.com/fluxcd/gitkit v0.6.0 // indirect
170175
github.com/fluxcd/pkg/apis/acl v0.1.0 // indirect
171176
github.com/fsnotify/fsnotify v1.7.0 // indirect
177+
github.com/fxamacker/cbor/v2 v2.5.0 // indirect
178+
github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect
172179
github.com/go-chi/chi v4.1.2+incompatible // indirect
173180
github.com/go-errors/errors v1.5.1 // indirect
174181
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
175182
github.com/go-gorp/gorp/v3 v3.1.0 // indirect
176183
github.com/go-jose/go-jose/v3 v3.0.1 // indirect
184+
github.com/go-ldap/ldap/v3 v3.4.6 // indirect
177185
github.com/go-logr/stdr v1.2.2 // indirect
178186
github.com/go-logr/zapr v1.3.0 // indirect
179187
github.com/go-openapi/analysis v0.22.0 // indirect
@@ -265,7 +273,6 @@ require (
265273
github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 // indirect
266274
github.com/oklog/ulid v1.3.1 // indirect
267275
github.com/oleiade/reflections v1.0.1 // indirect
268-
github.com/opencontainers/image-spec v1.1.0-rc5 // indirect
269276
github.com/opencontainers/runc v1.1.5 // indirect
270277
github.com/opentracing/opentracing-go v1.2.0 // indirect
271278
github.com/pborman/uuid v1.2.1 // indirect
@@ -312,6 +319,8 @@ require (
312319
github.com/tjfoc/gmsm v1.4.1 // indirect
313320
github.com/transparency-dev/merkle v0.0.2 // indirect
314321
github.com/vbatts/tar-split v0.11.5 // indirect
322+
github.com/veraison/go-cose v1.2.0 // indirect
323+
github.com/x448/float16 v0.8.4 // indirect
315324
github.com/xanzy/go-gitlab v0.96.0 // indirect
316325
github.com/xanzy/ssh-agent v0.3.3 // indirect
317326
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect

0 commit comments

Comments
 (0)