Sign with the local backend¶
Sign a checksums manifest using a private key held in a PEM file on disk, via
the reference local backend. This is the library path; in production, release
signing is normally driven by a CLI such as gtb sign, which wraps these same
calls.
The local backend is the lightweight default, meant for onboarding, local
development and reproducible examples. A private key on disk is a weaker
posture than a KMS or HSM, so for production use
AWS KMS or
implement a custom backend for your own KMS
or HSM.
Activate the backend¶
Backends register themselves on import. Blank-import the local package so its
init() registers the name "local":
import (
"context"
"gitlab.com/phpboyscout/go/signing"
_ "gitlab.com/phpboyscout/go/signing/local" // registers "local"
"gitlab.com/phpboyscout/go/signing/openpgpkey"
)
Point at a PEM key¶
Generate (or reuse) an unencrypted RSA private key of at least 3072 bits:
The keyID you pass to the local backend is simply the path to this PEM
file.
Supported formats:
- PKCS#1,
RSA PRIVATE KEYarmour (RSA) - PKCS#8,
PRIVATE KEYarmour (RSA, ECDSA P-256 or Ed25519) - SEC 1,
EC PRIVATE KEYarmour (ECDSA P-256)
Three key types, matching the signing paths:
| Key type | Path |
|---|---|
| RSA | OpenPGP signing of checksum manifests |
| Ed25519 | minisign artefact signing, which is what the Rust consumers verify |
| ECDSA P-256 | container image signing in the cosign formats |
Ed25519 support is what makes the artefact path usable without an HSM, so you can try it, test it, or run it in a project that has no cloud KMS at all.
Limitations (all surface as typed sentinels from the local package):
- Encrypted PEM is unsupported (
local.ErrEncryptedPEMUnsupported). Decrypt out of band first, or use a KMS or HSM backend. - Only RSA, ECDSA P-256 and Ed25519 are supported. Anything else (ECDSA
on P-384, for instance) returns
local.ErrUnsupportedKeyType. P-256 is read from PKCS#8 or from a SEC 1EC PRIVATE KEYblock. - An armored OpenPGP secret key is refused (
local.ErrOpenPGPSecretKey).keys generate --algorithm ed25519writes one by default; add--private-format pemto get a private half this backend reads. - A file with no PEM block, or with a PEM block of an unrecognised type,
yields
local.ErrMissingPEMBlock. - The path is read as given: symlinks are followed and nothing is canonicalised. Fine for an operator-supplied path, worth knowing if it could come from anywhere less trusted.
A key on disk is a key that can be copied. This backend is for tutorials, tests, and projects without an HSM; where custody matters, use
aws-kms.
Resolve, sign, publish¶
Resolve the backend through the registry, build a crypto.Signer from the PEM
path, then mint the public key and sign the manifest:
backend, err := signing.Get("local") // requires the blank import above
if err != nil {
return err // e.g. signing.ErrUnknownBackend if not imported
}
signer, err := backend.NewSigner(context.Background(), "release.pem") // keyID = PEM path
if err != nil {
return err // e.g. local.ErrEncryptedPEMUnsupported
}
now := time.Now()
pub, err := openpgpkey.ArmoredPublicKey(signer, "Release", "release@example.test", now)
if err != nil {
return err
}
manifest := []byte("sha256 ffmpeg.wasm 0xc0ffee\n")
sig, err := openpgpkey.DetachSign(signer, pub, bytes.NewReader(manifest), now)
if err != nil {
return err
}
// publish: manifest, sig (ASCII-armoured detached signature), and pub
Ship manifest, sig, and pub with your release assets. Consumers embed
pub and run the verify recipe.
ArmoredPublicKey and DetachSign take any crypto.Signer, so the same code
signs whether the key lives in a PEM file or a remote KMS. Only the backend
differs.
Run a named instance¶
The local package also registers a factory, so signing.NewInstance("local",
"staging") returns a backend named local:staging. It reads keys exactly as
the default does; local carries no per-instance settings, and the factory
exists so a CLI can treat every backend type the same way. NewInstance does
not register what it returns. See
the backend registry.
See also¶
- Sign artefacts with minisign: what the Ed25519 half of this backend is for.
- Implement a custom backend, for KMS or HSM signing in production.
- The backend registry:
Get,Names, named instances, and whatkeyIDmeans per backend. - Dependency inversion: why backends are injected rather than bundled.
- The full API and runnable
Exampletests: pkg.go.dev/gitlab.com/phpboyscout/go/signing/local.