Dara Docs
ReferenceSecurity

Key management

Who holds which key, where it lives, how it is rotated and what a compromise allows. The authority each key has on-chain is in AUTHORITY_MATRIX.md; this document is about the keys themselves.

Inventory

KeySignsLives inHeld by
H1…Hn (issuer signers)Issue, burn, clawback, issuer configuration (ceremony.Quorum: 4 signers 2 / 3; launch: 1 signer, 1 / 1)Launch: one software key on the signer's laptop (§1a; owner decision 2026-10-31)A person, never the platform
T1…Tn (Treasury signers)Refill and burn from COLD, COLD configuration, signer changes on HOT/SPONSOR/FUNDERLaunch: the same key as the issuer signerThe same person
role:AUTHTrustline authorize / revoke (issuer, weight 1 = LOW only)Platform signerWorker
role:HOTPayments from the hot Treasury (sales float)Platform signerWorker
role:SPONSORSponsoring new customer accounts' reservesPlatform signerWorker
role:FUNDERTopping up channel accounts with XLMPlatform signerWorker
role:CHANNELTransaction source (sequence and fee) for every platform transactionPlatform signerWorker
custody:CUSTOMERCustomer accounts (SELL, TRANSFER)Platform signerWorker
onboard:<customer>Only the customer account's creation transaction, which sets its master weight to 0Derived per customer from the onboarding seed (SIGNER_ONBOARD_SEED_FILE with the vault backend), never storedWorker
Database, MFA encryption key, session secrets—Secret store of the deploymentOperators

Human keys never touch the platform: the platform builds an envelope, the signer verifies it on their own device and uploads only a signature, which the platform verifies against the signer's public key and the hash (txmanager.AddSignature). Configuration carries only their public keys (ISSUER_SIGNERS, TREASURY_SIGNERS).

Signer backends

SIGNER_BACKEND selects how the online keys are held.

BackendStatusAllowed
derivedImplemented. Every online key is derived with HKDF-SHA256 from one 32-byte SIGNER_MASTER_SEED and a per-role labelAPP_ENV local, test or uat and a non-public network. It refuses APP_ENV=production and the Mainnet passphrase (signer.NewDerived)
vaultImplemented (§2). HashiCorp Vault or OpenBao Transit holds the online keys as non-exportable Ed25519 keys and signs hashes on requestEvery environment; the production choice (owner decision 2026-10-31)
Devsigners (stand-in H/T)Implemented for demos and testsLocal standalone network only

The derived master seed is therefore acceptable for local, demo and Testnet use only. The demo seed in deploy/demo/demo.env is public by design and works only on the local network.

1a. The launch signer key (software key on a laptop)

The owner chose one human signer holding a software key on a laptop. To keep that as safe as it can be:

  1. A laptop used only for signing: full-disk encryption, a strong login password, automatic screen lock, OS updates, no other software, browser use only for the admin console.
  2. The key is created on that laptop with the Stellar CLI (stellar keys generate dara-signer), and kept in its encrypted keystore or OS keychain. Only the public key (G…) leaves the laptop, into ISSUER_SIGNERS and TREASURY_SIGNERS.
  3. Signing: copy the envelope from Admin → Signing; decode it on the laptop (stellar xdr decode --type TransactionEnvelope) and check the network passphrase, source accounts, operations, assets and amounts; sign it (stellar tx sign --sign-with-key dara-signer --network mainnet); paste the printed signed envelope with your public key on the Signing page (a bare base64 signature is accepted too). The server checks the signature against the proposal's hash. Never sign an envelope that did not come from the Signing page. (Commands as in recent Stellar CLI releases; check them against stellar --help of the installed version.)
  4. Backup: one encrypted copy of the secret key, offline (a USB key in a safe, or paper), tested once a quarter by checking that its public key matches.
  5. If the laptop is lost or may be compromised: treat it as an incident at once (../operations/INCIDENT_RESPONSE.md, key compromise). If the key is still available, rotate it immediately (§Rotation, human signer).

2. Vault Transit (online keys)

