Enable external key storage with a KMS

This section shows how to enable external key storage for a Canton Participant, so that private keys are stored and managed by a KMS, and all cryptographic operations using those keys must go through the KMS.

Note

This assumes the KMS provider has already been configured. See Configure a KMS.

To enable external key storage and usage, apply the configuration below before the initial bootstrap of a new Participant node. If you’re updating an existing Participant, you must instead follow the migration guide: Migrate to external key storage with a KMS.

canton.participants.participant1.crypto.provider = kms

A complete example configuration that puts together both AWS KMS configuration and external key storage configuration is shown below:

canton.participants.participant1.crypto.provider = kms
canton.participants.participant1.crypto.kms {
    type = aws
    region = us-east-1
    multi-region-key = false # optional, default is false
    audit-logging = true # optional, default is false
}

The same configuration is applicable for all KMS types, by selecting the correct type (AWS, GCP or Driver).

This configuration tells Canton that we want to use external keys in a KMS, which are automatically created by default when a Participant starts — no further action is required. Read on if you prefer to use your own manually generated keys that are already stored in the KMS.

Run with manually-generated keys

This howto shows how to configure a participant node with keys that are generated manually in the KMS and not rely on automatic key generation by Canton

The first step is to manually generate new keys for the Participant in your KMS. All the necessary keys are listed below and include:

  • a (signing) namespace key;

  • a protocol signing key;

  • a sequencer authentication key;

  • an asymmetric encryption key;

Generate each key in your KMS with a supported key algorithm and purpose as shown in Table Key configuration for external keys as well as the correct usage (see Signing Key Usage) and record the generated keys identifier.

To be able to use these keys, you must configure manual initialization in the Participant. This is explained in detail in Initialize node identity manually. However, it is important to note that contrary to what is described there, the keys are expected to be registered, not generated.

// Register the KMS signing key used to define the node identity.
val namespaceKey = node.keys.secret
  .register_kms_signing_key(
    namespaceKmsKeyId,
    SigningKeyUsage.NamespaceOnly,
    name = s"${node.name}-${SigningKeyUsage.Namespace.identifier}",
  )

// Register the KMS signing key used to authenticate the node toward the Sequencer.
val sequencerAuthKey = node.keys.secret
  .register_kms_signing_key(
    sequencerAuthKmsKeyId,
    SigningKeyUsage.SequencerAuthenticationOnly,
    name = s"${node.name}-${SigningKeyUsage.SequencerAuthentication.identifier}",
  )

// Register the signing key used to sign protocol messages.
val signingKey = node.keys.secret
  .register_kms_signing_key(
    signingKmsKeyId,
    SigningKeyUsage.ProtocolOnly,
    name = s"${node.name}-${SigningKeyUsage.Protocol.identifier}",
  )

// Register the encryption key.
val encryptionKey = node.keys.secret
  .register_kms_encryption_key(encryptionKmsKeyId, name = node.name + "-encryption")

where xyzKmsKeyId is the KMS key identifier for a specific key (e.g. KMS Key ARN).

Note

When using AWS cross account keys the key ID can’t be used, use the key ARN instead.