Configure External Key Storage with GCP KMS

Important

Daml Enterprise license required

The following section describes the steps needed to enable External Key Storage in Canton using GCP KMS. These steps include configuring GCP KMS, as well as configuring this particular mode of operation.

GCP KMS Configuration

To start using this feature you must first enable a KMS for Canton.

–Configure GCP KMS for Canton–

The following IAM permissions are required:

  • cloudkms.cryptoKeyVersions.create
  • cloudkms.cryptoKeyVersions.useToDecrypt
  • cloudkms.cryptoKeyVersions.useToSign
  • cloudkms.cryptoKeyVersions.get
  • cloudkms.cryptoKeyVersions.viewPublicKey

When you are using cross-account keys, you do not need the cloudkms.cryptoKeyVersions.create permission.

External Key Storage Configuration

External key storage support can be enabled for a new installation (i.e., during the node bootstrap) or for an existing deployment. Be aware that if a node has already been deployed you need to perform a node migration. Simply adding the following configuration is not enough.

In the example below, you configure a Canton participant node (called participant1) to generate and store private keys in an external GCP KMS. The same configuration is applicable for all other node entities, including the domain manager, mediators, and sequencers.

canton.participants.participant1.crypto.provider = kms

An example configuration that puts together both KMS and external storage configuration is shown below:

canton.participants.participant1.crypto.provider = kms
canton.participants.participant1.crypto.kms {
    type = gcp
    location-id = us-east1
    project-id = gcp-kms-testing
    key-ring-id = canton-test-keys-2023
}

Setup with Pre-Generated Keys

In the previous example, Canton creates its own keys on startup and initializes the identity of the nodes automatically. To use pre-generated keys, you need to manually initialize the identity of the nodes by adding the following to each node’s configuration:

<node>.init.auto-init = false

This is only applicable for participant and domain/domain-manager nodes.

Afterwards, we need to register the keys in Canton by running the key registration command on each node. For example for a participant you would run:

val identityKey = participant.keys.secret
  .register_kms_signing_key(namespaceKmsKeyId, name = participant.name + "-namespace")
val signingKey = participant.keys.secret
  .register_kms_signing_key(signingKmsKeyId, name = participant.name + "-signing")
val encryptionKey = participant.keys.secret
  .register_kms_encryption_key(encryptionKmsKeyId, name = participant.name + "-encryption")

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

Here is a reminder of the initial keys that each node owns:

List of keys that each node owns
Keys Domain Domain-Manager Sequencer Mediator Participant
(Signing) Namespace Key x x     x
Signing Key x x x x x
(Asymmetric) Encryption Key         x

Depending on the key purpose and the default signing and encryption schemes defined in Canton, you need to pre-generate the corresponding GCP KMS keys with the correct settings:

GCP key configuration
Provider SIGNING ENCRYPTION
GCP
  • Key Purpose: ASYMMETRIC_SIGN
  • Key Algorithms: EC_SIGN_P256_SHA256 or EC_SIGN_P384_SHA384
  • Key Purpose: ASYMMETRIC_DECRYPT
  • Key Algorithm: RSA_DECRYPT_OAEP_2048_SHA256

Below are links to guides on how to manually initialize participant and domain nodes. In those guides, keys are generated using console commands such as:

val identityKey = participant.keys.secret.generate_signing_key(name = participant.name + "-namespace")

Make sure to replace those commands with the ones shown above with which you registered your existing keys instead of generating new ones.