SIGNER_BACKEND=vault. The operator runs Vault or OpenBao, then creates the keys and the backend's token with deploy/vault/setup-transit.sh (PREFIX=dara-mainnet-):

  • keys <prefix>auth, hot, sponsor, funder, channel, custody-customer: Ed25519, not exportable, no plaintext backup, deletion not allowed;
  • a policy that allows only read on those keys and update on their sign path, and a periodic orphan token bound to it (renew within 768 h). The backend can never export, rotate, delete or reconfigure a key.

The backend refuses a key that is exportable, allows plaintext backup or is derived; it pins each key to the version whose public key it resolved (a rotation inside Vault would otherwise change the Stellar signer silently) and verifies every signature locally before using it. dara keys prints the public keys for the ceremony. Secrets come from files: VAULT_TOKEN_FILE, SIGNER_ONBOARD_SEED_FILE (64 hex characters, from openssl rand -hex 32); TLS with VAULT_CACERT. Health feeds the trading gate (signer_unavailable). make vault-test runs the backend against a throwaway OpenBao and applies a Vault-signed transaction on local Stellar.

Rotating an online key held in Vault is the rotation in the next section: create a new Vault key (new name), add it to the account on-chain, remove the old one, then point the backend at it.

Rotation

KeyHowApproval
role:HOT, role:SPONSOR, role:FUNDERAdd the new key as signer of the account, remove the old one (SetOptions). These accounts carry every Treasury signer (weight 10 each) beside the online key, high threshold 20 (ceremony.OnlineLayout)The online key plus one Treasury signer, or two Treasury signers
role:AUTH (issuer signer, weight 1)Replace on each issuer accountThe issuer's high threshold (launch: the one signer)
role:CHANNELChannel accounts have only the channel key (weight 1). Rotation = create new channel accounts with the new key, register them, then merge the old ones into the funderOperations; no human signature (channels hold only fee XLM)
custody:CUSTOMERCustomer accounts have only the custody key (weight 1, master 0). Planned rotation: the old key adds the new one and removes itself, in batches. If the old key is compromised it cannot be trusted to do that: freeze, claw back, re-issue to fresh accountsRotation: operations with four-eyes; compromise: CLAWBACK_POLICY.md
Human signerRemaining signers replace the signer at the high threshold. With one signer, only that signer can replace its own key, and only while it still has itFour-eyes in the console plus the on-chain threshold
SIGNER_MASTER_SEED (non-production)Rotating it changes every derived key: a new account ceremony—

After any rotation the account manifest is unchanged (accounts stay), but the startup check (app.VerifyAccounts) compares on-chain signers with the configured keys and refuses to start until they agree.

Backup and loss

  • Human keys: with three or more signers, losing one is survivable (the thresholds from ceremony.Quorum stay reachable; TestLayoutsForEachSignerCount) and the others rotate it out. With the launch configuration of one signer there is no tolerance: losing the key locks the issuer and the cold Treasury for good (accepted risk, ../decisions/OWNER_DECISIONS_20261031.md). The owner chose no hardware key; an encrypted offline copy of the secret key (§1a) is still strongly advised.
  • Online keys (Vault): Vault's own snapshots (Raft) back up the sealed keys; the unseal keys or the auto-unseal key are held as the Vault policy requires. HOT, SPONSOR, FUNDER and the issuer's AUTH slot also have human signers who can add a replacement key; channels are simply replaced.
  • Customer custody key: it is the only signer of every customer account, so it must be backed up like the issuer's keys. If it were lost, the tokens are still recoverable by the issuer (clawback, then re-issue to new accounts); the accounts' XLM reserves are sponsored and are released when the accounts are merged or abandoned.

Compromise

The impact of each key is in AUTHORITY_MATRIX.md §2. Detection is the indexer: any movement or authority change without a matching intent opens a CRITICAL incident that stops trading. Response: ../operations/INCIDENT_RESPONSE.md.

Rules enforced in code

  • The signer is the only package that touches private keys; business code passes references.
  • A signer is bound to one network at construction; Stellar signatures cover the hash, which commits to the network passphrase, so signatures cannot be replayed across networks.
  • Dev signers and the derived backend refuse Mainnet; bootstrap-local, seed and demo refuse every network but local.
  • Secrets never appear in logs (config.LogValue redacts them); seed files are git-ignored.

On this page