> For the complete documentation index, see [llms.txt](https://docs.bitsafe.finance/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.bitsafe.finance/decentralization-manager/operations-and-reference/sign-with-aws-kms.md).

# Sign with AWS KMS

Grant Decentralization Manager the AWS KMS access it needs to sign ledger transactions with a Daml key that a KMS-backed participant holds.

[Security architecture](/decentralization-manager/operations-and-reference/security-architecture.md) · [Package and contract operations](/decentralization-manager/operations-and-reference/package-and-contract-operations.md)

## When this applies

Use this page when your Canton participant uses AWS KMS as its crypto provider. The participant setting is `canton.participants.<participant>.crypto.provider = kms`. On such a participant, Canton creates the party keys inside AWS KMS. The private keys cannot leave AWS KMS.

Each member of a Decentralized Party holds two keys:

| Key           | Signs                                                               | How it signs on a KMS-backed participant                                     |
| ------------- | ------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| Namespace key | Topology transactions                                               | The participant signs through its own KMS access. No setup is necessary.     |
| Daml key      | Ledger transactions, for example the governance contract deployment | Decentralization Manager calls the AWS KMS `Sign` API. This needs IAM setup. |

Canton has no API that signs a ledger transaction with a vault key. Decentralization Manager therefore calls AWS KMS itself. It signs during the contracts workflow, after it checks each prepared transaction.

You do not select the signing path. Decentralization Manager reads the key metadata from the participant with `VaultService.ListMyKeys`. A key with a KMS key ID uses AWS KMS. A key without one uses the export path in [JCE alternative](#jce-alternative).

## Key spec

Decentralization Manager creates each party key with an unspecified key spec. The participant then applies its own default: EC-P256 on a KMS-backed participant, Ed25519 on a JCE participant.

The AWS KMS signer supports EC-P256 keys only. AWS KMS calls this key spec `ECC_NIST_P256`. For each prepared transaction hash, Decentralization Manager does these steps:

1. It calls `Sign` with the signing algorithm `ECDSA_SHA_256` and the message type `RAW`.
2. It receives a DER-encoded signature. Canton accepts this format without conversion.
3. It verifies the signature against the public key that the participant registered. The coordinator then submits the transaction.

## IAM permissions

Decentralization Manager calls one AWS KMS API: `kms:Sign`. It reads the key ID and the public key from the participant, not from AWS KMS.

The participant creates the keys under its own KMS role. The IAM role of Decentralization Manager therefore has no access by default. Grant `kms:Sign` on the Daml key of each party.

{% tabs %}
{% tab title="Key policy (recommended)" %}
Add this statement to the key policy of each party Daml key. A key policy statement works whether or not the key policy delegates access to IAM.

```json
{
  "Sid": "AllowPartyDamlKeySigning",
  "Effect": "Allow",
  "Principal": { "AWS": "arn:aws:iam::<account>:role/<decentralization-manager-role>" },
  "Action": "kms:Sign",
  "Resource": "*"
}
```

In a key policy, `"Resource": "*"` means the key that the policy belongs to.
{% endtab %}

{% tab title="IAM policy" %}
An IAM policy on the Decentralization Manager role works only when the key policy delegates access to IAM. The statement has no `Principal`. Its `Resource` must name the ARN of each party Daml key.

```json
{
  "Sid": "AllowPartyDamlKeySigning",
  "Effect": "Allow",
  "Action": "kms:Sign",
  "Resource": "arn:aws:kms:<region>:<account>:key/<party-daml-key-id>"
}
```

{% endtab %}
{% endtabs %}

{% hint style="danger" %}
Never use `"Resource": "*"` in an IAM policy for this role. That statement grants signing with every key in the account, including the namespace keys of the participant.
{% endhint %}

### Find the key ID

The party Daml key has the name `<party-prefix>-daml-transactions`. List the key over the participant Admin API. Its metadata holds the `kmsKeyId` field.

```bash
grpcurl -plaintext -d '{"filters":{"name":"<party-prefix>-daml-transactions"}}' \
  <admin-host>:<admin-port> \
  com.digitalasset.canton.crypto.admin.v30.VaultService/ListMyKeys
```

The example uses `-plaintext`. Replace it with your TLS options if the Admin API uses TLS.

As an alternative, run the contracts workflow once. The `AccessDeniedException` error names the key ARN.

## Configure AWS credentials

Decentralization Manager has no `DECPM_*` variable for AWS KMS. It discovers the key ID from the participant. It loads the AWS credentials and the region from the default AWS credential chain:

| Source                | Settings                                                                                            |
| --------------------- | --------------------------------------------------------------------------------------------------- |
| Environment variables | `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`, plus `AWS_SESSION_TOKEN` for temporary credentials |
| Shared configuration  | `AWS_PROFILE` with the AWS configuration and credentials files                                      |
| Web identity role     | On Amazon EKS, an IAM role for the Decentralization Manager service account (IRSA)                  |
| Region                | `AWS_REGION`. Set it to the region of the KMS keys if the chain does not resolve it.                |

AWS resolves a bare key ID in the account and region of the credentials. If the participant keys are in another AWS account, give Decentralization Manager credentials for that account.

### Key ID validation

The participant metadata must hold a bare key ID. A bare key ID is a UUID, or `mrk-` followed by 32 hexadecimal digits. Decentralization Manager rejects an ARN, an alias or a malformed ID before it calls `Sign`. Metadata therefore cannot redirect signing to a key in another account.

## Verify the setup

1. Run the `ListMyKeys` command from [Find the key ID](#find-the-key-id). The result must show `kmsKeyId` with a bare key ID.
2. Optional: check the key spec in AWS. Use an AWS identity that can read the key.

   ```bash
   aws kms describe-key --key-id <kms-key-id> --region <region> \
     --query 'KeyMetadata.[KeySpec,KeyUsage]'
   ```

   The expected values are `ECC_NIST_P256` and `SIGN_VERIFY`.
3. Run the contracts workflow for the Decentralized Party. [Package and contract operations](/decentralization-manager/operations-and-reference/package-and-contract-operations.md) describes the workflow.
4. Read the Decentralization Manager log on each KMS-backed member. A successful workflow run logs `Signing <n> transaction hashes via AWS KMS key <kms-key-id>...`. It then logs `Signature <n> verified locally` for each hash.

A member on a JCE participant logs `Exporting private key from Canton...` instead.

### Failure modes

| Log message                                                   | Cause and action                                                                                                                                                                 |
| ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `KMS signing failed: ... AccessDeniedException`               | The Decentralization Manager role has no `kms:Sign` on the key. Add the key policy statement.                                                                                    |
| `KMS signing failed: ... dispatch failure`                    | Decentralization Manager found no AWS credentials, or it uses the wrong region. Check the credential chain and `AWS_REGION`.                                                     |
| `Invalid kms_key_id`                                          | The vault metadata holds an ARN, an alias or a malformed ID. Use the bare ID of the participant key and credentials for its account.                                             |
| `AwsKmsSigner does not support key spec`                      | The party Daml key is not EC-P256. The AWS KMS signer supports EC-P256 only.                                                                                                     |
| `failed local verification against the registered public key` | The KMS key does not match the registered public key. Check that the `kmsKeyId` belongs to the Daml key of this party.                                                           |
| The workflow fails at export with `ExportKeyPair`             | The key has no KMS key ID, so Decentralization Manager used the export path. This is normal on a JCE participant. On a KMS-backed participant, the key metadata is inconsistent. |

## JCE alternative

A participant with the JCE crypto provider keeps exportable keys in its vault. Decentralization Manager needs no AWS setup for such a participant. It does these steps each time it signs:

1. It exports the party Daml key over the Admin API with `VaultService.ExportKeyPair`.
2. It finds the Ed25519 private key in the export and checks it against the registered public key.
3. It signs each transaction hash in memory and verifies each signature locally.
4. It wipes the private key bytes from memory. It never stores the private key in its database or on disk.

Parties that JCE participants created before AWS KMS support hold Ed25519 keys. These parties continue to use the export path.

| Property                          | JCE participant                                          | KMS-backed participant                    |
| --------------------------------- | -------------------------------------------------------- | ----------------------------------------- |
| Daml key spec                     | Ed25519                                                  | EC-P256                                   |
| Private key leaves the key store  | Yes, into Decentralization Manager memory during signing | No                                        |
| Who can sign with the key         | Any caller with Admin API access to the participant      | IAM principals with `kms:Sign` on the key |
| Setup in Decentralization Manager | None                                                     | AWS credentials and `kms:Sign`            |

{% hint style="warning" %}
On a JCE participant, Admin API access is enough to export the party Daml key. Restrict the Admin API to the Decentralization Manager host.
{% endhint %}

## Limits

* Decentralization Manager supports AWS KMS only. A participant with another KMS driver also reports a KMS key ID. Signing then fails with a KMS error.
* The AWS KMS signer supports EC-P256 keys only.

## Technical sources

* [Signing with AWS KMS party keys](https://github.com/DLC-link/decentralization-manager/blob/main/docs/KMS_SIGNING.md)
* [Signing backends](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman/src/signing/mod.rs)
* [Signer selection](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman/src/signing/signer.rs)
* [AWS KMS signer](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman/src/signing/aws_kms.rs)
* [Vault export signer](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman/src/signing/vault_export.rs)
* [Contracts sign step](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman/src/workflow/contracts/steps/sign.rs)
* [Party key generation](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman/src/workflow/onboarding/steps/generate_keys.rs)

## Next step

👉 **Deploy contracts with the new setup:** [Package and contract operations](/decentralization-manager/operations-and-reference/package-and-contract-operations.md).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.bitsafe.finance/decentralization-manager/operations-and-reference/sign-with-aws-kms.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
