AWS KMS Signer
The KMS signer (github.com/smartcontractkit/crec-sdk/transact/signer/kms) signs CRE Connect operations using a secp256k1 key held in AWS Key Management Service. The private key never leaves the AWS HSM; the signer asks KMS to sign a digest and returns an Ethereum-canonical 65-byte signature.
Prerequisites
- A KMS key with
KeyUsage=SIGN_VERIFYandKeySpec=ECC_SECG_P256K1. - AWS credentials available to the process (env vars, IAM role, or config file).
- IAM permissions:
kms:Signandkms:GetPublicKeyon the target key.
Create the key:
aws kms create-key \
--key-usage SIGN_VERIFY \
--key-spec ECC_SECG_P256K1 \
--description "CREC signing key for treasury-prod-eth"
Note the key ARN: you'll pass it to NewSigner.
Construct the signer
import (
"github.com/smartcontractkit/crec-sdk/transact/signer/kms"
)
s, err := kms.NewSigner(ctx, "arn:aws:kms:us-west-2:123456789012:key/abcd-...")
if err != nil {
return err
}
NewSigner loads AWS configuration via config.LoadDefaultConfig(ctx) (standard AWS SDK env / role chain).
Custom AWS configuration
Pin a region or credentials explicitly:
cfg, _ := config.LoadDefaultConfig(ctx, config.WithRegion("us-east-1"))
s, err := kms.NewSignerWithConfig(cfg, keyID)
Testing with a mock client
import "github.com/smartcontractkit/crec-sdk/transact/signer/kms"
mockKMS := &mocks.KMSClient{}
s, err := kms.NewSigner(ctx, keyID, kms.WithClient(mockKMS))
Derive the signer's address
Before you can provision a wallet you need the address the KMS key signs as. The signer exposes a helper:
import (
"github.com/aws/aws-sdk-go-v2/service/kms"
awskms "github.com/smartcontractkit/crec-sdk/transact/signer/kms"
"github.com/ethereum/go-ethereum/crypto"
)
cfg, _ := config.LoadDefaultConfig(ctx)
client := kms.NewFromConfig(cfg)
pubKey, err := awskms.GetPubKeyCtx(ctx, client, keyID)
if err != nil { return err }
addr := crypto.PubkeyToAddress(*pubKey).Hex()
fmt.Println("KMS signer address:", addr)
Add this address to AllowedEcdsaSigners when you create the wallet; see Manage Wallet Signers.
Sign an operation
opHash, sig, err := client.Transact.SignOperation(ctx, op, s, chainSelector)
Internally Sign(ctx, hash):
- Calls
KMS.GetPublicKeyto retrieve the secp256k1 public key (used to disambiguate the recovery byte). - Calls
KMS.SignwithMessageType=DIGESTandSigningAlgorithm=ECDSA_SHA_256. - Decodes the ASN.1 ECDSA signature into raw
(r, s). - Normalises
sto the lower half of the curve (Ethereum BIP-62 rule). - Tries
v=0andv=1in turn, picking whichever recovers to the public key returned byGetPublicKey.
The result is a 65-byte (r ∥ s ∥ v) signature that the Smart Account verifies with ecrecover (the on-chain verifier accepts the raw recovery byte).
End-to-end flow
import (
"github.com/smartcontractkit/crec-sdk/transact/signer/kms"
)
s, err := kms.NewSigner(ctx, os.Getenv("KMS_KEY_ID"))
if err != nil { return err }
op := &types.Operation{ /* ... build as usual ... */ }
opr, err := client.Transact.ExecuteOperation(ctx, channelID, s, op, chainSelector)
if err != nil { return err }
IAM least-privilege policy
The signer needs only Sign and GetPublicKey:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["kms:Sign", "kms:GetPublicKey"],
"Resource": "arn:aws:kms:us-west-2:123456789012:key/abcd-..."
}
]
}
Avoid wildcard resources: bind the policy to the specific key ARN your service is allowed to drive.
Operational notes
- API calls per signature.
Signissues two KMS round-trips per signature: oneGetPublicKeyto disambiguate the recovery byte, then oneSign. Latency is dominated by the network path between your service and KMS; measure it from your own deployment. - Throughput. Per-account
kms:Signrequest rate is governed by AWS KMS service quotas. Confirm the current limits and any account-specific overrides in the AWS KMS console (Quotas) before sizing a high-throughput workload. - Cost. A
kms:Signcall on an asymmetric key is billed per request; check the current AWS pricing page. - Audit. Every
Signshows up in CloudTrail. Pair with the Signing Transparency guide to keep an off-AWS audit trail too.
Next steps
- HashiCorp Vault Signer: for self-hosted secret management.
- Smart Accounts: how the recovered signer address is checked on chain.