Sovra Sovra

Control Plane Initialization

This guide covers initializing a new Sovra control plane deployment.

Overview

The init-control-plane.sh script bootstraps a Sovra control plane:

  1. Runs database migrations
  2. Initializes Vault (bundled or external)
  3. Creates the first admin user
  4. Generates the admin Customer Root Key (CRK)

Prerequisites

Quick Start

# From the Sovra repository root
./scripts/init-control-plane.sh \
  --db-url "postgres://user:pass@localhost:5432/sovra" \
  --admin-email "admin@example.com"

Script Options

Option Description Required Default
--db-url PostgreSQL connection URL Yes -
--vault-addr Vault server address No http://127.0.0.1:8200
--vault-mode bundled or external No bundled
--admin-email Admin user email Yes -
--shares Number of CRK shares No 5
--threshold CRK reconstruction threshold No 3
--skip-db Skip database migrations No false
--skip-vault Skip Vault initialization No false

Examples

Basic Initialization

./scripts/init-control-plane.sh \
  --db-url "postgres://sovra:secret@db.example.com:5432/sovra?sslmode=require" \
  --admin-email "admin@company.com"

External Vault

export VAULT_TOKEN="s.abc123..."

./scripts/init-control-plane.sh \
  --db-url "postgres://sovra:secret@db.example.com:5432/sovra" \
  --vault-addr "https://vault.company.com:8200" \
  --vault-mode external \
  --admin-email "admin@company.com"

Custom Key Sharing

For larger organizations requiring more key custodians:

./scripts/init-control-plane.sh \
  --db-url "postgres://localhost:5432/sovra" \
  --admin-email "admin@example.com" \
  --shares 7 \
  --threshold 4

Skip Specific Steps

Re-run initialization after fixing an issue:

# Skip database (already migrated)
./scripts/init-control-plane.sh \
  --db-url "..." \
  --admin-email "..." \
  --skip-db

# Skip Vault (already initialized)
./scripts/init-control-plane.sh \
  --db-url "..." \
  --admin-email "..." \
  --skip-vault

Output Files

The script creates sensitive files that must be secured:

vault-init-secrets.json

Contains Vault unseal keys and root token (bundled mode only):

{
  "unseal_keys_b64": ["...", "...", "...", "...", "..."],
  "unseal_keys_hex": ["...", "...", "...", "...", "..."],
  "unseal_shares": 5,
  "unseal_threshold": 3,
  "recovery_keys_b64": [],
  "recovery_keys_hex": [],
  "recovery_keys_shares": 0,
  "recovery_keys_threshold": 0,
  "root_token": "hvs...."
}

Security:

admin-crk-shares.json

Contains the admin CRK shares for key ceremony:

{
  "public_key": "base64...",
  "shares": [
    {"index": 1, "value": "base64..."},
    {"index": 2, "value": "base64..."},
    {"index": 3, "value": "base64..."},
    {"index": 4, "value": "base64..."},
    {"index": 5, "value": "base64..."}
  ]
}

Security:

Vault Configuration

The script configures Vault with:

Secret Engines

Path Type Purpose
transit Transit Encryption/decryption (org KEK keys, CRK operations)
pki PKI Certificate authority (edge nodes, mTLS)

PKI Configuration

Audit Logging

Vault audit log enabled at /var/log/vault/audit.log

Database Tables

The migrations create these tables (36 migrations total):

Table Purpose
organizations Organization records
crks Customer Root Key metadata
crk_shares CRK share data
crk_encrypted_shares Password-protected CRK shares
workspaces Key workspaces
workspace_participants Workspace org membership
workspace_dek_wrapped Wrapped DEKs per org
workspace_invitations Pending workspace invitations
workspace_group_bindings Workspace-to-group bindings
federations Federation partnerships
policies OPA Rego access control policies
audit_events Immutable audit trail
edge_nodes Registered edge nodes
admin_identities Admin users (with mTLS cert, enrollment)
user_identities SSO user identities
service_identities Service accounts
device_identities Device identities
identity_groups Identity groups (with optional IdP binding)
group_memberships Group-to-identity membership
group_join_requests Pending group join requests
roles Role definitions
role_assignments Role-to-identity assignments
share_distributions CRK share distribution records
emergency_access_requests Break-glass access requests
account_recoveries Account recovery sessions
backups Backup metadata
direct_messages Encrypted direct messages

Troubleshooting

Database Connection Failed

[ERROR] Cannot connect to database

Vault Connection Failed

[ERROR] Cannot connect to external Vault

Admin Already Exists

[INFO] Admin user already exists

This is safe - the script is idempotent. The existing admin is unchanged.

CRK Generation Failed

[ERROR] Failed to generate CRK

Post-Initialization

After successful initialization:

  1. Secure the secrets files
    # Encrypt and backup
    gpg -c vault-init-secrets.json
    gpg -c admin-crk-shares.json
       
    # Securely delete originals
    shred -u vault-init-secrets.json admin-crk-shares.json
    
  2. Distribute CRK shares
    • Contact each key custodian
    • Transfer shares via secure channel
    • Verify each custodian has stored their share
  3. Start control plane services
    # Docker
    docker build -t sovra:latest -f Dockerfile .
    docker run -d -p 8080:8080 sovra:latest
    
    # Or run directly
    ./bin/api-gateway
    
  4. Verify deployment
    # Check health
    curl https://sovra.example.com/health
    
    # Admin operations use mTLS
    sovra --cert admin.crt --key admin.key workspace list
    

Security Considerations

  1. Network Isolation: Run initialization from within the trusted network
  2. TLS: Use HTTPS for all Vault and database connections in production
  3. Key Rotation: Plan for annual CRK rotation
  4. Backup: Create encrypted backups before initialization