PoC To Create A Keyless Signed OCI Helm Chart

PoC To Create A Keyless Signed OCI Helm Chart

PoC To Create A Keyless Signed OCI Helm Chart

TL;DR Code



  • CR_PAT for the GitHub container registry

See this guide for more information on how to create a personal access token.


Task is a task runner / build tool that aims to be simpler and easier to use than, for example, GNU Make.

Since it’s written in Go, Task is just a single binary and has no other dependencies, which means you don’t need to mess with any complicated install setups just to use a build tool.

Once installed, you just need to describe your build tasks using a simple YAML schema in a file called Taskfile.yml:

Our Taskfile.yml file looks like this:

version: '3'

      - echo "Purging..."
      - rm -rf dist

      - purge
      - mkdir dist
      - echo $CR_PAT | helm registry login ghcr.io --username $OWNER --password-stdin
      - helm package signed-helm-chart --destination dist
      - helm push dist/signed-helm-chart-*.tgz oci://ghcr.io/dirien/ > .digest
      - cosign sign ghcr.io/dirien/signed-helm-chart@$(cat .digest | awk -F "[, ]+" '/Digest/{print $NF}')

And has a purge and default task inside.


Helm 3 supports OCI for package distribution. Chart packages are able to be stored and shared across OCI-based registries.

Enabling OCI Support Currently OCI support is considered experimental.

In order to use the commands described below, please set HELM_EXPERIMENTAL_OCI in the environment:


We're going to use helm package to create a the chart package and with helm push to push it to the OCI registry. In this case , we will use ghcr.io as the registry.


To use cosign to sign keyless our OCI chart, we need to create set COSIGN_EXPERIMENTAL in the environment of our Taskfile.yml task default and of course have the cosign binary installed.

GitHub Action

To use keyless signing in GitHub Actions, we need do following steps:

Step 1: Enable OCI Support

Add permissions to add id-token to the permissions section.

  id-token: write

Step 2: Install Cosign

Just add this GitHub Action to your workflow:

- name: Install cosign
  uses: sigstore/cosign-installer@v1.4.1
    cosign-release: 'v1.4.1'

Step 3: Call the Taskfile

To build and sign our chart, we need to call the Taskfile.yml file in the GitHub Action. Just add this GitHub to your workflow:

- name: Build the helm chart and sign the oci image
  run: task
    CR_PAT: ${{ secrets.CR_PAT }}
    OWNER: ${{ github.repository_owner }}


If everything works, you should see the following output:

Run task
task: [purge] echo "Purging..."
task: [purge] rm -rf dist
task: [default] mkdir dist
task: [default] echo $CR_PAT | helm registry login ghcr.io --username $OWNER --password-stdin
Login Succeeded
task: [default] helm package signed-helm-chart --destination dist
Successfully packaged chart and saved it to: dist/signed-helm-chart-0.1.0.tgz
task: [default] helm push dist/signed-helm-chart-*.tgz oci://ghcr.io/dirien/ > .digest
task: [default] cat .digest | awk -F "[, ]+" '/Digest/{print $NF}'
task: [default] cosign sign ghcr.io/dirien/signed-helm-chart@$(cat .digest | awk -F "[, ]+" '/Digest/{print $NF}')
Generating ephemeral keys...
Retrieving signed certificate...
client.go:196: root pinning is not supported in Spec 1.0.19
Successfully verified SCT...
tlog entry created with index: 955563
Pushing signature to: ghcr.io/dirien/signed-helm-chart

Open Points - Helm Provenance and Integrity

What we need to improve now is: helm verify needs to check that the chart been signed and is valid.

Currently, Helm does not support the cosign to verify the signature of the chart.

See the documentation about the supported Helm Provenance and Integrity mechanisms.