Deployment
ScaiVault is a stateless container plus a PostgreSQL database, a Redis cache, and a KMS. Everything else — object storage, DNS providers, federated backends — is optional.
Prerequisites#
- PostgreSQL 14+. Dedicated database with a dedicated user. Expect ~10 GB per 100k secrets including history.
- Redis 7+. Single instance is fine for low-volume deployments; cluster for HA.
- A KMS. AWS KMS, GCP KMS, Azure Key Vault, HashiCorp Vault, or a PKCS#11 HSM. ScaiVault stores only a wrapped root key locally.
- ScaiKey. An instance you control, or the managed
scaikey.scailabs.ai. - Object storage (optional). S3-compatible. Used for large artifacts (certs, CRLs, audit exports). In-DB fallback works but limits how large those artifacts can be.
Configuration#
All configuration is via environment variables.
Core#
| Variable | Required | Description |
|---|---|---|
DATABASE_URL |
Yes | postgresql://user:pass@host:5432/scaivault?sslmode=require |
REDIS_URL |
Yes | redis://host:6379/0 or rediss:// for TLS |
SCAIKEY_URL |
Yes | https://scaikey.scailabs.ai |
SCAIKEY_JWKS_URL |
No | Override auto-discovery |
BIND_ADDRESS |
No | Default 0.0.0.0:8443 |
BASE_URL |
Yes | Your public ScaiVault URL |
LOG_LEVEL |
No | info (default), debug, warn, error |
LOG_FORMAT |
No | json (default) or text |
KMS#
Pick one. Provider auth is via the cloud provider's standard mechanisms (IAM role, workload identity, etc.) unless you specify static credentials.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | |
Object storage (optional)#
1 2 3 4 5 6 | |
Providers: s3, gcs, azure_blob, minio.
Identity cache sync#
1 2 | |
Rate limits (optional override)#
1 2 3 4 5 6 7 | |
See Rate Limiting for the full list of categories.
Single-node Docker#
For development or small deployments:
1 2 3 4 5 6 7 8 9 | |
The container runs the API on port 8443 with TLS terminated upstream. For TLS at the container, mount certs and set TLS_CERT_FILE / TLS_KEY_FILE.
Kubernetes#
A minimal Deployment:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | |
3 replicas is a good starting point. Scale horizontally — ScaiVault instances are stateless.
First-boot setup#
On first boot, ScaiVault:
- Runs database migrations.
- Generates an initial encryption root (wrapped by your KMS).
- Creates a bootstrap
super_adminuser as configured byBOOTSTRAP_SUPER_ADMIN.
For production, configure:
1 | |
First person signs in via ScaiKey with that email, gets promoted to super_admin automatically. After first login, set BOOTSTRAP_SUPER_ADMIN= (empty) to disable.
Database migrations#
On startup, ScaiVault checks migration state. If ahead of the schema it expects, it refuses to start. If behind, by default it migrates automatically. To run migrations as a separate step:
1 2 3 | |
Then start the API with --no-migrate (or set MIGRATE_ON_START=false).
TLS#
ScaiVault expects TLS termination. Typical setups:
- Load balancer terminates (ALB, GLB, Traefik, nginx-ingress). ScaiVault listens HTTP internally.
- ScaiVault terminates. Set
TLS_CERT_FILEandTLS_KEY_FILE. Certs from your PKI. - mTLS internal. Additional
TLS_CLIENT_CA_FILEforces client cert authentication on top of bearer tokens.
Scaling#
- API pods: stateless. Scale to taste; 3 is a sensible minimum.
- Postgres: single-writer, one or more replicas. ScaiVault can route reads to replicas with
DATABASE_URL_READ=postgresql://.... - Redis: single-instance works up to tens of thousands of concurrent identities; cluster mode beyond that.
High availability#
- Run at least 3 API pods across failure domains.
- Postgres streaming replication + automated failover (Patroni, Cloud SQL, RDS Multi-AZ).
- Redis Sentinel or cluster mode.
- KMS: use a regional key with cross-region replication; ScaiVault supports failover to a secondary key if the primary is unreachable (
KMS_KEY_ID_SECONDARY).
Backup and recovery#
What to back up:
- PostgreSQL: full + WAL.
- Object store bucket (if used).
- KMS key policy (so you can restore access).
What NOT to back up separately:
- The plaintext root key — it never leaves the KMS.
- Application container state — everything interesting is in Postgres.
Recovery test: restore DB to a staging cluster, point at a test KMS key wrapped by the same rehydrated material, verify a secret reads correctly. Do this at least annually.