Key management

Choose the encryption trust boundary

X2 remains functional without KMI for evaluation. Production credentials and object data should use an explicitly configured provider whose authorization and unseal material remain outside X2 consensus.

Command platform

Linux

Decision guide

Select a provider before storing production data

The session-signing and credential key names are stable internal identities. Bucket default encryption uses the cluster default object key unless an administrator selects a separately created customer key.

Supported

X2 KMS

Operate a sealed, independently authorized KMS cluster. X2 Node authenticates with a pinned client public-key identity and exact grants.

  • Manual initialization and unseal
  • Root-token operator administration
  • Per-node workload identities
  • Signing and data-key operations
Open X2 KMS guide
Supported

HashiCorp Vault

Use Vault Transit with AppRole, token-file, or client-certificate authentication and least-privilege policies.

  • Existing Vault operations model
  • Transit signing and envelope protection
  • Node-local provider credentials
Configure Vault
Supported

AWS KMS

Connect every X2 Node to AWS KMS using the same least-privilege static credentials, then select a key ARN per bucket or object.

  • Multiple same-region customer-managed keys
  • Full key ARN supplied as KMSMasterKeyID
  • AWS GenerateDataKey and Decrypt for object data
  • Cluster-local P-256 signing and internal-secret protection
  • No client certificate or session token
Configure AWS KMS

Security model

What stays outside X2

Operator authority

KMS root tokens, unseal shares, Vault root credentials, and cloud administrative identities never enter X2 configuration or UI.

Node authority

X2 KMS uses a separate workload certificate per node. AWS KMS and Vault credentials are also provisioned independently on every X2 node; they are never replicated through cluster consensus.

Stored state

Provider credentials remain in node-local configuration or the process environment. AWS-wrapped object data keys and selected key ARNs are stored with object metadata; plaintext data keys exist only in process memory.

Cluster rollout

Configure once, provision every node, then activate

In the Admin UI, open System Configuration → Encryption & KMS. Create a staged provider generation, open each node row, follow the provider-specific credential instructions, and run its data-key verification. Activation remains disabled until every current cluster member is ready. The UI and XC may connect through any proxy-visible node; X2 routes each node operation to its selected target over the authenticated internal mesh.

Shared state

Provider, endpoint, region, mounts, workload ID, required nodes, and generation are consensus protected.

Node-local state

Access keys, tokens, AppRole secrets, client keys, certificates, and trust files are stored only beneath that node's secrets root.

Safe rotation

New writes record the active provider generation. Older generations remain decrypt-only and can be selected for rollback.

xc encryption rollout create --file provider.json
xc encryption node prepare-x2 NODE_ID --rollout ROLLOUT_ID # X2 KMS only
xc encryption node provision NODE_ID --rollout ROLLOUT_ID --credentials-file credentials.json
xc encryption node verify NODE_ID --rollout ROLLOUT_ID
xc encryption rollout activate ROLLOUT_ID

HashiCorp Vault

Connect Vault Transit

Create a dedicated Transit mount and role with only the signing and data-key operations X2 requires. The Admin UI defaults to AppRole, generates the Vault CLI commands for each node, and keeps the optional private-CA certificate under advanced settings. A plain token is available for quick setup but must be rotated manually.

Linux environment

export X2_KMI_ENABLED=true
export X2_KMI_PROVIDER=hashicorp-vault
export X2_VAULT_ADDRESS=<VAULT_ADDRESS>
export X2_VAULT_TRANSIT_MOUNT=transit
export X2_VAULT_AUTH_METHOD=approle
export X2_VAULT_ROLE_ID_FILE=/data/x2/metadata/.x2/state/secrets/vault-role-id
export X2_VAULT_SECRET_ID_FILE=/data/x2/metadata/.x2/state/secrets/vault-secret-id
export X2_VAULT_CA=/data/x2/metadata/.x2/state/secrets/vault-ca.crt

Windows environment

$env:X2_KMI_ENABLED='true'
$env:X2_KMI_PROVIDER='hashicorp-vault'
$env:X2_VAULT_ADDRESS='<VAULT_ADDRESS>'
$env:X2_VAULT_TRANSIT_MOUNT='transit'
$env:X2_VAULT_AUTH_METHOD='approle'
$env:X2_VAULT_ROLE_ID_FILE='C:\ProgramData\X2\secrets\vault-role-id'
$env:X2_VAULT_SECRET_ID_FILE='C:\ProgramData\X2\secrets\vault-secret-id'
$env:X2_VAULT_CA='C:\ProgramData\X2\secrets\vault-ca.crt'

macOS configuration

sudo /usr/local/lib/x2/x2-node configure \
  --kmi-enabled --kmi-provider hashicorp-vault \
  --vault-address <VAULT_ADDRESS> \
  --vault-transit-mount transit --vault-auth-method approle \
  --vault-role-id-file /Volumes/X2Metadata/.x2/state/secrets/vault-role-id \
  --vault-secret-id-file /Volumes/X2Metadata/.x2/state/secrets/vault-secret-id \
  --vault-ca /Volumes/X2Metadata/.x2/state/secrets/vault-ca.crt
