> For the complete documentation index, see [llms.txt](https://docs.catalyx.solutions/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.catalyx.solutions/catalyx-blockchain-manager/canton-network/version-1.11/validator-management/kms-integration.md).

# Key Management Service (KMS)

CatalyX Blockchain Manager supports External Key Management Services (KMS) for storing Canton Validator Participant cryptographic keys. When KMS is enabled, participant keys are stored and managed in an external KMS rather than locally on the node, improving key security and enabling compliance with enterprise key management policies.

For background on why KMS matters, the two Canton key storage modes (encrypted vs. external), and the broader key management and wallet strategy for CAT-BM, see the Security & Privacy Implementation page:

{% content-ref url="/pages/bvHLoRkGDY6yVqcoe4i9" %}
[Broken mention](broken://pages/bvHLoRkGDY6yVqcoe4i9)
{% endcontent-ref %}

{% hint style="info" %}
KMS integration was introduced in **v1.11.8** as a Phase 1, environment-level toggle. As of **v1.11.11**, KMS is configured **per validator** — each validator can be created with its own KMS provider configuration and ServiceAccount, independently of other validators in the same environment.
{% endhint %}

{% hint style="warning" %}
KMS is now selected at **validator creation time** in the console (or via the API). It cannot be toggled on or off for an existing validator through the edit wizard. The environment-level Operator settings still exist, but they are no longer a master switch — they now only support migration of pre-v1.11.11 validators. See [Operator Settings (Legacy Migration Only)](#operator-settings-legacy-migration-only) below.
{% endhint %}

***

## What Changed in v1.11.11

| Aspect              | Phase 1 (v1.11.8)                                              | Per-validator (v1.11.11)                                                                                                                  |
| ------------------- | -------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| Scope               | Environment-wide — applied to **all** newly created validators | **Per validator** — chosen individually at creation time                                                                                  |
| How it is enabled   | `CANTON_TOPOLOGY_KMS_ENABLED=true` on the Operator             | `enableKms` flag in the validator create request / console create flow                                                                    |
| KMS provider config | Single global `CANTON_TOPOLOGY_KMS_VALUE` for everyone         | Per-validator `kmsValue` (falls back to the Operator default if omitted)                                                                  |
| ServiceAccount      | Single global `CANTON_TOPOLOGY_KMS_SERVICE_ACCOUNT`            | Per-validator `kmsServiceAccount` (falls back to the Operator default if omitted)                                                         |
| Changing the toggle | Required redeploying the Operator                              | No redeploy — set per validator at create time                                                                                            |
| Existing validators | Retained their original config                                 | Legacy KMS validators are auto-migrated on first reconcile (see [Backward Compatibility](#backward-compatibility-with-legacy-validators)) |

The Phase 1 global auto-enable flag (`CANTON_TOPOLOGY_KMS_ENABLED`) has been **retired**. KMS is no longer turned on by an environment variable; it is driven entirely by the per-validator request.

***

## How It Works

When a validator is created with KMS enabled, the CAT-BM Operator injects additional Canton crypto configuration into that validator's Participant pod at provisioning time. The Participant authenticates with the external KMS using IRSA — an IAM Role is associated with a Kubernetes ServiceAccount, and that ServiceAccount is assigned to the Participant pod.

The ServiceAccount is **externally managed**. It must be created and maintained outside of CAT-BM, and its name is provided per validator (or via the Operator default).

Each validator carries its own KMS settings on its spec:

* `enableKms` — whether this validator uses KMS
* `kmsValue` — the Canton KMS provider configuration fragment for this validator
* `kmsServiceAccount` — the externally managed ServiceAccount this validator's Participant pod runs under

Validators created without KMS are unaffected and continue to run under the `default` ServiceAccount with no KMS crypto config injected.

***

## Prerequisites

Before enabling KMS for a validator, ensure the following are in place:

* An external KMS key created in the appropriate region/project (e.g. AWS KMS, GCP KMS)
* An IAM Role configured with permissions to use the KMS key
* A Kubernetes ServiceAccount created in the validator namespace with the IAM Role ARN annotated via IRSA:

```yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: catalyst-canton-kms
  namespace: <validator-namespace>
  annotations:
    eks.amazonaws.com/role-arn: <iam-role-arn>
```

* The ServiceAccount name and the KMS provider configuration available to supply in the create request

***

## Enabling KMS for a Validator

KMS is enabled per validator at creation time. In the **Create Validator** flow, the participant configuration accepts three fields:

| Field               | Description                                                                                                       |
| ------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `enableKms`         | Set to `true` to store this validator's participant keys in an external KMS. Default: `false`.                    |
| `kmsValue`          | The KMS provider configuration in Canton config format (see below). Required when `enableKms` is true.            |
| `kmsServiceAccount` | The externally managed Kubernetes ServiceAccount used for IRSA authentication. Required when `enableKms` is true. |

### Request body (API)

These fields live under `clusterParticipantConfig` in the create-validator request. There are two modes, distinguished by which field you supply:

* **AWS / GCP** — use `kmsServiceAccount`
* **Azure** — use `kmsAzureVaultSecretName` (plus `overrideImage`)

`clusterParticipantConfig` KMS fields:

| Field                     | Type    | Description                                                  |
| ------------------------- | ------- | ------------------------------------------------------------ |
| `enableKms`               | boolean | Master flag — turns KMS on for this validator                |
| `kmsValue`                | string  | HOCON provider config (see Provider Examples below)          |
| `kmsServiceAccount`       | string  | K8s ServiceAccount for AWS/GCP (IRSA / workload identity)    |
| `kmsAzureVaultSecretName` | string  | K8s Secret holding Azure credentials (Azure only)            |
| `overrideImage`           | string  | Participant image override (required for Azure driver image) |

Azure also needs a pull secret for `overrideImage`, set elsewhere in the request body:

| Field                                   | Description                                     |
| --------------------------------------- | ----------------------------------------------- |
| `participant.resources.imagePullSecret` | Pull secret for the override image (Azure only) |

AWS example:

```json
{
  "clusterParticipantConfig": {
    "nodeIdentifier": "my-validator-01",
    "enableKms": true,
    "kmsValue": "{ type = \"aws\", region = \"eu-west-1\", audit-logging = true }",
    "kmsServiceAccount": "catalyst-canton-kms"
  }
}
```

### `kmsValue` format

`kmsValue` takes a Canton configuration fragment. Because it is passed through verbatim, any Canton-supported KMS provider can be used.

AWS KMS:

```
{ type = "aws", region = "eu-west-1", audit-logging = true }
```

GCP KMS:

```
{ type = "gcp", project-id = "my-project" }
```

Azure KMS (driver-based):

```
{ type = driver, name = "azure-kms", config { vault-url = "https://<your-vault>.vault.azure.net", credential { type = environment } } }
```

Azure additionally requires:

* `kmsAzureVaultSecretName`: a K8s Secret containing fields `tenant-id`, `client-id`, `client-secret`
* `overrideImage`: an Azure-KMS-enabled participant image that matches the splice image used by the validator's other apps
* A pull secret for that image, set under `participant.resources.imagePullSecret`

Azure example request:

```json
{
  "clusterParticipantConfig": {
    "nodeIdentifier": "my-validator-01",
    "enableKms": true,
    "kmsValue": "{ type = driver, name = \"azure-kms\", config { vault-url = \"https://my-vault.vault.azure.net\", credential { type = environment } } }",
    "kmsAzureVaultSecretName": "azure-kms-credentials",
    "overrideImage": "registry.gitlab.com/.../canton-azure-kms-driver:latest"
  },
  "participant": {
    "resources": {
      "imagePullSecret": "azure-kms-registry-credentials"
    }
  }
}
```

Adjust the provider settings to match your KMS key. For AWS, set `audit-logging = true` to enable KMS API audit logs (recommended for production).

### Validation

When `enableKms` is `true`, `kmsValue` must be non-blank, and at least one of `kmsServiceAccount` (AWS/GCP) or `kmsAzureVaultSecretName` (Azure) must be non-blank. If a required field is missing, empty, or whitespace-only, the API rejects the request with **HTTP 400** and a `fieldErrors` map identifying the offending field(s):

```json
{
  "fieldErrors": {
    "clusterParticipantConfig.kmsValue": "kmsValue must not be empty when enableKms is true",
    "clusterParticipantConfig.kmsServiceAccount": "kmsServiceAccount must not be empty when enableKms is true"
  },
  "globalErrors": {}
}
```

When `enableKms` is `false`, these fields are ignored and no validation is applied.

***

## Operator Settings (Legacy Migration Only)

The Operator still reads two environment-level KMS settings, but in v1.11.11 they are **not** a general-purpose configuration knob. Because the API requires both `kmsValue` and `kmsServiceAccount` whenever `enableKms=true` (see [Validation](#validation)), every validator created through the CAT-BM API or console already carries explicit values — so the Operator defaults are **never consulted for new validators**.

If `enableKms=true` but a per-validator KMS field is left blank, the Operator falls back to its configured defaults. This happens both as a one-time backfill onto pre-v1.11.11 validators on first reconcile, and at render time for any validator.

| Variable                                      | Role in v1.11.11                                                                               |
| --------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| `CANTON_TOPOLOGY_KMS_ENABLED`                 | **Retired** — no longer used to auto-enable KMS. KMS is enabled per validator via `enableKms`. |
| `CANTON_TOPOLOGY_KMS_VALUE`                   | Default fallback for `kmsValue` when blank.                                                    |
| `CANTON_TOPOLOGY_KMS_SERVICE_ACCOUNT`         | Default fallback for `kmsServiceAccount` when blank.                                           |
| `CANTON_TOPOLOGY_KMS_AZURE_IMAGE`             | Default fallback for `overrideImage` (Azure) when blank.                                       |
| `CANTON_TOPOLOGY_KMS_AZURE_IMAGE_PULL_SECRET` | Default fallback for `participant.resources.imagePullSecret` (Azure) when blank.               |
| `CANTON_TOPOLOGY_KMS_AZURE_VAULT_SECRET`      | Default fallback for `kmsAzureVaultSecretName` (Azure) when blank.                             |

{% hint style="warning" %}
To prevent a validator with blank KMS fields from silently inheriting these defaults, set the relevant variables to `""` on the Operator.
{% endhint %}

{% hint style="info" %}
If your environment has no legacy (pre-v1.11.11) KMS validators, these Operator settings have no effect and can be ignored. They only matter while un-migrated Phase 1 validators still exist — see [Backward Compatibility](#backward-compatibility-with-legacy-validators).
{% endhint %}

***

## What the Operator Configures

When a validator is provisioned with KMS enabled, the Operator makes the following changes to that validator's Participant pod:

**ServiceAccount reference** — the resolved ServiceAccount (per-validator value, or the Operator default) is set on the Participant/Canton spec:

```yaml
spec:
  serviceAccountName: catalyst-canton-kms
```

**KMS crypto config injection** — the following environment variable is injected into the Participant pod, built from the resolved `kmsValue`:

```
ADDITIONAL_CONFIG_SPLICE_PARTICIPANT_CRYPTO_KMS =
  "canton.participants.participant.crypto.provider = kms
   canton.participants.participant.crypto.kms { type = "aws", region = "eu-west-1", audit-logging = true }"
```

***

## Backward Compatibility with Legacy Validators

Validators that were created under the Phase 1 environment-level model (with `enableKms=true` but no per-validator `kmsValue` / `kmsServiceAccount` on their spec) are automatically migrated. On the next reconcile, the Operator **backfills** the global topology values (`CANTON_TOPOLOGY_KMS_VALUE` / `CANTON_TOPOLOGY_KMS_SERVICE_ACCOUNT`) onto the validator CR.

This makes the validator's KMS configuration fully explicit on its own spec, so that API reads (GET) and Operator writes (reconcile) share a single source of truth. The backfill:

* Runs only for validators that already have `enableKms=true`.
* Only fills fields that are currently **blank** — it never overwrites an explicit per-validator value.
* Runs regardless of the `disableUserEdit` flag, because it is a system migration rather than a user edit (it executes before the user-edit guard in the reconcile loop).
* Is **idempotent and self-terminating** — once both `kmsValue` and `kmsServiceAccount` are populated, it short-circuits and patches nothing on subsequent reconciles. After this one-time migration the validator no longer depends on the global Operator defaults.

{% hint style="warning" %}
For the legacy backfill to work, the Operator's `CANTON_TOPOLOGY_KMS_VALUE` and `CANTON_TOPOLOGY_KMS_SERVICE_ACCOUNT` defaults must still match what those validators were originally provisioned with, **until every legacy validator has reconciled at least once**. Removing them before legacy validators have been migrated would leave those validators without a resolvable KMS configuration.
{% endhint %}

***

## Verifying KMS Is Active

After provisioning a validator with KMS enabled, verify that:

1. The API echoes the KMS fields back on the participant — a GET on the participant returns `enableKms=true` and the `kmsValue` / `kmsServiceAccount` you submitted.
2. The Participant pod references the correct ServiceAccount — check with `kubectl get pod <participant-pod> -o yaml | grep serviceAccountName`
3. The `ADDITIONAL_CONFIG_SPLICE_PARTICIPANT_CRYPTO_KMS` environment variable is present on the Participant pod
4. The Participant starts successfully and reaches a Ready state — check the [Status](https://gitlab.com/intellecteu/products/catalyst/cat-bp/catbp-docu/catalyx-gitbook/-/blob/master/catalyx-blockchain-manager/canton-network/version-2.0/console-guide-canton/validator-detail/status.md) page in the console

{% hint style="info" %}
KMS key usage will appear in your provider's audit log (e.g. AWS CloudTrail) if audit logging is enabled on your KMS key. This can be used to confirm the Participant is actively using KMS for cryptographic operations.
{% endhint %}

***

## Scope and Limitations

| Capability                                         | v1.11.11                                                                                                                                                                              |
| -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Per-validator KMS toggle (at create time)          | ✅ Supported                                                                                                                                                                           |
| Per-validator KMS provider config & ServiceAccount | ✅ Supported                                                                                                                                                                           |
| Multiple KMS providers (AWS, GCP, …)               | ✅ Supported via the `kmsValue` Canton config fragment                                                                                                                                 |
| Legacy validator migration                         | ✅ Supported — Operator KMS settings backfilled onto the CR on reconcile                                                                                                               |
| Environment-level KMS defaults for new validators  | ❌ Not applicable — validation requires explicit values, so Operator defaults are never used for new validators                                                                        |
| Toggling KMS on an existing validator (edit)       | ❌ Not supported — KMS is fixed at creation time; the edit wizard guards these fields. All KMS fields are immutable after creation **except `overrideImage`**, which remains editable. |
| Retroactive KMS enablement for non-KMS validators  | ❌ Not supported — only validators created with `enableKms=true` use KMS                                                                                                               |
| Operator-managed ServiceAccount lifecycle          | ❌ Not yet supported — SA must be externally managed                                                                                                                                   |
| KMS key rotation                                   | ❌ Not yet supported                                                                                                                                                                   |


---

# 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 dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.catalyx.solutions/catalyx-blockchain-manager/canton-network/version-1.11/validator-management/kms-integration.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
