Files

Public keys

Chart signing key

.gitea/workflows/release-chart.yaml runs helm package --sign to produce a .tgz.prov file for every chart release, and charts/aptly/Chart.yaml carries an artifacthub.io/signKey annotation pointing at chart-signing.asc in this directory (fingerprint FC35C0FAA26605C4C21C7BBFBF43884145E5AA94). The matching private key is stored as the GPG_PRIVATE_KEY/GPG_PASSPHRASE/GPG_KEY_ID secrets in this repo's Gitea settings.

This key must NOT be Ed25519/EdDSA. Helm's chart signing is built on the deprecated golang.org/x/crypto/openpgp library, which cannot read Ed25519 keys at all — signing fails with Error: private key not found (or, depending on gpg version, openpgp: unsupported feature: public key type: 22). This is a long-standing, unresolved upstream limitation (helm/helm#11634, #31180, #31181), not a configuration mistake — confirmed by reproducing it locally against a throwaway Ed25519 test key before writing this note. Use RSA (4096-bit, no expiry is fine for a CI signing key) or a classic ECC curve helm's openpgp fork supports; RSA is the safest choice since it's unambiguously supported.

The org's existing "Morlana CI Signing Key" (used by e.g. bookstack-chart) is Ed25519 and was tried here first — it does not work for this purpose. It may still be perfectly valid for other things (signing an actual apt repository via aptly.gpg.signingKey, which is a completely different code path that does support Ed25519 — see docs/packaging.md — just not for helm package --sign. This repo therefore needs its own, separate, RSA key dedicated to chart-package signing.

Generating a replacement (e.g. on rotation)

Run this yourself (locally, not in CI) so the private key material never has to pass through anything but your own machine and the Gitea secrets store:

gpg --full-generate-key
# RSA and RSA (default)
# 4096 bit
# key does not expire (or a long expiry — a CI signing key you'd have to rotate
# on a schedule is more operational overhead than it's worth here)
# Name: Aptly Chart Signing Key
# Email: something you control, e.g. contact+development@morlana.net

gpg --list-secret-keys --with-colons | awk -F: '$1=="sec"{print $5}'   # -> the key ID
gpg --armor --export <key-id> > pubkeys/chart-signing.asc
gpg --armor --export-secret-keys <key-id>                              # -> paste as GPG_PRIVATE_KEY

Then, in the repo's Gitea settings, update:

  • Secret GPG_PRIVATE_KEY — the armored output of the last command above
  • Secret GPG_PASSPHRASE — whatever passphrase you set (empty string if none)
  • Secret GPG_KEY_ID — the key ID or fingerprint from gpg --list-secret-keys

Commit the new pubkeys/chart-signing.asc over the old one, and update the fingerprint in the artifacthub.io/signKey annotation in charts/aptly/Chart.yaml.

Verifying a downloaded chart

gpg --import pubkeys/chart-signing.asc
gpg --export > /tmp/pubring.gpg   # legacy binary format — helm can't read pubring.kbx
helm verify aptly-<version>.tgz --keyring /tmp/pubring.gpg