Credential handling: do not place tokens, Secret IDs, client private keys, or unseal material in node.yaml, consensus, the UI, or release manifests.

Least-privilege Vault Transit policy

path "<transit-mount>/keys" {
  capabilities = ["list"]
}

path "<transit-mount>/keys/*" {
  capabilities = ["read", "update"]
}

path "<transit-mount>/datakey/plaintext/*" {
  capabilities = ["update"]
}

path "<transit-mount>/decrypt/*" {
  capabilities = ["update"]
}

path "<transit-mount>/encrypt/*" {
  capabilities = ["update"]
}

Replace <transit-mount> with the configured mount, save the file as x2-kmi-policy.hcl, and apply it with vault policy write x2-kmi x2-kmi-policy.hcl. Updating the contents of an already attached policy does not require generating a new node identity. If the policy was not attached to the AppRole or token, attach it and obtain fresh node credentials as appropriate for that authentication method.

Existing Vault policies must include encrypt: provider verification now encrypts an existing data key as well as generating and decrypting one. A node can authenticate successfully and still report that its policy does not allow the required KMS operations when <transit-mount>/encrypt/* is missing. Update the policy attached to that node identity, then verify the node again. X2 KMS is not involved when the selected provider is HashiCorp Vault, so upgrading X2 KMS does not repair a Vault policy.
Key discovery: grant the configured Vault identity list capability on <transit-mount>/keys to populate the encryption UI. Manual key-name entry remains available when listing is not granted.

AWS KMS

Use multiple AWS KMS keys for object encryption

KMI is the KES-equivalent layer. For SSE-KMS, the bucket or object supplies a full key ARN and AWS returns the plaintext and wrapped object data key. X2 never asks AWS to create customer-managed keys.

Linux environment

export X2_KMI_ENABLED=true
export X2_KMI_PROVIDER=aws-kms
export X2_AWS_KMS_REGION=us-east-1
export X2_AWS_KMS_ACCESS_KEY_ID='REPLACE_ACCESS_KEY'
export X2_AWS_KMS_SECRET_ACCESS_KEY='REPLACE_SECRET_KEY'

Windows environment

$env:X2_KMI_ENABLED='true'
$env:X2_KMI_PROVIDER='aws-kms'
$env:X2_AWS_KMS_REGION='us-east-1'
$env:X2_AWS_KMS_ACCESS_KEY_ID='REPLACE_ACCESS_KEY'
$env:X2_AWS_KMS_SECRET_ACCESS_KEY='REPLACE_SECRET_KEY'

IAM policy for the allowed keys

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["kms:GenerateDataKey", "kms:Decrypt", "kms:DescribeKey"],
      "Resource": [
        "arn:aws:kms:us-east-1:123456789012:key/KEY_ONE",
        "arn:aws:kms:us-east-1:123456789012:key/KEY_TWO"
      ]
    },
    {
      "Effect": "Allow",
      "Action": ["kms:ListKeys", "kms:ListAliases"],
      "Resource": "*"
    }
  ]
}
S3 selection: set KMSMasterKeyID to a full key ARN when enabling aws:kms bucket encryption, or send x-amz-server-side-encryption-aws-kms-key-id on an object request. Labels, aliases, bare key IDs, other-region keys, and AWS S3 Bucket Keys are rejected. Each object causes an AWS GenerateDataKey call; CloudTrail and X2 debug logs can be used to verify the selected ARN.
Key discovery: the encryption UI displays a customer alias while submitting the associated full key ARN. AWS can enumerate only keys in the configured account and region, so manual ARN entry remains available for cross-account keys. Without the list and describe permissions above, encryption still works through manual ARN entry.
Encryption modes: AES256 remains available and uses X2's cluster-local SSE-S3 wrapping key. Only aws:kms object encryption calls AWS KMS.
TLS and credentials: standard AWS endpoints use the operating-system CA store. Configure X2_AWS_KMS_CA_FILE only for a private endpoint with a custom CA. Environment overrides are not written to node.yaml; no session-token or client-certificate authentication is accepted in this version.
Compatibility: this is a clean break from the single-root AWS provider. root_key_arn, X2_AWS_KMS_ROOT_KEY_ARN, logical KMI labels, and aws-kms:v1 envelopes are rejected. Existing AWS-encrypted data must be exported and reimported, or the cluster must be recreated; existing sessions must be re-established.

Provider status

KMI adapter support

Provider status is release-scoped and is published from the portal support matrix into each immutable release manifest. AWS KMS is implemented directly in X2 Node for the current publication source; Azure Key Vault and Google Cloud KMS require an external adapter.

Provider Status Identity Operations
X2 KMS Supported Pinned client public-key ID Sign and data-key transit
HashiCorp Vault Supported Token, AppRole, or certificate Transit sign/encrypt/decrypt
AWS KMS Supported Shared access key and secret key KMI: local Sign/GetPublicKey; AWS: object GenerateDataKey/Decrypt using the selected ARN
Azure Key Vault Adapter required Managed identity Sign and wrap/unwrap
Google Cloud KMS Adapter required Workload identity Sign and envelope protection