Skip to main content
This guide deploys a three-node citadel-core cluster on Kubernetes. Key material is generated offline, stored as Kubernetes Secrets, and mounted read-only into distroless containers that run as a non-root user.

Prerequisites

  • A Kubernetes cluster (v1.24 or later) with kubectl access, at least three worker nodes, and a persistent-storage provisioner.
  • NATS with JetStream and Consul, either in the cluster (the official NATS and Consul Helm charts are the recommended route) or external and reachable from it.
  • On a secure workstation: citadel-core-cli, age, and kubectl.
  • The citadel-core container image from Blockops, available to your cluster’s registry.

Generate key material offline

1

Peer registry

Pod names in a StatefulSet are citadel-core-0, citadel-core-1, citadel-core-2. Edit peers.json so its node names match those pod names.
2

Event initiator

The encrypted private key goes to citadel-api; keep its password in your secrets manager.
3

Node identities

Record each identity password.
4

Chain code

One value, shared by every node, set as chain_code in the ConfigMap.

Create the namespace, secrets and configuration

Back up the share-store password immediately. BadgerDB encrypts the store under it at creation and it cannot be changed afterwards. In production, source both passwords from External Secrets Operator or Sealed Secrets rather than --from-literal.
Shared configuration:

Register peers in Consul

Alternatively, pass --peers=/app/peers.json to the node at start-up (as the manifest below does) and each node syncs the registry into Consul itself.

Deploy the StatefulSet

Use /health only as the readiness probe. It returns 503 while a node is still exchanging keys with its peers at start-up; a liveness probe on it would kill nodes that are initialising. Use a TCP probe for liveness, as above.

Restrict network access

Nodes need to reach each other, NATS and Consul, and nothing else:

Verify

Expect the version banner, Connected to badger kv store, Loaded peers from consul, [READY] Node is ready and Starting consumers. In Consul’s key-value store, mpc_peers/ lists the three nodes. Then run a key generation from citadel-api to confirm the cluster signs end to end. The image is distroless: there is no shell inside it. To inspect a running pod, attach an ephemeral debug container: kubectl debug -n citadel-core <pod> -it --image=busybox --target=citadel-core.

Next

Operate a cluster covers backups, upgrades, adding nodes and recovering a lost pod; the security checklist covers what to lock down before production.