- How to use AWS Key Management Service (KMS) to generate and manage a secure private key that acts as the signer for your treasury wallet.
- Creating, signing and submitting transactions for your wallet, using the KMS.
Required AWS IAM Permissions
Required AWS IAM Permissions
To complete this setup, your AWS user or role will need the following permissions:
| Permission | Purpose |
|---|---|
kms:CreateKey | Create the KMS asymmetric key for signing |
iam:CreateRole | Create the IAM role for Lambda execution |
iam:PutRolePolicy | Attach inline policies to the IAM role |
iam:PutGroupPolicy | Configure group-level policies if needed |
ec2:DescribeVpcEndpoints | Configure VPC endpoints for private API access |
apigateway:UpdateRestApiPolicy | Update API Gateway resource policies |
Why Use AWS KMS as Signer for a Treasury Wallet?
Crossmint Treasury Wallets support a myriad of different signers. From email/phone number backed up keys, to passkeys, to bringing your own signer. AWS KMS is a fully managed service for creating, controlling, and managing cryptographic keys. Crossmint recommends using it as an external signer for treasury wallets, for bank grade security with high performance. It has the following properties:- Confidential Key Generation and Custody: generate private keys within hardware security modules (HSMs). No one —including your own team— ever sees or has access to the raw key material.
- Granular Access Control: define explicit permissions on who can perform signing operations using AWS IAM roles and policies. Integrate seamlessly with your organization’s existing authentication and authorization infrastructure.
- Advanced Observability: enable Cloud Trail to log every operation, and use Cloud Watch for anomaly detection and alerting.
- High Performance: operate over 1000 TPS with tens of milliseconds of latency.
Integration Steps
0. Pre-requisites
Before you begin, ensure you have:- An AWS account with appropriate permissions to create KMS keys, IAM roles, Lambda functions, and API Gateway resources
- AWS CLI installed on your machine (for testing)
1. Create a key in AWS KMS
Create an asymmetric key in AWS KMS that will be used as your wallet signerThis guide is written for EVM-compatible blockchains. The steps for Solana or Stellar are similar, but key
settings change. Contact your Crossmint support representative for assistance.
Access AWS KMS
Log in to your AWS account and search for “KMS” in the AWS Console. Navigate to the Key Management Service.
Configure Key Settings
Configure your key with the following settings:
| Setting | Value |
|---|---|
| Key type | Asymmetric |
| Key usage | Sign and verify |
| Key spec | ECC_SECG_P256K1 |
The
ECC_SECG_P256K1 specification is the secp256k1 elliptic curve, which is the same curve used by Ethereum and other EVM-compatible blockchains for cryptographic operations.Name Your Key
Give your key a descriptive alias that identifies its purpose, for example:
treasuryABC-admin-signer.Set Permissions
Specify the key administrators and users who should have access to manage and use this key.
2. Set up KMS Signing Policy
Next, create an IAM role that allows to call KMS for signing operations.In this guide, we use an AWS Lambda function to handle signing requests. However, this architecture can be adapted
to run on other compute types such as EC2 instances or ECS containers depending on your infrastructure
requirements.
Skip Permission Policies
Skip the permission policies step for now (you’ll add an inline policy next).
Add Inline Policy
From within the new role page, select Add Permissions and then Create inline policy.
Configure the Policy
Set the Policy editor to JSON and add the following policy:Replace the placeholders with your actual values:
| Placeholder | Where to Find It |
|---|---|
REGION | Your AWS region (e.g., us-east-1, eu-north-1) |
ACCOUNT_ID | Click your profile icon in the top-right corner of AWS Console |
KEY_ID | Found on your KMS key’s dashboard page |
3. Create a Crossmint Treasury Wallet with Key as a Signer
Follow the steps on the Treasury Wallets quickstart, passing the public key created earlier as the signer address. Since AWS KMS provides the public key in PEM format, you need to convert it to an Ethereum address. The code below handles this conversion by parsing the PEM-encoded public key and deriving the corresponding Ethereum address.Replace the
publicKeyPem placeholder with the public key you copied from AWS KMS in the previous step.Node.js
Required npm packages
Required npm packages
Install the following packages to parse the PEM public key:The
viem package should already be available as a peer dependency of @crossmint/wallets-sdk.4. Create a Lambda Function to Handle Signature Requests
Now create a Lambda function that will handle signing requests using your KMS key.Create the Function
Search for “Lambda” in the AWS Console and click Create function. Give your function a name, for example:
adminSigner.Configure Execution Role
Under Change default execution role, select Use an existing role. From the Existing role dropdown, select the role you created during IAM Role Setup (e.g.,
adminSignerInvoker).Set Environment Variables
Create a new environment variable 
KMS_KEY_ID and set it to your KMS key ID. You can find the key ID at the top of the KMS key’s dashboard page.
Add the Function Code
Enter the following code in the Lambda function editor:
View Lambda Function Code
View Lambda Function Code
Optional: Expose Function as HTTP Endpoint
Then, make the function accessible to your main application.Below, you can see optional steps for enabling it as via an HTTP endpoint whitelisted to an IAM role.
Create an API Gateway
Create an API Gateway
Expose the function via an HTTP route, only callable from accounts with certain IAM role.
Create the API
Search for “API Gateway” in the AWS Console and click Create API. Select Build for REST API.
Configure API Settings
Name your API (e.g.,
KMS Sign API) and select a security policy that meets your requirements.Create a Method
After creating the API, select Create method with the following settings:
| Setting | Value |
|---|---|
| Method type | POST |
| Lambda function | Select the Lambda function you created |
| Authorization (In Method Request Settings) | AWS IAM |
Deploy the API
Go back to API > Resource and select Deploy API. Select the stage you created and click Deploy.
Add Resource Policy
Navigate to Resource policy in the left panel and add the following policy to allow invocations from your AWS account:Replace the placeholders with your actual values:
After adding the policy, click Save and then re-deploy the API to the stage for the changes to take effect.
| Placeholder | Where to Find It |
|---|---|
REGION | Your AWS region (e.g., us-east-1, eu-north-1) |
ACCOUNT_ID | Click your profile icon in the top-right corner of AWS Console |
API_ID | Found in the API Gateway console URL or in the API’s ARN |
Save the Invoke URL
Copy the Invoke URL for your API. You’ll need this URL to test the endpoint. You can always find this URL under the Stages view.
Grant User Group Access to API Gateway
Add a policy to your user group to allow members to invoke the API Gateway endpoint.Replace the placeholders with your actual values:
- Search for IAM in the AWS Console and navigate to User groups in the left panel.
- Select the user group you want to grant access to (or create a new one).
- Go to the Permissions tab.
- Click Add permissions and select Create inline policy.
- Select the JSON tab in the policy editor.
- Paste the following policy:
| Placeholder | Where to Find It |
|---|---|
REGION | Your AWS region (e.g., us-east-1, eu-north-1) |
ACCOUNT_ID | Click your profile icon in the top-right corner of AWS Console |
API_ID | Found in the API Gateway console URL or in the API’s ARN |
STAGE | The stage name you created (e.g., prod) |
- Click Next, give the policy a name (e.g.,
api-gateway-invoke-policy), and click Create policy.
Test Using AWS CLI
Test Using AWS CLI
You can invoke the function using the AWS CLI to ensure everything is working correctly.
Open Security Credentials
Click on your username in the top right corner of the AWS Console, then select Security credentials from the dropdown menu.
Select Use Case
Select the use case (e.g., “Command Line Interface (CLI)”) and click Create access key.
Copy Access Keys
Important: Copy both the Access key ID and Secret access key immediately. The secret access key will only be shown once and cannot be retrieved later.
Enter Access Key ID
When prompted, enter your AWS Access Key ID: Paste the access key ID you copied in the previous step.
Enter Default Region
Enter your Default region name: Enter your AWS region (e.g.,
us-east-1, eu-north-1).Set Output Format
For Default output format: Press Enter to use the default (JSON) or specify
json, yaml, text, or table.Your credentials will be stored in ~/.aws/credentials and your configuration in ~/.aws/config.Generate Signature
Run the following command to sign a message using your endpoint:Replace the placeholders with your actual values:
| Placeholder | Description |
|---|---|
YOUR_REGION | Your AWS region (e.g., us-east-1, eu-north-1) |
YOUR_API_ID | Found in the API Gateway console URL or ARN (e.g., if ARN is arn:aws:execute-api:eu-north-1:257027486036:bho48fe8dl/*/POST/, then API_ID is bho48fe8dl) |
BASE64_ENCODED_MESSAGE_HASH | The base64-encoded message hash returned from wallet APIs |
0xYOUR_KMS_SIGNER_ADDRESS | The Ethereum address derived from your KMS public key (from step 3) |
5. Initiate Regulated Transfer
Initiate a regulated transfer from your treasury wallet to a recipient. Before calling the API, ensure the recipient wallet is properly set up with registered personal data as described in the regulated transfers guide. The API returns a transaction object containing amessage (hash) that needs to be signed by the adminSigner.
6. Sign the Message
Send the message hash returned from the previous step to your AWS API Gateway endpoint. For testing, you can use the AWS CLI to submit the signature. This would have required you to expose the lambda as an HTTP API in step 4.Generate Signature
Run the following command to sign a message using your endpoint:Replace the placeholders with your actual values:
The response will contain the signature with the correct recovery parameter:
| Placeholder | Description |
|---|---|
YOUR_REGION | Your AWS region (e.g., us-east-1, eu-north-1) |
YOUR_API_ID | Found in the API Gateway console URL or in the API’s ARN |
BASE64_ENCODED_MESSAGE_HASH | The base64-encoded message hash returned from wallet APIs |
0xYOUR_KMS_SIGNER_ADDRESS | The Ethereum address derived from your KMS public key (from step 3) |
7. Approve the Transaction
Finally, submit the signature to the Approve Transaction API to complete the transfer. The transaction is then broadcast to the blockchain.Security Best Practices
Follow these security best practices:- Principle of Least Privilege: Only grant the minimum permissions necessary for each IAM role and user
- Audit Logging: Enable AWS CloudTrail to log all KMS and API Gateway operations
- Network Security: Consider using VPC endpoints for KMS to keep traffic within your AWS network
- Access Reviews: Regularly review who has access to your KMS keys and API Gateway endpoints

