Sign with AWS KMS¶
Sign a release manifest with a key held in AWS KMS, where the private half
never leaves AWS — every signature is a remote kms:Sign call. The backend is
the standalone module
gitlab.com/phpboyscout/signing-aws-kms;
it implements signing.Backend and registers as aws-kms.
This mirrors Sign with the local backend — the only difference is the backend module and key setup. See Backends and the per-provider module pattern for why the AWS SDK lives in its own module.
Prerequisites¶
- An RSA SIGN_VERIFY customer master key in AWS KMS. KMS does not expose Ed25519 for asymmetric signing, so RSA is the only option; use RSA 4096 (the verify side rejects RSA keys below 3072 bits).
- AWS credentials resolvable by the SDK default chain (environment,
~/.aws/credentials/AWS_PROFILE, IAM role, or OIDC web identity). - The IAM principal needs
kms:GetPublicKeyandkms:Signon the key. - The key's ARN or alias.
Add the backend¶
import (
"gitlab.com/phpboyscout/signing"
_ "gitlab.com/phpboyscout/signing-aws-kms" // blank import registers "aws-kms"
)
The blank import runs the backend's init(), which registers it with the
signing registry under the name aws-kms.
Resolve a signer¶
backend, err := signing.Get("aws-kms")
if err != nil {
return err
}
signer, err := backend.NewSigner(ctx, "arn:aws:kms:eu-west-2:123456789012:key/abcd-…")
if err != nil {
return err
}
keyID is the KMS key ARN or alias. Region resolves from AWS_REGION (or
the --kms-region CLI flag — see below); the default is eu-west-2.
Sign a manifest and publish the key¶
Identical to every other backend — the signer is a stdlib crypto.Signer:
import "gitlab.com/phpboyscout/signing/openpgpkey"
pub, err := openpgpkey.ArmoredPublicKey(signer, "Release", "[email protected]", time.Now())
// publish `pub`: embed it in consumers, or serve it via WKD
// (see "Publish keys via WKD")
sig, err := openpgpkey.DetachSign(signer, pub, bytes.NewReader(manifest), time.Now())
// ship `manifest`, `sig`, and `pub` alongside the release
Consumers verify with signing/verify exactly as in
Verify a release.
Programmatic configuration (region, logger)¶
Outside the registry, construct a configured signer or backend directly with functional options:
import (
"log/slog"
awskms "gitlab.com/phpboyscout/signing-aws-kms"
)
// region + logger via options
signer, err := awskms.NewSigner(ctx, "us-east-1", keyARN,
awskms.WithLogger(slog.Default()))
// or register a configured backend under "aws-kms"
signing.Register(awskms.New(awskms.WithRegion("us-east-1")))
The optional *slog.Logger emits DEBUG-level diagnostics carrying only
non-secret identifiers (key id, region, key bit-length, algorithm) — never
credentials, the digest, or signature bytes.
CLI flag¶
The backend implements an optional flag-registration interface that a CLI
front-end type-asserts for; it contributes --kms-region. The canonical CLI is:
Credentials & IAM¶
No credential logic lives in the backend — it relies entirely on the AWS SDK
default chain. For CI, OIDC web-identity federation
(AWS_WEB_IDENTITY_TOKEN_FILE + AWS_ROLE_ARN) is the recommended keyless path;
scope the role's trust policy to the specific pipeline (ref/tag) so a leaked ARN
can't be assumed elsewhere.
Limitations¶
- RSA only — a non-RSA KMS key returns
ErrUnsupportedKMSKeyType. - RSASSA-PKCS1-v1_5 only — a caller requesting RSASSA-PSS gets
ErrPSSUnsupported(no silent scheme downgrade). This covers the OpenPGP RSA signing path used here.
See also¶
- Sign with the local backend — the no-cloud path.
- Implement a custom backend — roll your own (GCP, Azure, Vault, HSM).
- Backends and the per-provider module pattern.
- API reference: pkg.go.dev/gitlab.com/phpboyscout/signing-aws-kms.