Documentation
¶
Overview ¶
Package kms is the AWS KMS backend for pkg/signing. Blank-import to activate; the init() call registers the backend under the name "aws-kms" against pkg/signing's global registry.
import _ "gitlab.com/phpboyscout/go/signing/kms"
The backend wraps a KMS-held asymmetric signing key as a crypto.Signer. The private half never leaves AWS — every signing operation is a remote kms:Sign call.
Two key types are supported, serving two different release paths:
- **RSA SIGN_VERIFY** — drives pkg/openpgpkey to mint an OpenPGP-armored public key and sign the checksums manifest.
- **ECC_NIST_EDWARDS25519** — signs release artefacts for the Rust consumers, which speak minisign rather than OpenPGP. Hash the artefact first and sign the digest: KMS caps its Sign message at 4096 bytes, so a multi-MB archive can never be the message. go/signing's minisign package does this, and the resulting HSM custody is identical to the RSA key's — the private half never materialises.
Ed25519 keys are not usable with pkg/openpgpkey: go-crypto's OpenPGP Ed25519 branch requires a concrete *ed25519.PrivateKey and offers no crypto.Signer fall-through, so it cannot be driven by an opaque KMS signer at all.
The AWS configuration is resolved by go/awsclient, and its lifecycle by go/clientlifecycle — one implementation for the estate rather than a copy per adapter (org spec 0003). The default rung resolves PER CALL and holds no credentials between mints (0003 P-12): one kms:Sign per mint, nothing retained. A consumer that already holds a config, a client, or a shared resolver injects it through the ladder rather than resolving again.
Backend-specific CLI flag:
--kms-region <region> AWS region. Default: eu-west-2.
The default is applied as an explicit region, so AWS_REGION and the shared config's region are not consulted. Name another with --kms-region or WithRegion, or inject a resolved config with NewFromConfig or NewFromSource.
Credentials are resolved from the AWS SDK default chain (env vars / ~/.aws/credentials / IAM Roles Anywhere / OIDC web identity). Users with multiple profiles can either set AWS_PROFILE before invoking the minter or assume a role explicitly via `aws sts assume-role` and export the resulting credentials.
Example ¶
Example shows that blank-importing this module registers the "aws-kms" backend with the signing registry, so it can be resolved by name. From the resolved Backend, NewSigner(ctx, keyID) returns a crypto.Signer over a KMS RSA SIGN_VERIFY key (keyID is the key ARN or alias) — that call needs AWS credentials, so it is shown in the how-to rather than run here.
package main
import (
"fmt"
"gitlab.com/phpboyscout/go/signing"
_ "gitlab.com/phpboyscout/go/signing-aws-kms"
)
func main() {
backend, err := signing.Get("aws-kms")
if err != nil {
panic(err)
}
fmt.Println(backend.Name())
}
Output: aws-kms
Index ¶
- Constants
- Variables
- func New(opts ...Option) signing.Backend
- func NewDefault(name string, opts ...Option) (signing.Backend, error)
- func NewFromClient(name string, client kmsClient, opts ...Option) (signing.Backend, error)
- func NewFromConfig(name string, cfg aws.Config, opts ...Option) (signing.Backend, error)
- func NewFromSource(name string, src configSource, opts ...Option) (signing.Backend, error)
- func NewSigner(ctx context.Context, region, keyID string, opts ...Option) (crypto.Signer, error)
- type Option
Examples ¶
Constants ¶
const ( // BackendName is the identifier the zero-conf default registers under, and // the one a caller selects this backend by with "--backend aws-kms". BackendName = "aws-kms" )
Variables ¶
var ( // ErrUnsupportedKMSKeyType is returned by NewSigner when the KMS // key's public half is neither RSA nor Ed25519 — for instance one // of the ECC_NIST_P* curves. ErrUnsupportedKMSKeyType = errors.NewSentinel("signing-aws-kms.unsupported_k_m_s_key_type", "KMS key is neither RSA nor Ed25519; only RSA SIGN_VERIFY and ECC_NIST_EDWARDS25519 keys are supported") // ErrKeyUnusable is returned by NewSigner when the KMS key's // KeyUsage is not SIGN_VERIFY. An RSA ENCRYPT_DECRYPT key parses // exactly like a signing key and would otherwise fail per signature. ErrKeyUnusable = errors.NewSentinel("signing-aws-kms.key_unusable", "KMS key usage is not SIGN_VERIFY") // ErrKeyRotated is returned by Sign when KMS reports signing with a // different key than the one Public() was resolved from, as happens // when an alias is repointed. Mint a new signer. ErrKeyRotated = errors.NewSentinel("signing-aws-kms.key_rotated", "KMS signed with a different key than the signer resolved") // ErrUnsupportedHashFunc is returned by the signer when the // caller requests a hash function KMS RSA Sign does not map to. ErrUnsupportedHashFunc = errors.NewSentinel("signing-aws-kms.unsupported_hash_func", "unsupported hash function; KMS RSA Sign accepts SHA-256 / 384 / 512 only") // ErrEd25519RequiresUnhashed is returned when a caller asks an // Ed25519 signer for a pre-hashed signature. EdDSA signs the // message itself, so the standard library's convention is // crypto.Hash(0); honouring any other hash would sign the wrong // bytes. ErrEd25519RequiresUnhashed = errors.NewSentinel("signing-aws-kms.ed25519_requires_unhashed", "Ed25519 signing requires crypto.Hash(0) — EdDSA signs the message, not a digest") // ErrMessageTooLarge is returned when an Ed25519 Sign call's // message exceeds the KMS Sign API's 4096-byte cap. Sign a digest // of the artefact instead of the artefact itself. ErrMessageTooLarge = errors.NewSentinel("signing-aws-kms.message_too_large", "message exceeds the KMS Sign 4096-byte limit; sign a digest instead") // ErrUnexpectedSignatureEncoding is returned when KMS returns an // Ed25519 signature that is not the raw 64-byte form every // consumer requires. ErrUnexpectedSignatureEncoding = errors.NewSentinel("signing-aws-kms.unexpected_signature_encoding", "KMS returned a non-raw Ed25519 signature") // ErrPSSUnsupported is returned by the signer when the caller requests // RSASSA-PSS via *rsa.PSSOptions. This backend only implements // RSASSA-PKCS1-v1_5; it refuses rather than silently downgrading the // signature scheme behind the caller's back. ErrPSSUnsupported = errors.NewSentinel("signing-aws-kms.p_s_s_unsupported", "RSASSA-PSS is not supported; this KMS signer only implements RSASSA-PKCS1-v1_5") // ErrNotConfigured is returned by the ladder constructors for a wiring // fault caught at construction: an empty backend name, a nil client, a // nil source, or a config with no region. ErrNotConfigured = errors.NewSentinel("signing-aws-kms.not_configured", "aws-kms backend is not configured") )
Exported sentinel errors so callers (and tests) can errors.Is against specific failure modes.
Functions ¶
func New ¶
New constructs the AWS KMS Backend with the supplied options, named "aws-kms" and resolving its configuration per call from the ambient chain. Importing this package has already registered an "aws-kms" default, and signing.Register panics on a duplicate, so use the result directly:
backend := awskms.New(awskms.WithRegion("us-east-1"), awskms.WithLogger(l))
It is the NewDefault rung under the fixed name; a caller who needs a differently named instance, or to supply its own client, config or shared resolver, uses the ladder directly.
func NewDefault ¶ added in v0.5.0
NewDefault builds a named backend that resolves its own configuration per call from the ambient AWS chain, holding no credentials between mints. This is the rung the blank-import default uses.
func NewFromClient ¶ added in v0.5.0
NewFromClient builds a named backend around a KMS client the caller already holds — a shared client, a custom endpoint, an assumed-role client. The client is used as-is.
func NewFromConfig ¶ added in v0.5.0
NewFromConfig builds a named backend around an aws.Config the caller resolved. The client is constructed with kms.NewFromConfig (no I/O). The region is checked now rather than left to fail per call.
func NewFromSource ¶ added in v0.5.0
NewFromSource builds a named backend that resolves its AWS configuration through the supplied source. It is the sharing seam (org 0003 P-5): a consumer resolves one chain with go/awsclient — memoised or per-call — and hands the same source to the config, signing and encryption adapters.
func NewSigner ¶
NewSigner is the programmatic constructor for callers that don't want to go through the global signing registry. Most callers should use signing.Get("aws-kms") instead; this exists for integration tests and for tool authors wiring signing into their own command structure.
region is the AWS region the key lives in (an explicit positional value; WithRegion in opts overrides it when non-empty). It builds a one-off default backend and mints from it.
Types ¶
type Option ¶
type Option func(*settings)
Option configures the backend or a programmatic signer.
func WithLogger ¶
WithLogger injects a *slog.Logger for diagnostic (DEBUG-level) output. nil disables logging. Consistent with the signing module's seam conventions; gtb passes slog.New(<its handler>).
Logging policy: DEBUG records carry only non-secret identifiers — the KMS key id, AWS region, key bit-length, and signing algorithm. The library never logs credentials, the message digest, or the signature bytes. Nothing is logged above DEBUG.
func WithRegion ¶
WithRegion overrides the AWS region (default "eu-west-2"). An empty string is ignored so the default — or a flag-bound value — survives.