External key management

Deploy and authorize X2 KMS

X2 KMS is an independent sealed service. Initialize one member once, use the same root token and five unseal shares for the cluster, and unseal every member locally after restart.

01

Plan custody and addresses

  • Dedicated encrypted storage and Raft paths
  • HTTPS API on TCP 18200
  • Raft peer traffic on TCP 18201
  • Unique node ID and peer address per member
  • Separate server and peer TLS trust
  • Three-of-five unseal custody procedure
No automated unseal: X2 Node and the web console never receive or submit KMS unseal shares.
02

Download X2 KMS and its service installer

Operating system
Architecture
Loading release catalog…
Loading release catalog…
Loading release catalog…
03

Install and start the sealed service

sudo bash ./install-x2-kms.sh \
  --binary "$(realpath ./x2-kms)" \
  --address 0.0.0.0:18200 --host kms.example.com
sudo systemctl enable --now x2-kms
Set-ExecutionPolicy -Scope Process Bypass
.\install-x2-kms-service.ps1 `
  -BinaryPath (Resolve-Path .\x2-kms.exe) `
  -Address '0.0.0.0:18200' -CertificateHost 'kms.example.com'
Start-Service X2KMS
Get-Content 'C:\ProgramData\X2KMS\kms.yaml'
Get-Content 'C:\ProgramData\X2KMS\logs\x2-kms-service.log' -Tail 100
sudo bash ./install-x2-kms.sh \
  --binary "$PWD/x2-kms" \
  --address 0.0.0.0:18200 --host kms.example.com

The service starts sealed. Its server certificate authenticates the KMS endpoint to clients; workload authorization is handled separately.

04

Initialize exactly one member

export X2_KMS_ADDR='https://127.0.0.1:18200'
export X2_KMS_SERVER_CERT='/var/lib/x2-kms/tls/kms-server.crt'
sudo /usr/lib/x2/x2-kms operator init
$env:X2_KMS_ADDR='https://127.0.0.1:18200'
$env:X2_KMS_SERVER_CERT='C:\ProgramData\X2KMS\tls\kms-server.crt'
& 'C:\Program Files\X2\x2-kms.exe' operator init
export X2_KMS_ADDR='https://127.0.0.1:18200'
export X2_KMS_SERVER_CERT='/usr/local/var/lib/x2-kms/tls/kms-server.crt'
sudo /usr/local/lib/x2/x2-kms operator init

Initialization returns one root token and five shares. Move them immediately to separate protected operator custody. Other cluster members initialize from replicated state.

05

Unseal each member locally

read -rsp 'Unseal share: ' SHARE
printf '%s' "$SHARE" | sudo /usr/lib/x2/x2-kms operator unseal --key -
unset SHARE
# Repeat with two different shares
Read-Host 'Unseal share' -MaskInput |
  & 'C:\Program Files\X2\x2-kms.exe' operator unseal --key -
# Repeat with two different shares
read -rsp 'Unseal share: ' SHARE
printf '%s' "$SHARE" | sudo /usr/local/lib/x2/x2-kms operator unseal --key -
unset SHARE
# Repeat with two different shares
06

Generate a separate workload identity for each X2 node

sudo /usr/lib/x2/x2-kms workloads generate-identity \
  --name node-1 --out-dir /var/lib/x2/state/secrets \
  --kms-endpoint https://kms.example.com:18200 \
  --server-certificate /var/lib/x2-kms/tls/kms-server.crt
& 'C:\Program Files\X2\x2-kms.exe' workloads generate-identity `
  --name node-1 --out-dir 'C:\ProgramData\X2\runtime\secrets' `
  --kms-endpoint 'https://kms.example.com:18200' `
  --server-certificate 'C:\ProgramData\X2KMS\tls\kms-server.crt'
sudo /usr/local/lib/x2/x2-kms workloads generate-identity \
  --name node-1 --out-dir /usr/local/var/lib/x2/state/secrets \
  --kms-endpoint https://kms.example.com:18200 \
  --server-certificate /usr/local/var/lib/x2-kms/tls/kms-server.crt

The command prints the workload ID, pinned client-key identifier, file paths, and exact environment variables. Never copy a node private key to another node.

07

Apply exact workload grants

workloads:
  - name: "x2w-storage-production"
    client_keys:
      - spki_sha256: "sha256:REPLACE_WITH_64_HEX_DIGEST"
    grants:
      - key: "x2-workload-x2w-storage-production-session-signing"
        operations: [ensure-key, public-key, sign]
      - key: "x2-workload-x2w-storage-production-credentials"
        operations: [ensure-key, generate-data-key, decrypt-data-key]
      - key: "x2-workload-x2w-storage-production-default-objects"
        operations: [ensure-key, generate-data-key, decrypt-data-key]

Restart members after grant changes and unseal them locally again. Customer object keys require a separate explicit grant.

08

Enable KMI on X2 Node

export X2_KMI_ENABLED=true
export X2_KMI_PROVIDER=x2-kms
export X2_X2KMS_ENDPOINT=https://kms.example.com:18200
export X2_X2KMS_WORKLOAD_ID=x2w-REPLACE
export X2_X2KMS_SERVER_CERT=/var/lib/x2/state/secrets/kms-server.crt
export X2_X2KMS_CLIENT_CERT=/var/lib/x2/state/secrets/node-1.crt
export X2_X2KMS_CLIENT_KEY=/var/lib/x2/state/secrets/node-1.key
[Environment]::SetEnvironmentVariable('X2_KMI_ENABLED','true','Machine')
[Environment]::SetEnvironmentVariable('X2_KMI_PROVIDER','x2-kms','Machine')
[Environment]::SetEnvironmentVariable('X2_X2KMS_ENDPOINT','https://kms.example.com:18200','Machine')
[Environment]::SetEnvironmentVariable('X2_X2KMS_WORKLOAD_ID','x2w-REPLACE','Machine')
[Environment]::SetEnvironmentVariable('X2_X2KMS_SERVER_CERT','C:\ProgramData\X2\runtime\secrets\kms-server.crt','Machine')
[Environment]::SetEnvironmentVariable('X2_X2KMS_CLIENT_CERT','C:\ProgramData\X2\runtime\secrets\node-1.crt','Machine')
[Environment]::SetEnvironmentVariable('X2_X2KMS_CLIENT_KEY','C:\ProgramData\X2\runtime\secrets\node-1.key','Machine')
sudo /usr/local/lib/x2/x2-node configure \
  --kmi-enabled --kmi-provider x2-kms \
  --x2-kms-endpoint https://kms.example.com:18200 \
  --x2-kms-workload-id x2w-REPLACE \
  --x2-kms-server-cert /usr/local/var/lib/x2/state/secrets/kms-server.crt \
  --x2-kms-client-cert /usr/local/var/lib/x2/state/secrets/node-1.crt \
  --x2-kms-client-key /usr/local/var/lib/x2/state/secrets/node-1.key
KMS integration complete

Restart X2 Node and verify its banner and health report KMI enabled before creating encrypted buckets.

Continue node installation →