Keep the personal half of the desktop in one place, and ask before installing it
Agent instructions, skills, SSH host aliases and expansion triggers are worth having identical on every machine one person owns, and belong in none of the shared configuration. They live in user/ now, with a manifest saying where each piece goes and a link-user stage that puts it there. That stage does nothing unless the machine said yes. Somebody who clones Panama to try the desktop keeps their own ~/.claude/CLAUDE.md exactly where it was; the question names the destinations and defaults to no. Anything displaced goes to config/old rather than being deleted. ~/.claude/CLAUDE.md and ~/.codex/AGENTS.md were byte-identical copies of one file, which is the drift this exists to prevent. Also adds the vitals toggles for the battery and Claude usage readouts, which had preferences and no way to reach them.
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
---
|
||||
name: infisical-self-host
|
||||
description: Deploy and operate Infisical self-hosted instances with Docker, Docker Compose, and Kubernetes. Covers architecture, environment variables, ENCRYPTION_KEY management, database setup, Redis configuration, production hardening, FIPS compliance, scaling, and high availability patterns.
|
||||
triggers:
|
||||
- self-host infisical
|
||||
- deploy infisical
|
||||
- docker compose infisical
|
||||
- infisical docker
|
||||
- helm chart infisical
|
||||
- kubernetes infisical
|
||||
- ENCRYPTION_KEY
|
||||
- infisical environment variables
|
||||
- production deployment infisical
|
||||
- FIPS infisical
|
||||
- scale infisical
|
||||
- ha infisical
|
||||
---
|
||||
|
||||
# Infisical Self-Hosted Deployment
|
||||
|
||||
This skill guides you through deploying, configuring, and operating Infisical in self-hosted environments. Whether you are running Infisical on Docker, Docker Compose, or Kubernetes, this resource covers essential setup, security hardening, scaling, and maintenance patterns.
|
||||
|
||||
## Guiding Principles
|
||||
|
||||
1. **ENCRYPTION_KEY is Critical**: This key encrypts all secrets at rest. It is 16 bytes (32 hex characters), generated with `openssl rand -hex 16`, and **cannot be recovered if lost**. Back it up and rotate it carefully following Infisical's rotation procedures.
|
||||
|
||||
2. **AUTH_SECRET is Required**: This key is used for session and JWT signing. It is 32 bytes (base64), generated with `openssl rand -base64 32`, and must be stable across restarts.
|
||||
|
||||
3. **Database Requirements**: PostgreSQL 14+ is required. Always backup your database before upgrading Infisical. Schema migrations run automatically on boot (since v0.111.0-postgres).
|
||||
|
||||
4. **Redis Configuration**: Redis 6.2+ is required. Cluster mode is NOT supported; use standalone or Redis Sentinel for high availability. Standalone mode is simplest for development; use Sentinel for production HA.
|
||||
|
||||
5. **Stateless Architecture**: Infisical is stateless. Scale horizontally by adding more replicas. All state lives in PostgreSQL and Redis.
|
||||
|
||||
6. **FIPS Compliance**: FIPS 140-2 mode is available via the `infisical/infisical:latest-fips` image. Enable with `FIPS_ENABLED=true` and appropriate Node.js options.
|
||||
|
||||
## Quick Start
|
||||
|
||||
- **Docker Standalone**: Pull `infisical/infisical:<version>`, set environment variables, run on port 8080.
|
||||
- **Docker Compose**: Use `docker-compose.prod.yml` from the repository with PostgreSQL and Redis services.
|
||||
- **Kubernetes**: Deploy via Helm chart `infisical-standalone-postgres` from Cloudsmith registry with optional managed databases.
|
||||
|
||||
## Reference Guides
|
||||
|
||||
### [Environment Variables](./references/environment-variables.md)
|
||||
Complete reference for all configuration environment variables, including:
|
||||
- Required keys (ENCRYPTION_KEY, AUTH_SECRET, database, Redis)
|
||||
- Database and replication setup
|
||||
- Redis with Sentinel support
|
||||
- SMTP configuration
|
||||
- OAuth/SSO providers
|
||||
- FIPS and telemetry settings
|
||||
- Security options
|
||||
|
||||
### [Docker Deployment](./references/docker-deployment.md)
|
||||
Docker and Docker Compose deployment patterns, including:
|
||||
- Standalone container setup
|
||||
- Docker Compose production stack
|
||||
- Image variants (standard and FIPS)
|
||||
- Production hardening with security capabilities and read-only filesystems
|
||||
- Health checks
|
||||
|
||||
### [Kubernetes Deployment](./references/kubernetes-deployment.md)
|
||||
Kubernetes and Helm deployment guide, including:
|
||||
- Helm chart installation and configuration
|
||||
- Secret creation and management
|
||||
- Optional PostgreSQL and Redis (Bitnami charts)
|
||||
- Pod security and RBAC
|
||||
- Networking policies and Ingress/TLS
|
||||
|
||||
### [Scaling and High Availability](./references/scaling-and-ha.md)
|
||||
Production scaling patterns and HA architecture, including:
|
||||
- Horizontal scaling (adding replicas)
|
||||
- Sizing guidelines for Infisical, PostgreSQL, and Redis
|
||||
- Database read replicas
|
||||
- Redis Sentinel for HA
|
||||
- Backup and upgrade procedures
|
||||
- License server firewall rules
|
||||
@@ -0,0 +1,405 @@
|
||||
# Docker Deployment Guide
|
||||
|
||||
Deploy Infisical using Docker or Docker Compose for flexible, containerized self-hosted environments.
|
||||
|
||||
## Docker Standalone Container
|
||||
|
||||
### Quick Start
|
||||
|
||||
1. Pull the image:
|
||||
```bash
|
||||
docker pull infisical/infisical:latest
|
||||
```
|
||||
|
||||
2. Create a `.env` file with required configuration:
|
||||
```bash
|
||||
ENCRYPTION_KEY=$(openssl rand -hex 16)
|
||||
AUTH_SECRET=$(openssl rand -base64 32)
|
||||
DB_CONNECTION_URI="postgresql://user:[email protected]:5432/infisical"
|
||||
REDIS_URL="redis://redis.example.com:6379"
|
||||
SITE_URL="https://secrets.example.com"
|
||||
SMTP_HOST="smtp.example.com"
|
||||
SMTP_PORT="587"
|
||||
SMTP_USERNAME="[email protected]"
|
||||
SMTP_PASSWORD="password"
|
||||
SMTP_FROM_ADDRESS="[email protected]"
|
||||
```
|
||||
|
||||
3. Run the container:
|
||||
```bash
|
||||
docker run -d \
|
||||
--name infisical \
|
||||
--env-file .env \
|
||||
-p 8080:8080 \
|
||||
infisical/infisical:latest
|
||||
```
|
||||
|
||||
4. Verify the container is running:
|
||||
```bash
|
||||
curl http://localhost:8080/api/status
|
||||
```
|
||||
|
||||
### Image Variants
|
||||
|
||||
#### Standard Image
|
||||
```bash
|
||||
docker pull infisical/infisical:latest
|
||||
docker pull infisical/infisical:v0.110.0 # Specific version
|
||||
```
|
||||
|
||||
#### FIPS 140-2 Compliant Image
|
||||
Use the FIPS image for regulated environments requiring FIPS compliance:
|
||||
|
||||
```bash
|
||||
docker pull infisical/infisical:latest-fips
|
||||
```
|
||||
|
||||
When using the FIPS image, set:
|
||||
```bash
|
||||
FIPS_ENABLED=true
|
||||
NODE_OPTIONS="--max-old-space-size=8192 --force-fips"
|
||||
```
|
||||
|
||||
## Docker Compose Deployment (Production)
|
||||
|
||||
The repository includes `docker-compose.prod.yml` for complete production setups with PostgreSQL and Redis.
|
||||
|
||||
### Basic docker-compose.yml
|
||||
|
||||
Create a `docker-compose.yml` file:
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:14-alpine
|
||||
container_name: infisical-postgres
|
||||
environment:
|
||||
POSTGRES_USER: infisical
|
||||
POSTGRES_PASSWORD: infisical_db_password
|
||||
POSTGRES_DB: infisical
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- infisical-network
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U infisical"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: infisical-redis
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
networks:
|
||||
- infisical-network
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
infisical:
|
||||
image: infisical/infisical:latest
|
||||
container_name: infisical-api
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
ENCRYPTION_KEY: ${ENCRYPTION_KEY}
|
||||
AUTH_SECRET: ${AUTH_SECRET}
|
||||
DB_CONNECTION_URI: postgresql://infisical:infisical_db_password@postgres:5432/infisical
|
||||
REDIS_URL: redis://redis:6379
|
||||
SITE_URL: https://secrets.example.com
|
||||
SMTP_HOST: ${SMTP_HOST}
|
||||
SMTP_PORT: ${SMTP_PORT}
|
||||
SMTP_USERNAME: ${SMTP_USERNAME}
|
||||
SMTP_PASSWORD: ${SMTP_PASSWORD}
|
||||
SMTP_FROM_ADDRESS: ${SMTP_FROM_ADDRESS}
|
||||
ports:
|
||||
- "80:8080"
|
||||
networks:
|
||||
- infisical-network
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8080/api/status"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
redis_data:
|
||||
|
||||
networks:
|
||||
infisical-network:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
Create a `.env` file in the same directory:
|
||||
|
||||
```bash
|
||||
# Generated keys
|
||||
ENCRYPTION_KEY=a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8
|
||||
AUTH_SECRET=VUJrQV9FbmNyeXB0aW9uS2V5XzMyQnl0ZXNfQmFzZTY0RW5jb2RlZA==
|
||||
|
||||
# SMTP Configuration
|
||||
SMTP_HOST=smtp.gmail.com
|
||||
SMTP_PORT=587
|
||||
SMTP_USERNAME=[email protected]
|
||||
SMTP_PASSWORD=your-app-password
|
||||
SMTP_FROM_ADDRESS=[email protected]
|
||||
```
|
||||
|
||||
### Start the Services
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
Monitor logs:
|
||||
```bash
|
||||
docker-compose logs -f infisical
|
||||
```
|
||||
|
||||
### Upgrade
|
||||
|
||||
1. Backup the PostgreSQL database:
|
||||
```bash
|
||||
docker-compose exec postgres pg_dump -U infisical infisical > backup.sql
|
||||
```
|
||||
|
||||
2. Pull the new image:
|
||||
```bash
|
||||
docker pull infisical/infisical:latest
|
||||
```
|
||||
|
||||
3. Restart the services:
|
||||
```bash
|
||||
docker-compose down
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
Schema migrations run automatically on startup.
|
||||
|
||||
## External Databases
|
||||
|
||||
If using managed PostgreSQL (RDS, Cloud SQL, Azure Database) or managed Redis (ElastiCache, Cloud Memorystore, Azure Cache), configure the connection URIs directly:
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
DB_CONNECTION_URI: postgresql://user:[email protected]:5432/infisical
|
||||
DB_ROOT_CERT: ${DB_ROOT_CERT} # Set if TLS certificate verification is required
|
||||
REDIS_URL: rediss://redis-instance.cache.amazonaws.com:6380 # TLS enabled
|
||||
```
|
||||
|
||||
For TLS certificates, base64-encode and pass as `DB_ROOT_CERT`:
|
||||
```bash
|
||||
cat /path/to/ca.pem | base64 -w 0 > /tmp/cert.b64
|
||||
export DB_ROOT_CERT=$(cat /tmp/cert.b64)
|
||||
```
|
||||
|
||||
## Production Hardening
|
||||
|
||||
### Read-Only Root Filesystem
|
||||
|
||||
Run the container with a read-only root filesystem and temporary writable mounts:
|
||||
|
||||
```yaml
|
||||
infisical:
|
||||
image: infisical/infisical:latest
|
||||
read_only: true
|
||||
tmpfs:
|
||||
- /tmp
|
||||
- /app/node_modules/.cache
|
||||
```
|
||||
|
||||
This limits the attack surface if the container is compromised.
|
||||
|
||||
### Drop Capabilities
|
||||
|
||||
Drop unnecessary Linux capabilities:
|
||||
|
||||
```yaml
|
||||
infisical:
|
||||
image: infisical/infisical:latest
|
||||
cap_drop:
|
||||
- ALL
|
||||
cap_add:
|
||||
- NET_BIND_SERVICE
|
||||
```
|
||||
|
||||
### Resource Limits
|
||||
|
||||
Set memory and CPU limits:
|
||||
|
||||
```yaml
|
||||
infisical:
|
||||
image: infisical/infisical:latest
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '2'
|
||||
memory: 4G
|
||||
reservations:
|
||||
cpus: '1'
|
||||
memory: 2G
|
||||
```
|
||||
|
||||
Adjust based on your expected load.
|
||||
|
||||
### Network Security
|
||||
|
||||
Restrict network access:
|
||||
|
||||
```yaml
|
||||
networks:
|
||||
infisical-network:
|
||||
driver: bridge
|
||||
driver_opts:
|
||||
com.docker.network.bridge.name: br-infisical
|
||||
```
|
||||
|
||||
Use separate networks for different components (application, database, cache).
|
||||
|
||||
## Health Checks
|
||||
|
||||
The Infisical container exposes a health check endpoint:
|
||||
|
||||
```
|
||||
GET /api/status
|
||||
```
|
||||
|
||||
This returns HTTP 200 if the service is healthy.
|
||||
|
||||
### Docker Compose Health Check Configuration
|
||||
|
||||
```yaml
|
||||
infisical:
|
||||
image: infisical/infisical:latest
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8080/api/status"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
```
|
||||
|
||||
## Logging
|
||||
|
||||
### JSON Logging
|
||||
|
||||
Logs are output as JSON for better integration with log aggregation systems:
|
||||
|
||||
```bash
|
||||
docker-compose logs infisical | jq '.msg'
|
||||
```
|
||||
|
||||
### Log File Output
|
||||
|
||||
Mount a volume to persist logs:
|
||||
|
||||
```yaml
|
||||
infisical:
|
||||
image: infisical/infisical:latest
|
||||
volumes:
|
||||
- ./logs:/app/logs
|
||||
environment:
|
||||
LOG_DIR: /app/logs
|
||||
```
|
||||
|
||||
## Networking
|
||||
|
||||
### Reverse Proxy (Nginx)
|
||||
|
||||
Use Nginx to reverse proxy traffic to Infisical:
|
||||
|
||||
```nginx
|
||||
upstream infisical {
|
||||
server infisical:8080;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name secrets.example.com;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/secrets.example.com/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/secrets.example.com/privkey.pem;
|
||||
|
||||
location / {
|
||||
proxy_pass http://infisical;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In your `.env`, set:
|
||||
```bash
|
||||
SITE_URL=https://secrets.example.com
|
||||
```
|
||||
|
||||
### Load Balancing
|
||||
|
||||
Deploy multiple Infisical containers behind a load balancer:
|
||||
|
||||
```yaml
|
||||
infisical-1:
|
||||
image: infisical/infisical:latest
|
||||
environment:
|
||||
DB_CONNECTION_URI: postgresql://...
|
||||
REDIS_URL: redis://...
|
||||
|
||||
infisical-2:
|
||||
image: infisical/infisical:latest
|
||||
environment:
|
||||
DB_CONNECTION_URI: postgresql://...
|
||||
REDIS_URL: redis://...
|
||||
|
||||
infisical-3:
|
||||
image: infisical/infisical:latest
|
||||
environment:
|
||||
DB_CONNECTION_URI: postgresql://...
|
||||
REDIS_URL: redis://...
|
||||
|
||||
loadbalancer:
|
||||
image: nginx:latest
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
```
|
||||
|
||||
All instances share the same PostgreSQL and Redis, making the service stateless and scalable.
|
||||
|
||||
## Backup and Recovery
|
||||
|
||||
### Backup PostgreSQL
|
||||
|
||||
```bash
|
||||
docker-compose exec postgres pg_dump -U infisical infisical > backup_$(date +%s).sql
|
||||
```
|
||||
|
||||
### Restore PostgreSQL
|
||||
|
||||
```bash
|
||||
docker-compose exec -T postgres psql -U infisical infisical < backup.sql
|
||||
```
|
||||
|
||||
### Backup Redis
|
||||
|
||||
```bash
|
||||
docker-compose exec redis redis-cli BGSAVE
|
||||
docker cp infisical-redis:/data/dump.rdb ./redis_backup.rdb
|
||||
```
|
||||
|
||||
Always backup before upgrading or making configuration changes.
|
||||
@@ -0,0 +1,294 @@
|
||||
# Environment Variables Reference
|
||||
|
||||
This guide covers all environment variables used to configure Infisical self-hosted deployments.
|
||||
|
||||
## Essential Security Keys
|
||||
|
||||
### ENCRYPTION_KEY
|
||||
**Required** – Master encryption key for all secrets at rest.
|
||||
|
||||
- **Format**: 16 bytes as hex (32 hex characters)
|
||||
- **Example**: `a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8`
|
||||
- **Generation**: `openssl rand -hex 16`
|
||||
- **Critical Notes**:
|
||||
- Cannot be recovered if lost
|
||||
- Must be stable across deployments and upgrades
|
||||
- Rotate using Infisical's key rotation procedures (enterprise feature)
|
||||
- Back up securely in a separate location
|
||||
|
||||
### AUTH_SECRET
|
||||
**Required** – Secret key for signing session tokens and JWTs.
|
||||
|
||||
- **Format**: 32 bytes as base64
|
||||
- **Example**: `VUJrQV9FbmNyeXB0aW9uS2V5XzMyQnl0ZXNfQmFzZTY0RW5jb2RlZA==`
|
||||
- **Generation**: `openssl rand -base64 32`
|
||||
- **Notes**:
|
||||
- Used for all authentication tokens
|
||||
- Must be stable and unique per deployment
|
||||
|
||||
## Database Configuration
|
||||
|
||||
### DB_CONNECTION_URI
|
||||
**Required** – PostgreSQL connection string.
|
||||
|
||||
- **Format**: `postgresql://user:password@host:port/database`
|
||||
- **Example**: `postgresql://infisical:[email protected]:5432/infisical`
|
||||
- **Requirements**:
|
||||
- PostgreSQL 14 or newer
|
||||
- `uuid-ossp` extension enabled: `CREATE EXTENSION IF NOT EXISTS "uuid-ossp";`
|
||||
- `pgcrypto` extension enabled: `CREATE EXTENSION IF NOT EXISTS pgcrypto;`
|
||||
|
||||
### DB_ROOT_CERT
|
||||
Optional – Base64-encoded PEM certificate for SSL/TLS verification of PostgreSQL.
|
||||
|
||||
- **Format**: Base64-encoded SSL certificate
|
||||
- **Usage**: For databases with self-signed or custom CA certificates
|
||||
- **Example**:
|
||||
```bash
|
||||
cat /path/to/ca.pem | base64 -w 0
|
||||
```
|
||||
- **Notes**: Verify SSL/TLS connections for managed database services (RDS, Cloud SQL, Azure Database)
|
||||
|
||||
### DB_READ_REPLICAS
|
||||
Optional – JSON array of read-only database replicas.
|
||||
|
||||
- **Format**: JSON array of connection objects
|
||||
- **Example**:
|
||||
```json
|
||||
[
|
||||
{"connectionString": "postgresql://user:pass@replica1:5432/infisical"},
|
||||
{"connectionString": "postgresql://user:pass@replica2:5432/infisical"}
|
||||
]
|
||||
```
|
||||
- **Use Case**: Distribute read-heavy workloads across multiple database replicas
|
||||
- **Requirements**: Read replicas must be in sync with primary
|
||||
|
||||
## Redis Configuration
|
||||
|
||||
### REDIS_URL
|
||||
**Required** – Redis connection string.
|
||||
|
||||
- **Format**: `redis://[:password@]host:port[/db]` or `rediss://...` for TLS
|
||||
- **Examples**:
|
||||
- Standard: `redis://redis.example.com:6379`
|
||||
- With auth: `redis://:password@redis.example.com:6379`
|
||||
- TLS: `rediss://redis.example.com:6380`
|
||||
- **Requirements**: Redis 6.2 or newer
|
||||
- **Important**: Redis Cluster mode is NOT supported; use standalone or Sentinel
|
||||
|
||||
### Redis Sentinel (High Availability)
|
||||
|
||||
Use these variables to configure Redis Sentinel for HA without Cluster mode.
|
||||
|
||||
#### REDIS_SENTINEL_HOSTS
|
||||
Comma-separated list of Sentinel node addresses.
|
||||
|
||||
- **Format**: `host1:port1,host2:port2,host3:port3`
|
||||
- **Example**: `sentinel1.example.com:26379,sentinel2.example.com:26379,sentinel3.example.com:26379`
|
||||
|
||||
#### REDIS_SENTINEL_MASTER_NAME
|
||||
Name of the Redis master monitored by Sentinel.
|
||||
|
||||
- **Example**: `mymaster`
|
||||
- **Default**: `mymaster` (if not specified)
|
||||
|
||||
#### REDIS_SENTINEL_ENABLE_TLS
|
||||
Enable TLS for Sentinel connections.
|
||||
|
||||
- **Format**: `true` or `false`
|
||||
- **Default**: `false`
|
||||
|
||||
#### REDIS_SENTINEL_USERNAME
|
||||
Username for Sentinel authentication (if required).
|
||||
|
||||
#### REDIS_SENTINEL_PASSWORD
|
||||
Password for Sentinel authentication.
|
||||
|
||||
## SMTP Configuration
|
||||
|
||||
SMTP is required for email-based features. Without SMTP configured, the following features are disabled:
|
||||
- Multi-factor authentication (MFA) via email
|
||||
- Email invitations
|
||||
- Suspicious login alerts
|
||||
- Password reset emails
|
||||
|
||||
### SMTP_HOST
|
||||
**Required if SMTP enabled** – SMTP server hostname.
|
||||
|
||||
- **Example**: `smtp.gmail.com`
|
||||
|
||||
### SMTP_PORT
|
||||
SMTP server port.
|
||||
|
||||
- **Default**: `587` (STARTTLS)
|
||||
- **Common Values**:
|
||||
- `587` — STARTTLS (recommended)
|
||||
- `465` — SMTPS (implicit TLS)
|
||||
- `25` — Unencrypted (not recommended for production)
|
||||
|
||||
### SMTP_USERNAME
|
||||
Username for SMTP authentication.
|
||||
|
||||
### SMTP_PASSWORD
|
||||
Password for SMTP authentication.
|
||||
|
||||
### SMTP_FROM_ADDRESS
|
||||
**Required if SMTP enabled** – Email address from which emails are sent.
|
||||
|
||||
- **Example**: `noreply@infisical.com`
|
||||
|
||||
### SMTP_FROM_NAME
|
||||
Display name for the sender.
|
||||
|
||||
- **Example**: `Infisical`
|
||||
- **Default**: `Infisical`
|
||||
|
||||
### SMTP_REQUIRE_TLS
|
||||
Require TLS connection (STARTTLS).
|
||||
|
||||
- **Format**: `true` or `false`
|
||||
- **Default**: `true`
|
||||
|
||||
### SMTP_IGNORE_TLS
|
||||
Ignore TLS certificate errors (useful for self-signed certificates in development).
|
||||
|
||||
- **Format**: `true` or `false`
|
||||
- **Default**: `false`
|
||||
- **Warning**: Do not use in production
|
||||
|
||||
## OAuth/SSO Configuration
|
||||
|
||||
### Google Login
|
||||
To enable Google OAuth login, register an OAuth 2.0 application in Google Cloud Console.
|
||||
|
||||
#### CLIENT_ID_GOOGLE_LOGIN
|
||||
Google OAuth client ID.
|
||||
|
||||
#### CLIENT_SECRET_GOOGLE_LOGIN
|
||||
Google OAuth client secret.
|
||||
|
||||
### GitHub Login
|
||||
Register an OAuth application at https://github.com/settings/developers.
|
||||
|
||||
#### CLIENT_ID_GITHUB_LOGIN
|
||||
GitHub OAuth client ID.
|
||||
|
||||
#### CLIENT_SECRET_GITHUB_LOGIN
|
||||
GitHub OAuth client secret.
|
||||
|
||||
### GitLab Login
|
||||
Register an OAuth application in your GitLab instance (or gitlab.com).
|
||||
|
||||
#### CLIENT_ID_GITLAB_LOGIN
|
||||
GitLab OAuth client ID.
|
||||
|
||||
#### CLIENT_SECRET_GITLAB_LOGIN
|
||||
GitLab OAuth client secret.
|
||||
|
||||
## Authentication Timeouts
|
||||
|
||||
### JWT_AUTH_LIFETIME
|
||||
Lifetime of access tokens.
|
||||
|
||||
- **Default**: `15m` (15 minutes)
|
||||
- **Format**: Valid Node.js duration string (e.g., `30m`, `1h`)
|
||||
|
||||
### JWT_REFRESH_LIFETIME
|
||||
Lifetime of refresh tokens.
|
||||
|
||||
- **Default**: `24h` (24 hours)
|
||||
- **Format**: Valid Node.js duration string
|
||||
|
||||
## Enterprise and Licensing
|
||||
|
||||
### LICENSE_KEY
|
||||
License key for Infisical Enterprise features.
|
||||
|
||||
- **Format**: Provided by Infisical upon enterprise subscription
|
||||
- **Features Enabled**: SAML, RBAC advanced features, audit logs, IP allowlisting, etc.
|
||||
|
||||
## FIPS 140-2 Compliance
|
||||
|
||||
FIPS mode is enabled using the `infisical/infisical:latest-fips` image with additional Node.js configuration.
|
||||
|
||||
### FIPS_ENABLED
|
||||
Enable FIPS 140-2 mode.
|
||||
|
||||
- **Format**: `true` or `false`
|
||||
- **Default**: `false`
|
||||
- **Requirement**: Must use `infisical/infisical:latest-fips` image
|
||||
|
||||
### NODE_OPTIONS
|
||||
Node.js runtime options for FIPS compliance.
|
||||
|
||||
- **For FIPS Mode**:
|
||||
```
|
||||
NODE_OPTIONS="--max-old-space-size=8192 --force-fips"
|
||||
```
|
||||
- **Notes**:
|
||||
- `--force-fips` enables FIPS mode
|
||||
- `--max-old-space-size` allocates memory for the Node.js heap (adjust based on load)
|
||||
|
||||
## Telemetry
|
||||
|
||||
### TELEMETRY_ENABLED
|
||||
Enable or disable telemetry collection.
|
||||
|
||||
- **Format**: `true` or `false`
|
||||
- **Default**: `true`
|
||||
|
||||
### OTEL_EXPORT_TYPE
|
||||
Export destination for OpenTelemetry metrics.
|
||||
|
||||
- **Options**: `prometheus`, `otlp`
|
||||
- **Example**: `prometheus` exports metrics on `/metrics` endpoint for Prometheus scraping
|
||||
|
||||
## Web and Security
|
||||
|
||||
### SITE_URL
|
||||
**Required** – Public URL of the Infisical instance.
|
||||
|
||||
- **Format**: Full URL (e.g., `https://secrets.example.com`)
|
||||
- **Usage**: Used for email links, OAuth redirects, and frontend configuration
|
||||
|
||||
### CORS_ALLOWED_ORIGINS
|
||||
Comma-separated list of allowed CORS origins.
|
||||
|
||||
- **Format**: Full URLs (e.g., `https://app.example.com,https://admin.example.com`)
|
||||
- **Default**: Allows same origin
|
||||
- **Notes**: Whitelist specific origins in production; avoid wildcards (`*`)
|
||||
|
||||
### ALLOW_INTERNAL_IP_CONNECTIONS
|
||||
Allow connections to internal IP addresses (useful for Kubernetes).
|
||||
|
||||
- **Format**: `true` or `false`
|
||||
- **Default**: `false`
|
||||
- **Use Case**: Kubernetes nodes using internal IPs, local Redis/PostgreSQL on private networks
|
||||
|
||||
## Summary: Minimal Configuration
|
||||
|
||||
For a minimal production deployment, these environment variables are required:
|
||||
|
||||
```bash
|
||||
# Security
|
||||
ENCRYPTION_KEY="<16-byte-hex>"
|
||||
AUTH_SECRET="<base64-32-byte>"
|
||||
|
||||
# Database
|
||||
DB_CONNECTION_URI="postgresql://user:pass@host:5432/infisical"
|
||||
|
||||
# Redis
|
||||
REDIS_URL="redis://host:6379"
|
||||
|
||||
# Web
|
||||
SITE_URL="https://secrets.example.com"
|
||||
|
||||
# SMTP (required for email features)
|
||||
SMTP_HOST="smtp.example.com"
|
||||
SMTP_PORT="587"
|
||||
SMTP_USERNAME="[email protected]"
|
||||
SMTP_PASSWORD="password"
|
||||
SMTP_FROM_ADDRESS="[email protected]"
|
||||
```
|
||||
|
||||
For additional features (OAuth, FIPS, Sentinel, etc.), add the relevant variables from the sections above.
|
||||
@@ -0,0 +1,533 @@
|
||||
# Kubernetes Deployment Guide
|
||||
|
||||
Deploy Infisical on Kubernetes using the official Helm chart for scalable, cloud-native deployments.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Kubernetes 1.23 or newer
|
||||
- Helm 3.11.3 or newer
|
||||
- `kubectl` configured and authenticated to your cluster
|
||||
- PostgreSQL 14+ (managed or in-cluster)
|
||||
- Redis 6.2+ (managed or in-cluster)
|
||||
|
||||
## Helm Chart Installation
|
||||
|
||||
### Add the Infisical Helm Repository
|
||||
|
||||
```bash
|
||||
helm repo add infisical https://dl.cloudsmith.io/public/infisical/helm-charts/helm/charts/
|
||||
helm repo update
|
||||
```
|
||||
|
||||
### Create a Namespace
|
||||
|
||||
```bash
|
||||
kubectl create namespace infisical
|
||||
```
|
||||
|
||||
### Create Secrets
|
||||
|
||||
Before installing the chart, create a Kubernetes secret with required environment variables:
|
||||
|
||||
```bash
|
||||
kubectl create secret generic infisical-secrets \
|
||||
--from-literal=ENCRYPTION_KEY=$(openssl rand -hex 16) \
|
||||
--from-literal=AUTH_SECRET=$(openssl rand -base64 32) \
|
||||
--from-literal=DB_CONNECTION_URI="postgresql://user:password@postgres-host:5432/infisical" \
|
||||
--from-literal=REDIS_URL="redis://redis-host:6379" \
|
||||
--from-literal=SITE_URL="https://secrets.example.com" \
|
||||
--from-literal=SMTP_HOST="smtp.example.com" \
|
||||
--from-literal=SMTP_PORT="587" \
|
||||
--from-literal=SMTP_USERNAME="[email protected]" \
|
||||
--from-literal=SMTP_PASSWORD="password" \
|
||||
--from-literal=SMTP_FROM_ADDRESS="[email protected]" \
|
||||
-n infisical
|
||||
```
|
||||
|
||||
### Install the Chart
|
||||
|
||||
```bash
|
||||
helm install infisical infisical/infisical-standalone-postgres \
|
||||
--namespace infisical \
|
||||
--values values.yaml
|
||||
```
|
||||
|
||||
## Values Configuration
|
||||
|
||||
Create a `values.yaml` file to customize the deployment:
|
||||
|
||||
```yaml
|
||||
# Replica count for horizontal scaling
|
||||
replicaCount: 3
|
||||
|
||||
image:
|
||||
repository: infisical/infisical
|
||||
tag: latest
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
# Pod configuration
|
||||
podAnnotations: {}
|
||||
podSecurityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1001
|
||||
fsGroup: 1001
|
||||
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
readOnlyRootFilesystem: true
|
||||
|
||||
# Resource limits
|
||||
resources:
|
||||
limits:
|
||||
cpu: 2
|
||||
memory: 4Gi
|
||||
requests:
|
||||
cpu: 500m
|
||||
memory: 1Gi
|
||||
|
||||
# Service
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 8080
|
||||
|
||||
# Environment variables from the secret
|
||||
env:
|
||||
- name: ENCRYPTION_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: infisical-secrets
|
||||
key: ENCRYPTION_KEY
|
||||
- name: AUTH_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: infisical-secrets
|
||||
key: AUTH_SECRET
|
||||
- name: DB_CONNECTION_URI
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: infisical-secrets
|
||||
key: DB_CONNECTION_URI
|
||||
- name: REDIS_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: infisical-secrets
|
||||
key: REDIS_URL
|
||||
- name: SITE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: infisical-secrets
|
||||
key: SITE_URL
|
||||
- name: SMTP_HOST
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: infisical-secrets
|
||||
key: SMTP_HOST
|
||||
- name: SMTP_PORT
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: infisical-secrets
|
||||
key: SMTP_PORT
|
||||
- name: SMTP_USERNAME
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: infisical-secrets
|
||||
key: SMTP_USERNAME
|
||||
- name: SMTP_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: infisical-secrets
|
||||
key: SMTP_PASSWORD
|
||||
- name: SMTP_FROM_ADDRESS
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: infisical-secrets
|
||||
key: SMTP_FROM_ADDRESS
|
||||
|
||||
# Persistence (for temporary files)
|
||||
persistence:
|
||||
enabled: true
|
||||
storageClassName: standard
|
||||
accessMode: ReadWriteOnce
|
||||
size: 2Gi
|
||||
mountPath: /tmp
|
||||
|
||||
# Ingress
|
||||
ingress:
|
||||
enabled: true
|
||||
className: nginx
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
hosts:
|
||||
- host: secrets.example.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
tls:
|
||||
- secretName: infisical-tls
|
||||
hosts:
|
||||
- secrets.example.com
|
||||
|
||||
# Health checks
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /api/status
|
||||
port: 8080
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /api/status
|
||||
port: 8080
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 5
|
||||
|
||||
# PostgreSQL (optional - if using in-cluster)
|
||||
postgresql:
|
||||
enabled: true
|
||||
auth:
|
||||
username: infisical
|
||||
password: change-me-in-production
|
||||
database: infisical
|
||||
primary:
|
||||
persistence:
|
||||
size: 8Gi
|
||||
resources:
|
||||
requests:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
limits:
|
||||
cpu: 2
|
||||
memory: 2Gi
|
||||
|
||||
# Redis (optional - if using in-cluster)
|
||||
redis:
|
||||
enabled: true
|
||||
auth:
|
||||
enabled: false
|
||||
master:
|
||||
persistence:
|
||||
size: 2Gi
|
||||
resources:
|
||||
requests:
|
||||
cpu: 250m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 1
|
||||
memory: 1Gi
|
||||
```
|
||||
|
||||
## Using External Databases
|
||||
|
||||
To use managed PostgreSQL and Redis (RDS, Cloud SQL, ElastiCache, etc.), disable the in-cluster services:
|
||||
|
||||
```yaml
|
||||
postgresql:
|
||||
enabled: false
|
||||
|
||||
redis:
|
||||
enabled: false
|
||||
```
|
||||
|
||||
Then configure the connection strings in the secret:
|
||||
|
||||
```bash
|
||||
kubectl create secret generic infisical-secrets \
|
||||
--from-literal=DB_CONNECTION_URI="postgresql://user:[email protected]:5432/infisical" \
|
||||
--from-literal=REDIS_URL="rediss://redis-cluster.cache.amazonaws.com:6380" \
|
||||
# ... other variables
|
||||
-n infisical
|
||||
```
|
||||
|
||||
## Scaling
|
||||
|
||||
### Horizontal Scaling
|
||||
|
||||
Increase the number of replicas in `values.yaml`:
|
||||
|
||||
```yaml
|
||||
replicaCount: 5 # Scale to 5 replicas
|
||||
```
|
||||
|
||||
Apply the change:
|
||||
|
||||
```bash
|
||||
helm upgrade infisical infisical/infisical-standalone-postgres \
|
||||
--namespace infisical \
|
||||
--values values.yaml
|
||||
```
|
||||
|
||||
Or use kubectl directly:
|
||||
|
||||
```bash
|
||||
kubectl scale deployment infisical --replicas=5 -n infisical
|
||||
```
|
||||
|
||||
### Autoscaling
|
||||
|
||||
Enable Horizontal Pod Autoscaler (HPA):
|
||||
|
||||
```yaml
|
||||
autoscaling:
|
||||
enabled: true
|
||||
minReplicas: 3
|
||||
maxReplicas: 10
|
||||
targetCPUUtilizationPercentage: 70
|
||||
```
|
||||
|
||||
## Pod Security
|
||||
|
||||
### Non-Root User
|
||||
|
||||
The default configuration runs Infisical as a non-root user (UID 1001):
|
||||
|
||||
```yaml
|
||||
podSecurityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1001
|
||||
fsGroup: 1001
|
||||
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
readOnlyRootFilesystem: true
|
||||
```
|
||||
|
||||
### Pod Security Policy
|
||||
|
||||
For Kubernetes clusters with Pod Security Policies (PSP) enabled, ensure the Infisical deployment complies:
|
||||
|
||||
```bash
|
||||
kubectl label pod -l app=infisical restricted=true -n infisical
|
||||
```
|
||||
|
||||
## Networking
|
||||
|
||||
### Network Policy
|
||||
|
||||
Create a NetworkPolicy to isolate Infisical traffic:
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: infisical-network-policy
|
||||
namespace: infisical
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app: infisical
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
||||
ingress:
|
||||
- from:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
name: ingress-nginx
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 8080
|
||||
egress:
|
||||
- to:
|
||||
- namespaceSelector: {}
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 5432 # PostgreSQL
|
||||
- protocol: TCP
|
||||
port: 6379 # Redis
|
||||
- to:
|
||||
- podSelector: {}
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 53 # DNS
|
||||
```
|
||||
|
||||
### Ingress with TLS
|
||||
|
||||
Use cert-manager and Let's Encrypt for automated TLS:
|
||||
|
||||
```yaml
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: Certificate
|
||||
metadata:
|
||||
name: infisical-cert
|
||||
namespace: infisical
|
||||
spec:
|
||||
secretName: infisical-tls
|
||||
issuerRef:
|
||||
name: letsencrypt-prod
|
||||
commonName: secrets.example.com
|
||||
dnsNames:
|
||||
- secrets.example.com
|
||||
```
|
||||
|
||||
Then configure Ingress:
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: infisical-ingress
|
||||
namespace: infisical
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
tls:
|
||||
- hosts:
|
||||
- secrets.example.com
|
||||
secretName: infisical-tls
|
||||
rules:
|
||||
- host: secrets.example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: infisical
|
||||
port:
|
||||
number: 8080
|
||||
```
|
||||
|
||||
## Persistence
|
||||
|
||||
Create PersistentVolumeClaims for PostgreSQL and Redis data:
|
||||
|
||||
```yaml
|
||||
postgresql:
|
||||
primary:
|
||||
persistence:
|
||||
enabled: true
|
||||
storageClassName: fast-ssd
|
||||
size: 20Gi
|
||||
|
||||
redis:
|
||||
master:
|
||||
persistence:
|
||||
enabled: true
|
||||
storageClassName: fast-ssd
|
||||
size: 5Gi
|
||||
```
|
||||
|
||||
## Monitoring and Logging
|
||||
|
||||
### Metrics
|
||||
|
||||
Infisical exposes metrics via the `/metrics` endpoint (OpenTelemetry format):
|
||||
|
||||
```bash
|
||||
kubectl port-forward svc/infisical 8080:8080 -n infisical
|
||||
curl http://localhost:8080/metrics
|
||||
```
|
||||
|
||||
### Logs
|
||||
|
||||
View logs from all Infisical replicas:
|
||||
|
||||
```bash
|
||||
kubectl logs -l app=infisical -n infisical --all-containers=true -f
|
||||
```
|
||||
|
||||
### Prometheus Integration
|
||||
|
||||
Create a ServiceMonitor for Prometheus:
|
||||
|
||||
```yaml
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: ServiceMonitor
|
||||
metadata:
|
||||
name: infisical
|
||||
namespace: infisical
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: infisical
|
||||
endpoints:
|
||||
- port: metrics
|
||||
interval: 30s
|
||||
path: /metrics
|
||||
```
|
||||
|
||||
## Backup and Recovery
|
||||
|
||||
### Backup PostgreSQL
|
||||
|
||||
If using in-cluster PostgreSQL:
|
||||
|
||||
```bash
|
||||
kubectl exec -it infisical-postgresql-0 -n infisical -- \
|
||||
pg_dump -U infisical infisical | gzip > backup.sql.gz
|
||||
```
|
||||
|
||||
For managed PostgreSQL (RDS, Cloud SQL), use the managed service's backup tools.
|
||||
|
||||
### Backup Redis
|
||||
|
||||
For in-cluster Redis:
|
||||
|
||||
```bash
|
||||
kubectl exec -it infisical-redis-master-0 -n infisical -- \
|
||||
redis-cli BGSAVE
|
||||
kubectl cp infisical/infisical-redis-master-0:/data/dump.rdb ./redis_backup.rdb
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Check Pod Status
|
||||
|
||||
```bash
|
||||
kubectl get pods -n infisical
|
||||
kubectl describe pod <pod-name> -n infisical
|
||||
```
|
||||
|
||||
### View Logs
|
||||
|
||||
```bash
|
||||
kubectl logs <pod-name> -n infisical
|
||||
```
|
||||
|
||||
### Port Forward for Testing
|
||||
|
||||
```bash
|
||||
kubectl port-forward svc/infisical 8080:8080 -n infisical
|
||||
curl http://localhost:8080/api/status
|
||||
```
|
||||
|
||||
### Check Events
|
||||
|
||||
```bash
|
||||
kubectl get events -n infisical --sort-by='.lastTimestamp'
|
||||
```
|
||||
|
||||
## Upgrading
|
||||
|
||||
To upgrade Infisical on Kubernetes:
|
||||
|
||||
1. Backup PostgreSQL (see Backup and Recovery section)
|
||||
|
||||
2. Update the chart:
|
||||
```bash
|
||||
helm repo update
|
||||
```
|
||||
|
||||
3. Upgrade the release:
|
||||
```bash
|
||||
helm upgrade infisical infisical/infisical-standalone-postgres \
|
||||
--namespace infisical \
|
||||
--values values.yaml
|
||||
```
|
||||
|
||||
4. Monitor the rollout:
|
||||
```bash
|
||||
kubectl rollout status deployment/infisical -n infisical
|
||||
```
|
||||
|
||||
Schema migrations run automatically during pod startup.
|
||||
@@ -0,0 +1,552 @@
|
||||
# Scaling and High Availability Guide
|
||||
|
||||
Infisical is a stateless application designed to scale horizontally. This guide covers scaling patterns, sizing recommendations, high availability (HA) setup, and upgrade procedures.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
Infisical's stateless architecture means:
|
||||
|
||||
- **All state is external**: PostgreSQL stores data, Redis handles caching and job queues
|
||||
- **Horizontal scaling**: Add more Infisical replicas without reconfiguration
|
||||
- **Load balancing**: Multiple replicas distribute traffic evenly
|
||||
- **Zero shared state**: Each replica is identical and independent
|
||||
|
||||
This enables seamless scaling from single-node deployments to large distributed clusters.
|
||||
|
||||
## Sizing Recommendations
|
||||
|
||||
Choose deployment sizes based on your organization's users, secrets, and API request volume.
|
||||
|
||||
### Small Deployment
|
||||
|
||||
**Use Case**: Development, testing, small organizations (< 50 users)
|
||||
|
||||
**Infisical**:
|
||||
- Replicas: 2
|
||||
- CPU: 2 cores per replica
|
||||
- Memory: 4-8 GB per replica
|
||||
- Storage: N/A (stateless)
|
||||
|
||||
**PostgreSQL**:
|
||||
- vCPU: 2
|
||||
- Memory: 8 GB
|
||||
- Storage: 100 GB (SSD recommended)
|
||||
- Configuration: Single instance with automated backups
|
||||
|
||||
**Redis**:
|
||||
- vCPU: 2
|
||||
- Memory: 4 GB
|
||||
- Storage: N/A (in-memory)
|
||||
- Configuration: Standalone (simplest for this size)
|
||||
|
||||
### Medium Deployment
|
||||
|
||||
**Use Case**: Production environments (50-500 users)
|
||||
|
||||
**Infisical**:
|
||||
- Replicas: 5
|
||||
- CPU: 2-4 cores per replica
|
||||
- Memory: 4-8 GB per replica
|
||||
- Storage: N/A (stateless)
|
||||
|
||||
**PostgreSQL**:
|
||||
- vCPU: 4
|
||||
- Memory: 16 GB
|
||||
- Storage: 200 GB (SSD)
|
||||
- Configuration: Primary + read replicas for load distribution
|
||||
|
||||
**Redis**:
|
||||
- vCPU: 2
|
||||
- Memory: 4 GB
|
||||
- Configuration: Standalone or Sentinel for HA
|
||||
|
||||
### Large Deployment
|
||||
|
||||
**Use Case**: Enterprise environments (500+ users)
|
||||
|
||||
**Infisical**:
|
||||
- Replicas: 10+
|
||||
- CPU: 2-4 cores per replica
|
||||
- Memory: 4-8 GB per replica
|
||||
- Storage: N/A (stateless)
|
||||
|
||||
**PostgreSQL**:
|
||||
- vCPU: 8
|
||||
- Memory: 32 GB
|
||||
- Storage: 500 GB+ (SSD with RAID)
|
||||
- Configuration: Primary + multiple read replicas, automated backups and WAL archiving
|
||||
|
||||
**Redis**:
|
||||
- vCPU: 2-4
|
||||
- Memory: 4-8 GB
|
||||
- Configuration: Redis Sentinel for HA or Redis Cluster (but Infisical does NOT support Cluster mode)
|
||||
|
||||
## Horizontal Scaling
|
||||
|
||||
### Docker Compose
|
||||
|
||||
To scale Infisical with Docker Compose, create multiple service definitions:
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:14-alpine
|
||||
environment:
|
||||
POSTGRES_USER: infisical
|
||||
POSTGRES_PASSWORD: password
|
||||
POSTGRES_DB: infisical
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
|
||||
infisical-1:
|
||||
image: infisical/infisical:latest
|
||||
depends_on:
|
||||
- postgres
|
||||
- redis
|
||||
environment:
|
||||
ENCRYPTION_KEY: ${ENCRYPTION_KEY}
|
||||
AUTH_SECRET: ${AUTH_SECRET}
|
||||
DB_CONNECTION_URI: postgresql://infisical:password@postgres:5432/infisical
|
||||
REDIS_URL: redis://redis:6379
|
||||
SITE_URL: https://secrets.example.com
|
||||
ports:
|
||||
- "8001:8080"
|
||||
|
||||
infisical-2:
|
||||
image: infisical/infisical:latest
|
||||
depends_on:
|
||||
- postgres
|
||||
- redis
|
||||
environment:
|
||||
ENCRYPTION_KEY: ${ENCRYPTION_KEY}
|
||||
AUTH_SECRET: ${AUTH_SECRET}
|
||||
DB_CONNECTION_URI: postgresql://infisical:password@postgres:5432/infisical
|
||||
REDIS_URL: redis://redis:6379
|
||||
SITE_URL: https://secrets.example.com
|
||||
ports:
|
||||
- "8002:8080"
|
||||
|
||||
infisical-3:
|
||||
image: infisical/infisical:latest
|
||||
depends_on:
|
||||
- postgres
|
||||
- redis
|
||||
environment:
|
||||
ENCRYPTION_KEY: ${ENCRYPTION_KEY}
|
||||
AUTH_SECRET: ${AUTH_SECRET}
|
||||
DB_CONNECTION_URI: postgresql://infisical:password@postgres:5432/infisical
|
||||
REDIS_URL: redis://redis:6379
|
||||
SITE_URL: https://secrets.example.com
|
||||
ports:
|
||||
- "8003:8080"
|
||||
|
||||
nginx:
|
||||
image: nginx:latest
|
||||
volumes:
|
||||
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
ports:
|
||||
- "80:80"
|
||||
depends_on:
|
||||
- infisical-1
|
||||
- infisical-2
|
||||
- infisical-3
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
redis_data:
|
||||
```
|
||||
|
||||
Use Nginx or HAProxy as a load balancer to distribute traffic:
|
||||
|
||||
```nginx
|
||||
upstream infisical {
|
||||
server infisical-1:8080;
|
||||
server infisical-2:8080;
|
||||
server infisical-3:8080;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
location / {
|
||||
proxy_pass http://infisical;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Kubernetes
|
||||
|
||||
Scale using kubectl:
|
||||
|
||||
```bash
|
||||
kubectl scale deployment infisical --replicas=10 -n infisical
|
||||
```
|
||||
|
||||
Or update the Helm values:
|
||||
|
||||
```yaml
|
||||
replicaCount: 10
|
||||
```
|
||||
|
||||
Then apply:
|
||||
|
||||
```bash
|
||||
helm upgrade infisical infisical/infisical-standalone-postgres \
|
||||
--namespace infisical \
|
||||
-f values.yaml
|
||||
```
|
||||
|
||||
## Database Replication
|
||||
|
||||
### PostgreSQL Read Replicas
|
||||
|
||||
For large deployments, use PostgreSQL read replicas to distribute read-heavy queries (secrets, audit logs):
|
||||
|
||||
```bash
|
||||
DB_READ_REPLICAS='[
|
||||
{"connectionString": "postgresql://user:[email protected]:5432/infisical"},
|
||||
{"connectionString": "postgresql://user:[email protected]:5432/infisical"}
|
||||
]'
|
||||
```
|
||||
|
||||
Infisical will distribute SELECT queries across replicas while ensuring writes go to the primary.
|
||||
|
||||
### Setting Up AWS RDS Read Replicas
|
||||
|
||||
1. Create a read replica in AWS RDS:
|
||||
```bash
|
||||
aws rds create-db-instance-read-replica \
|
||||
--db-instance-identifier infisical-replica-1 \
|
||||
--source-db-instance-identifier infisical-primary
|
||||
```
|
||||
|
||||
2. Configure in Infisical:
|
||||
```bash
|
||||
DB_READ_REPLICAS='[
|
||||
{"connectionString": "postgresql://user:password@infisical-replica-1.123456789.us-east-1.rds.amazonaws.com:5432/infisical"}
|
||||
]'
|
||||
```
|
||||
|
||||
## Redis High Availability
|
||||
|
||||
Infisical supports Redis Sentinel for high availability. Cluster mode is NOT supported.
|
||||
|
||||
### Redis Sentinel Setup
|
||||
|
||||
Sentinel monitors Redis and automatically promotes a replica to master if the primary fails.
|
||||
|
||||
#### Configure Sentinel
|
||||
|
||||
Create `sentinel.conf`:
|
||||
|
||||
```
|
||||
port 26379
|
||||
sentinel monitor mymaster 192.168.1.100 6379 2
|
||||
sentinel down-after-milliseconds mymaster 5000
|
||||
sentinel parallel-syncs mymaster 1
|
||||
sentinel failover-timeout mymaster 180000
|
||||
```
|
||||
|
||||
Run three Sentinel nodes for quorum:
|
||||
|
||||
```bash
|
||||
redis-sentinel sentinel-1.conf
|
||||
redis-sentinel sentinel-2.conf
|
||||
redis-sentinel sentinel-3.conf
|
||||
```
|
||||
|
||||
#### Configure Infisical to Use Sentinel
|
||||
|
||||
```bash
|
||||
REDIS_SENTINEL_HOSTS="sentinel1.example.com:26379,sentinel2.example.com:26379,sentinel3.example.com:26379"
|
||||
REDIS_SENTINEL_MASTER_NAME="mymaster"
|
||||
REDIS_SENTINEL_ENABLE_TLS="true"
|
||||
REDIS_SENTINEL_USERNAME="sentinel-user"
|
||||
REDIS_SENTINEL_PASSWORD="sentinel-password"
|
||||
```
|
||||
|
||||
Infisical will discover the current Redis master through Sentinel and automatically handle failovers.
|
||||
|
||||
### Docker Compose with Sentinel
|
||||
|
||||
```yaml
|
||||
redis-master:
|
||||
image: redis:7-alpine
|
||||
ports:
|
||||
- "6379:6379"
|
||||
|
||||
redis-replica:
|
||||
image: redis:7-alpine
|
||||
command: redis-server --slaveof redis-master 6379
|
||||
depends_on:
|
||||
- redis-master
|
||||
|
||||
sentinel-1:
|
||||
image: redis:7-alpine
|
||||
command: redis-sentinel /sentinel.conf
|
||||
volumes:
|
||||
- ./sentinel.conf:/sentinel.conf
|
||||
ports:
|
||||
- "26379:26379"
|
||||
|
||||
sentinel-2:
|
||||
image: redis:7-alpine
|
||||
command: redis-sentinel /sentinel.conf
|
||||
volumes:
|
||||
- ./sentinel.conf:/sentinel.conf
|
||||
ports:
|
||||
- "26380:26379"
|
||||
|
||||
sentinel-3:
|
||||
image: redis:7-alpine
|
||||
command: redis-sentinel /sentinel.conf
|
||||
volumes:
|
||||
- ./sentinel.conf:/sentinel.conf
|
||||
ports:
|
||||
- "26381:26379"
|
||||
|
||||
infisical:
|
||||
image: infisical/infisical:latest
|
||||
environment:
|
||||
REDIS_SENTINEL_HOSTS: "sentinel-1:26379,sentinel-2:26379,sentinel-3:26379"
|
||||
REDIS_SENTINEL_MASTER_NAME: "mymaster"
|
||||
```
|
||||
|
||||
## Backup and Disaster Recovery
|
||||
|
||||
### PostgreSQL Backup Strategy
|
||||
|
||||
**Automated Backups**:
|
||||
|
||||
For managed PostgreSQL (RDS, Cloud SQL), use automated backups:
|
||||
|
||||
```bash
|
||||
# AWS RDS
|
||||
aws rds create-db-snapshot \
|
||||
--db-instance-identifier infisical \
|
||||
--db-snapshot-identifier infisical-backup-$(date +%s)
|
||||
```
|
||||
|
||||
**Manual Backups**:
|
||||
|
||||
For self-hosted PostgreSQL:
|
||||
|
||||
```bash
|
||||
pg_dump -h pg.example.com -U infisical infisical | gzip > backup_$(date +%Y%m%d).sql.gz
|
||||
```
|
||||
|
||||
**Point-in-Time Recovery** (if WAL archiving is configured):
|
||||
|
||||
```bash
|
||||
# Configure WAL archiving in PostgreSQL postgresql.conf
|
||||
archive_mode = on
|
||||
archive_command = 'aws s3 cp %p s3://backup-bucket/wal_archive/%f'
|
||||
```
|
||||
|
||||
Then restore to a specific point in time.
|
||||
|
||||
### Redis Backup
|
||||
|
||||
Redis backups are less critical than database backups (data can be repopulated from PostgreSQL), but they can speed up recovery:
|
||||
|
||||
```bash
|
||||
redis-cli BGSAVE
|
||||
redis-cli LASTSAVE # Shows timestamp of last snapshot
|
||||
```
|
||||
|
||||
Backup the RDB file periodically:
|
||||
|
||||
```bash
|
||||
cp /var/lib/redis/dump.rdb /backup/redis_$(date +%s).rdb
|
||||
```
|
||||
|
||||
### Backup Schedule
|
||||
|
||||
- **PostgreSQL**: Daily automated backups + continuous WAL archiving
|
||||
- **Redis**: Daily snapshots (optional, less critical)
|
||||
- **Retention**: Keep at least 30 days of backups for compliance
|
||||
|
||||
### Test Restores
|
||||
|
||||
Regularly test restores in a non-production environment to ensure backup integrity.
|
||||
|
||||
## Upgrades
|
||||
|
||||
Upgrading Infisical with zero downtime:
|
||||
|
||||
1. **Backup the database** (critical):
|
||||
```bash
|
||||
pg_dump -h pg.example.com -U infisical infisical > backup.sql
|
||||
```
|
||||
|
||||
2. **Check the upgrade path** (optional):
|
||||
Visit https://app.infisical.com/upgrade-path to verify your upgrade path and any special steps.
|
||||
|
||||
3. **Update replicas incrementally**:
|
||||
|
||||
For Kubernetes with rolling updates:
|
||||
```bash
|
||||
kubectl set image deployment/infisical infisical=infisical/infisical:new-version -n infisical
|
||||
```
|
||||
|
||||
The rolling update ensures some replicas stay running while others update.
|
||||
|
||||
4. **Monitor the rollout**:
|
||||
```bash
|
||||
kubectl rollout status deployment/infisical -n infisical
|
||||
```
|
||||
|
||||
5. **Schema migrations run automatically** on startup (since v0.111.0-postgres):
|
||||
- One instance acquires a lock
|
||||
- Migrations run
|
||||
- Other instances wait for migrations to complete
|
||||
- Cluster is ready
|
||||
|
||||
6. **Rollback if needed**:
|
||||
```bash
|
||||
kubectl rollout undo deployment/infisical -n infisical
|
||||
```
|
||||
|
||||
## Licensing and Compliance
|
||||
|
||||
### License Server IP Addresses
|
||||
|
||||
Enterprise Infisical installations require connectivity to the license server. Whitelist these IPs in your firewall:
|
||||
|
||||
- `13.248.249.247`
|
||||
- `35.71.190.59`
|
||||
|
||||
Ensure outbound HTTPS (port 443) is allowed to these addresses.
|
||||
|
||||
## Monitoring and Observability
|
||||
|
||||
### Key Metrics to Monitor
|
||||
|
||||
- **CPU and Memory**: Per-replica resource utilization
|
||||
- **Request Latency**: API response times
|
||||
- **Error Rate**: 5xx errors, database connection errors
|
||||
- **Database Connections**: Active connections, connection pool saturation
|
||||
- **Redis Memory**: Memory usage and eviction
|
||||
- **Database Query Time**: Slow query logs
|
||||
|
||||
### Prometheus Metrics
|
||||
|
||||
Infisical exposes metrics on `/metrics` (OpenTelemetry format):
|
||||
|
||||
```bash
|
||||
curl http://infisical:8080/metrics
|
||||
```
|
||||
|
||||
### Log Aggregation
|
||||
|
||||
Aggregate logs from all replicas using your logging platform:
|
||||
|
||||
```bash
|
||||
# Docker Compose
|
||||
docker-compose logs infisical | grep ERROR
|
||||
|
||||
# Kubernetes
|
||||
kubectl logs -l app=infisical -n infisical --all-containers=true
|
||||
```
|
||||
|
||||
## Performance Tuning
|
||||
|
||||
### PostgreSQL Tuning
|
||||
|
||||
For large deployments, optimize PostgreSQL:
|
||||
|
||||
```sql
|
||||
-- Increase shared buffers (typically 25% of RAM)
|
||||
ALTER SYSTEM SET shared_buffers = '8GB';
|
||||
|
||||
-- Increase effective cache size (typically 50-75% of RAM)
|
||||
ALTER SYSTEM SET effective_cache_size = '24GB';
|
||||
|
||||
-- Increase work_mem for complex queries
|
||||
ALTER SYSTEM SET work_mem = '8MB';
|
||||
|
||||
-- Reload configuration
|
||||
SELECT pg_reload_conf();
|
||||
```
|
||||
|
||||
### Redis Tuning
|
||||
|
||||
Increase maxmemory if needed:
|
||||
|
||||
```bash
|
||||
redis-cli CONFIG SET maxmemory 4gb
|
||||
redis-cli CONFIG SET maxmemory-policy allkeys-lru
|
||||
```
|
||||
|
||||
### Connection Pool Tuning
|
||||
|
||||
Monitor connection pool saturation and adjust if needed:
|
||||
|
||||
```bash
|
||||
# Check PostgreSQL max connections
|
||||
psql -h pg.example.com -U infisical -d infisical -c "SHOW max_connections;"
|
||||
```
|
||||
|
||||
Increase if you have many Infisical replicas:
|
||||
|
||||
```bash
|
||||
ALTER SYSTEM SET max_connections = 400;
|
||||
```
|
||||
|
||||
## Troubleshooting HA Setups
|
||||
|
||||
### Redis Sentinel Failover Not Triggering
|
||||
|
||||
Check Sentinel logs:
|
||||
|
||||
```bash
|
||||
redis-cli -p 26379 SENTINEL MASTERS
|
||||
redis-cli -p 26379 SENTINEL SLAVES mymaster
|
||||
```
|
||||
|
||||
Ensure Sentinel nodes can communicate with Redis.
|
||||
|
||||
### Database Connection Pool Exhaustion
|
||||
|
||||
If you see "too many connections" errors:
|
||||
|
||||
1. Check current connections:
|
||||
```bash
|
||||
psql -c "SELECT datname, count(*) FROM pg_stat_activity GROUP BY datname;"
|
||||
```
|
||||
|
||||
2. Increase PostgreSQL max_connections
|
||||
3. Reduce Infisical replicas or increase connection pool size
|
||||
|
||||
### Read Replica Lag
|
||||
|
||||
If read replicas are lagging, monitor replication lag:
|
||||
|
||||
```bash
|
||||
# AWS RDS
|
||||
aws rds describe-db-instances --query 'DBInstances[*].[DBInstanceIdentifier,ReplicationLag]'
|
||||
```
|
||||
|
||||
Lag > 1 second may cause stale reads. Infisical writes always use the primary.
|
||||
|
||||
## Capacity Planning
|
||||
|
||||
To estimate hardware needs:
|
||||
|
||||
- **Users**: 10 users per core for moderate activity
|
||||
- **Secrets**: 1 million secrets per 10 GB of PostgreSQL storage
|
||||
- **API Calls**: 1000 req/sec per 2 cores with 4 GB memory
|
||||
- **Database Connections**: 20-50 per Infisical replica
|
||||
|
||||
Example for 200 users:
|
||||
- Infisical: 3 replicas x 2 cores
|
||||
- PostgreSQL: 4 vCPU, 16 GB RAM, 100 GB storage
|
||||
- Redis: 2 vCPU, 4 GB RAM
|
||||
|
||||
Adjust based on actual monitoring and load testing.
|
||||
Reference in New Issue
Block a user