Skip to content

Backends and the per-provider module pattern

signing defines the signing mechanics and the Backend contract; the actual keys live behind backends. A Backend produces a crypto.Signer for a held key:

type Backend interface {
    Name() string
    NewSigner(ctx context.Context, keyID string) (crypto.Signer, error)
}

The library ships one backend, local (PEM on disk), as a light default and reference. Every other backend lives in its own module and is activated by a blank import.

Available backends

Backend name Module Keys keyID is How-to
local gitlab.com/phpboyscout/go/signing/local (in this module) Unencrypted PEM on disk: RSA (PKCS#1 or PKCS#8) or Ed25519 (PKCS#8) a filesystem path Sign with the local backend
aws-kms gitlab.com/phpboyscout/go/signing-aws-kms RSA_4096 SIGN_VERIFY, or ECC_NIST_EDWARDS25519 a key ARN or alias Sign with AWS KMS

Both backends carry both key families for the same reason: RSA drives the OpenPGP manifest path and Ed25519 drives the minisign artefact path. A backend does not choose between them; the signing package you hand the signer to does.

No other provider backend exists yet. GCP KMS, Azure Key Vault or HashiCorp Vault would follow the same pattern; to build one, see Implement a custom backend.

Why a module per provider

A module's go.mod require list enters the module graph of every consumer that imports a package from it. If every backend lived here (or in one multi-cloud module), every consumer would inherit every cloud SDK as a requirement. Separate per-provider modules quarantine each SDK, so a consumer pulls only what it uses:

Consumer Imports Cloud SDKs pulled
verify-only signing/verify none
an AWS signer signing + signing-aws-kms AWS only
a multi-provider tool signing + each backend module each, by choice

Using a backend

Blank-import to register, then resolve by name:

import (
    "gitlab.com/phpboyscout/go/signing"
    _ "gitlab.com/phpboyscout/go/signing-aws-kms" // registers "aws-kms"
)

backend, _ := signing.Get("aws-kms")
signer, _ := backend.NewSigner(ctx, keyARNorAlias)

Both backends also register a factory, so one binary can hold several named instances of a type (aws-kms:prod beside aws-kms:staging) through signing.NewInstance. The registry checks only the shape of an instance's name; giving each instance its own settings is the backend's and the CLI's business. See the backend registry.

To add your own, see Implement a custom backend. signing-aws-kms is the worked example of a backend in its own module.