mirror of https://github.com/fluxcd/flux2.git
				
				
				
			
			You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			283 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			Markdown
		
	
			
		
		
	
	
			283 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			Markdown
		
	
# RFC-0002 Flux OCI support for Helm
 | 
						|
 | 
						|
**Status:** implemented (partially)
 | 
						|
 | 
						|
**Creation date:** 2022-03-30
 | 
						|
 | 
						|
**Last update:** 2023-11-28
 | 
						|
 | 
						|
## Summary
 | 
						|
 | 
						|
Given that Helm v3.8 supports [OCI](https://helm.sh/docs/topics/registries/) for package distribution,
 | 
						|
we should extend the Flux Source API to allow fetching Helm charts from container registries.
 | 
						|
 | 
						|
## Motivation
 | 
						|
 | 
						|
Helm OCI support is one of the most requested feature in Flux
 | 
						|
as seen on this [issue](https://github.com/fluxcd/source-controller/issues/124).
 | 
						|
 | 
						|
With OCI support, Flux users can automate chart updates to Git in the same way
 | 
						|
they do today for container images.
 | 
						|
 | 
						|
### Goals
 | 
						|
 | 
						|
- Add support for fetching Helm charts stored as OCI artifacts with minimal API changes to Flux.
 | 
						|
- Add support for verifying the authenticity of Helm OCI charts signed with Cosign.
 | 
						|
- Make it easy for users to switch from [HTTP/S Helm repositories](https://github.com/helm/helm-www/blob/416fabea6ffab8dc156b6a0c5eb5e8df5f5ef7dc/content/en/docs/topics/chart_repository.md)
 | 
						|
  to OCI repositories.
 | 
						|
 | 
						|
### Non-Goals
 | 
						|
 | 
						|
- Introduce a new API kind for referencing charts stored as OCI artifacts.
 | 
						|
 | 
						|
## Proposal
 | 
						|
 | 
						|
Introduce an optional field called `type` to the `HelmRepository` spec.
 | 
						|
When not specified, the `spec.type` field defaults to `default` which preserve the current `HelmRepository` API behaviour.
 | 
						|
When the `spec.type` field is set to `oci`, the `spec.url` field must be prefixed with `oci://` (to follow the Helm conventions).
 | 
						|
For `oci://` URLs, source-controller will use the Helm SDK and the `oras` library to connect to the OCI remote storage.
 | 
						|
 | 
						|
Introduce an optional field called `provider` for
 | 
						|
[context-based authorization](https://fluxcd.io/flux/security/contextual-authorization/)
 | 
						|
to AWS, Azure and Google Cloud. The `spec.provider` is ignored when `spec.type` is set to `default`.
 | 
						|
 | 
						|
### Pull charts from private repositories
 | 
						|
 | 
						|
#### Basic auth
 | 
						|
 | 
						|
For private repositories hosted on GitHub, Quay, self-hosted Docker Registry and others,
 | 
						|
the credentials can be supplied with:
 | 
						|
 | 
						|
```yaml
 | 
						|
apiVersion: source.toolkit.fluxcd.io/v1beta2
 | 
						|
kind: HelmRepository
 | 
						|
metadata:
 | 
						|
  name: <repo-name>
 | 
						|
spec:
 | 
						|
  type: oci
 | 
						|
  secretRef:
 | 
						|
    name: regcred
 | 
						|
```
 | 
						|
 | 
						|
The `secretRef` points to a Kubernetes secret in the same namespace as the `HelmRepository`.
 | 
						|
The [secret type](https://kubernetes.io/docs/concepts/configuration/secret/#secret-types)
 | 
						|
must be `kubernetes.io/dockerconfigjson`:
 | 
						|
 | 
						|
```shell
 | 
						|
kubectl create secret docker-registry regcred \
 | 
						|
  --docker-server=<your-registry-server> \
 | 
						|
  --docker-username=<your-name> \
 | 
						|
  --docker-password=<your-pword>
 | 
						|
```
 | 
						|
 | 
						|
#### OIDC auth
 | 
						|
 | 
						|
When Flux runs on AKS, EKS or GKE, an IAM role (that grants read-only access to ACR, ECR or GCR)
 | 
						|
can be used to bind the `source-controller` to the IAM role.
 | 
						|
 | 
						|
```yaml
 | 
						|
apiVersion: source.toolkit.fluxcd.io/v1beta2
 | 
						|
kind: HelmRepository
 | 
						|
metadata:
 | 
						|
  name: <repo-name>
 | 
						|
spec:
 | 
						|
  type: oci
 | 
						|
  provider: azure
 | 
						|
```
 | 
						|
 | 
						|
The provider accepts the following values: `generic`, `aws`, `azure` and `gcp`. When the provider is
 | 
						|
not specified, it defaults to `generic`. When the provider is set to `aws`, `azure` or `gcp`, the
 | 
						|
controller will use a specific cloud SDK for authentication purposes.
 | 
						|
 | 
						|
If both `spec.secretRef` and a non-generic provider are present in the definition,
 | 
						|
the controller will use the static credentials from the referenced secret.
 | 
						|
 | 
						|
### Verify Helm charts
 | 
						|
 | 
						|
To verify the authenticity of the Helm OCI charts, Flux will use the Sigstore Go SDK and implement verification
 | 
						|
for artifacts which were either signed with keys generated by Cosign or signed using the Cosign
 | 
						|
[keyless method](https://github.com/sigstore/cosign/blob/main/KEYLESS.md).
 | 
						|
 | 
						|
To enable signature verification, the Cosign public keys can be supplied with:
 | 
						|
 | 
						|
```yaml
 | 
						|
apiVersion: source.toolkit.fluxcd.io/v1beta2
 | 
						|
kind: HelmChart
 | 
						|
metadata:
 | 
						|
  name: <chart-name>
 | 
						|
spec:
 | 
						|
  verify:
 | 
						|
    provider: cosign
 | 
						|
    secretRef:
 | 
						|
      name: cosign-public-keys
 | 
						|
```
 | 
						|
 | 
						|
Note that the Kubernetes secret containing the Cosign public keys, must use `.pub` extension:
 | 
						|
 | 
						|
```yaml
 | 
						|
apiVersion: v1
 | 
						|
kind: Secret
 | 
						|
metadata:
 | 
						|
  name: cosign-public-keys
 | 
						|
type: Opaque
 | 
						|
stringData:
 | 
						|
  key1.pub: <pub-key-1>
 | 
						|
  key2.pub: <pub-key-2>
 | 
						|
```
 | 
						|
 | 
						|
For verifying public Helm charts which are signed using the keyless method,
 | 
						|
the `spec.verify.secretRef` field must be omitted:
 | 
						|
 | 
						|
```yaml
 | 
						|
spec:
 | 
						|
  verify:
 | 
						|
    provider: cosign
 | 
						|
```
 | 
						|
 | 
						|
When using the keyless method, Flux will verify the signatures in the Rekor
 | 
						|
transparency log instance hosted at [rekor.sigstore.dev](https://rekor.sigstore.dev/).
 | 
						|
 | 
						|
### User Stories
 | 
						|
 | 
						|
#### Story 1
 | 
						|
 | 
						|
> As a developer I want to use Flux `HelmReleases` that refer to Helm charts stored
 | 
						|
> as OCI artifacts in GitHub Container Registry.
 | 
						|
 | 
						|
First create a secret using a GitHub token that allows access to GHCR:
 | 
						|
 | 
						|
```sh
 | 
						|
kubectl create secret docker-registry ghcr-charts \
 | 
						|
    --docker-server=ghcr.io \
 | 
						|
    --docker-username=$GITHUB_USER \
 | 
						|
    --docker-password=$GITHUB_TOKEN
 | 
						|
```
 | 
						|
 | 
						|
Then define a `HelmRepository` of type `oci` and reference the `dockerconfig` secret:
 | 
						|
 | 
						|
```yaml
 | 
						|
apiVersion: source.toolkit.fluxcd.io/v1beta2
 | 
						|
kind: HelmRepository
 | 
						|
metadata:
 | 
						|
  name: ghcr-charts
 | 
						|
  namespace: default
 | 
						|
spec:
 | 
						|
  type: oci
 | 
						|
  url: oci://ghcr.io/my-org/charts/
 | 
						|
  secretRef:
 | 
						|
    name: ghcr-charts
 | 
						|
```
 | 
						|
 | 
						|
And finally in Flux `HelmReleases`, refer to the ghcr-charts `HelmRepository`:
 | 
						|
 | 
						|
```yaml
 | 
						|
apiVersion: helm.toolkit.fluxcd.io/v2beta1
 | 
						|
kind: HelmRelease
 | 
						|
metadata:
 | 
						|
  name: my-app
 | 
						|
  namespace: default
 | 
						|
spec:
 | 
						|
  interval: 60m
 | 
						|
  chart:
 | 
						|
    spec:
 | 
						|
      chart: my-app
 | 
						|
      version: '1.0.x'
 | 
						|
      sourceRef:
 | 
						|
        kind: HelmRepository
 | 
						|
        name: ghcr-charts
 | 
						|
      interval: 1m # check for new OCI artifacts every minute
 | 
						|
```
 | 
						|
 | 
						|
#### Story 2
 | 
						|
 | 
						|
> As a platform admin I want to automate Helm chart updates based on a semver ranges.
 | 
						|
> When a new patch version is available in the container registry, I want Flux to open a PR
 | 
						|
> with the version set in the `HelmRelease` manifests.
 | 
						|
 | 
						|
Given that charts are stored in container registries, you can use Flux image automation
 | 
						|
and patch the chart version in Git, in the same way Flux works for updating container image tags.
 | 
						|
 | 
						|
Define an image registry and a policy for the chart artifact:
 | 
						|
 | 
						|
```yaml
 | 
						|
apiVersion: image.toolkit.fluxcd.io/v1beta1
 | 
						|
kind: ImageRepository
 | 
						|
metadata:
 | 
						|
  name: my-app
 | 
						|
  namespace: default
 | 
						|
spec:
 | 
						|
  image: ghcr.io/my-org/charts/my-app
 | 
						|
  interval: 1m0s
 | 
						|
---
 | 
						|
apiVersion: image.toolkit.fluxcd.io/v1beta1
 | 
						|
kind: ImagePolicy
 | 
						|
metadata:
 | 
						|
  name: my-app
 | 
						|
  namespace: default
 | 
						|
spec:
 | 
						|
  imageRepositoryRef:
 | 
						|
    name: my-app
 | 
						|
  policy:
 | 
						|
    semver:
 | 
						|
      range: 1.0.x
 | 
						|
```
 | 
						|
 | 
						|
Then add the policy marker to the `HelmRelease` manifests in Git:
 | 
						|
 | 
						|
```yaml
 | 
						|
apiVersion: helm.toolkit.fluxcd.io/v2beta1
 | 
						|
kind: HelmRelease
 | 
						|
metadata:
 | 
						|
  name: my-app
 | 
						|
  namespace: default
 | 
						|
spec:
 | 
						|
  interval: 60m
 | 
						|
  chart:
 | 
						|
    spec:
 | 
						|
      chart: my-app
 | 
						|
      version: 1.0.0 # {"$imagepolicy": "default:my-app:tag"}
 | 
						|
      sourceRef:
 | 
						|
        kind: HelmRepository
 | 
						|
        name: ghcr-charts
 | 
						|
      interval: 1m
 | 
						|
```
 | 
						|
 | 
						|
### Alternatives
 | 
						|
 | 
						|
We could introduce a new API type e.g. `HelmRegistry` to hold the reference to auth secret,
 | 
						|
as proposed in [#2573](https://github.com/fluxcd/flux2/pull/2573).
 | 
						|
That is considered unpractical, as there is no benefit for users in having a dedicated kind instead of
 | 
						|
a `type` field in the current `HelmRepository` API. Adding a `type` field to the spec follows the Flux
 | 
						|
Bucket API design, where the same Kind servers different implementations: AWS S3 vs Azure Blob vs Google Storage.
 | 
						|
 | 
						|
## Design Details
 | 
						|
 | 
						|
Unlike the default `HelmRepository`, the OCI `HelmRepository` does not need to
 | 
						|
download any repository index file. The associated HelmChart can pull the chart
 | 
						|
directly from the OCI registry based on the registry information in the
 | 
						|
`HelmRepository` object. This makes the `HelmRepository` of type `oci` static,
 | 
						|
not backed by a reconciler to move to a desired state. It becomes a data
 | 
						|
container with information about the OCI registry.
 | 
						|
 | 
						|
In source-controller, the `HelmRepositoryReconciler` will be updated to check
 | 
						|
the `.spec.type` field of `HelmRepository` and do nothing if it is `oci`.
 | 
						|
 | 
						|
The current `HelmChartReconciler` will be adapted to handle both types.
 | 
						|
 | 
						|
### Enabling the feature
 | 
						|
 | 
						|
The feature is enabled by default.
 | 
						|
 | 
						|
## Implementation History
 | 
						|
 | 
						|
* **2022-05-19** Partially implemented by [source-controller#690](https://github.com/fluxcd/source-controller/pull/690)
 | 
						|
* **2022-06-06** First implementation released with [flux2 v0.31.0](https://github.com/fluxcd/flux2/releases/tag/v0.31.0)
 | 
						|
* **2022-08-11** Resolve chart dependencies from OCI released with [flux2 v0.32.0](https://github.com/fluxcd/flux2/releases/tag/v0.32.0)
 | 
						|
* **2022-08-29** Contextual login for AWS, Azure and GCP released with [flux2 v0.33.0](https://github.com/fluxcd/flux2/releases/tag/v0.33.0)
 | 
						|
* **2022-10-21** Verifying Helm charts with Cosign released with [flux2 v0.36.0](https://github.com/fluxcd/flux2/releases/tag/v0.36.0)
 | 
						|
* **2023-11-28** Update the design of HelmRepository of type OCI to be static object [flux2 v2.2.0](https://github.com/fluxcd/flux2/releases/tag/v2.2.0)
 | 
						|
 | 
						|
### TODOs
 | 
						|
 | 
						|
* [Add support for container registries with self-signed TLS certs](https://github.com/fluxcd/source-controller/issues/723)
 |