Infisical Operations Cheatsheet

Service: Self-hosted Infisical (secrets management) URL: https://sm.solanasis.com Admin: admin@solanasis.com Last updated: 2026-03-28

Master docs:

  • Deep plan: C:\_my\.claude-plans\deep-plan-infisical-hardening-2026-03-25.md
  • Original plan: C:\Users\zasya\.claude\plans\vectorized-frolicking-comet.md
  • Continuation prompt: solanasis-docs/temp-working/infisical-hardening-continuation-prompt.md
  • Service inventory: solanasis-docs/operations/service-inventory.md
  • Backup restore instructions: C:\_my\infisical-backups\README.md

Quick Access

  1. Navigate to https://sm.solanasis.com
  2. Cloudflare Access gate appears — enter your @solanasis.com email
  3. Check email for One-Time PIN (OTP) from Cloudflare
  4. Enter OTP — you’re now past the perimeter gate
  5. Log into Infisical with your Infisical credentials

Allowed emails: mr.sunshine@solanasis.com, ds@solanasis.com Session duration: 24 hours (Cloudflare Access), then re-authenticate


Managing Secrets

Web UI

  1. Log in at https://sm.solanasis.com
  2. Select project “Solanasis Apps”
  3. Secrets are organized by folder:
    • /shared/ — Secrets shared across all repos (imported into each repo folder)
    • /solanasis-site/ — Website-specific secrets
    • /solanasis-scripts/ — Script-specific secrets
    • /solanasis-docs/ — Docs-specific secrets
    • /matchkeyz/ — Matchkeyz-specific secrets

Architecture

/shared/                    ← Common secrets (API keys, service credentials)
  ├── BASEROW_BASE_URL
  ├── BASEROW_DB_TOKEN
  ├── BREVO_SMTP_KEY          ← Brevo SMTP password (starts with xsmtpsib-)
  ├── BREVO_SMTP_USER         ← Brevo SMTP login (xxx@smtp-brevo.com, NOT sender address)
  ├── CLOUDFLARE_GLOBAL_API_KEY
  ├── INFISICAL_BACKUP_PASSPHRASE
  └── ... (15 total)

/solanasis-site/            ← Imports from /shared/ via Secret Imports
/solanasis-scripts/         ← Imports from /shared/ via Secret Imports
/solanasis-docs/            ← Imports from /shared/ via Secret Imports
/matchkeyz/                 ← Imports from /shared/ via Secret Imports
/mrsunshine-site/           ← Imports from /shared/ via Secret Imports
/selfinquire/               ← Imports from /shared/ via Secret Imports

Adding a new shared secret: Add it to /shared/ — all repo folders inherit it automatically via Secret Imports.

Adding a repo-specific secret: Add it directly to that repo’s folder.

Machine Identity (for API/automation)

  • Client ID: 10baaf13-1ca9-468f-ae61-38b76fa060fc
  • Client Secret: INFISICAL_CLIENT_SECRET, looked up in order:
    1. INFISICAL_CLIENT_SECRET environment variable
    2. C:\_my\.env (Windows)
    3. ~/.config/infisical/credentials (WSL/Linux)
    4. /mnt/c/_my/.env (WSL fallback via Windows mount)
  • Project ID: ec70b6f3-da5a-4eac-bb7a-e6bbd4c9dd4d
  • API docs: https://infisical.com/docs/api-reference/overview/introduction

Managing Secrets (CLI)

Script: _solanasis/infisical/manage_secrets.py Alias: secret (bash alias on WSL, secret.cmd on Windows) Docs: https://infisical.com/docs/api-reference/overview/introduction

Zero-Disk Secrets (Preferred)

Use secret run to inject secrets as in-memory env vars — no .env file created on disk. This prevents secret exposure if a directory is accidentally served via tunnel or web server.

# Run a command with secrets injected from an Infisical folder
secret run shared -- python script.py                  # /shared/ secrets
secret run solanasis-scripts -- python my_script.py    # /solanasis-scripts/ + imports
secret run matchkeyz -- dotnet run                     # /matchkeyz/ + imports
secret run matchkeyz --env staging -- dotnet run       # Staging environment
 
# Cron jobs use cron-wrapper.py for automatic secret injection
python3 cron-wrapper.py shared -- python3 backup-infisical.py

How it works: Authenticates via Machine Identity → fetches secrets from Infisical API → injects as environment variables into child process → secrets exist only in process memory, never on disk.

Fallback: If Infisical is down, secret run auto-falls back to .env.master with a warning. Both secret get and secret run support this fallback.

Other Commands

# Set a secret (creates or updates — upsert)
secret set STRIPE_KEY sk_live_xxx                    # → /shared/ (default)
secret set STRIPE_KEY sk_live_xxx -f solanasis-site  # → /solanasis-site/
secret set DB_URL "postgres://..." -c "Production DB" # With comment
 
# Get a secret
secret get STRIPE_KEY                      # Pretty output with version info
secret get STRIPE_KEY --plain              # Just the value (for scripting)
secret get STRIPE_KEY -f matchkeyz         # From specific folder
 
# List secrets
secret list                                # All folders, keys only
secret list -f shared                      # Specific folder
secret list -f shared --values             # Show values too
secret list --imports                      # Include imported (/shared/) secrets
 
# Delete a secret
secret delete OLD_KEY                      # Prompts for confirmation
secret delete OLD_KEY --yes                # Skip confirmation
secret delete OLD_KEY -f matchkeyz         # From specific folder
 
# Manage folders
secret folders                             # List all folders
secret folders create new-repo             # Create a new folder
 
# Initialize a new repo (creates folder + secret import + .infisical.json + updates sync_env.py)
secret init new-repo C:\path\to\repo
 
# Sync secrets to local .env files (legacy — prefer `secret run` instead)
secret sync --all                             # All repos
secret sync solanasis-site                    # Specific repo
secret sync --backup                          # Generate .env.master fallback

Defaults: Environment = dev, Folder = /shared/. Override with -e prod and -f folder-name.

Official Infisical CLI (installed via winget)

# Full-featured CLI for advanced operations
infisical secrets --path=/shared --projectId=ec70b6f3-da5a-4eac-bb7a-e6bbd4c9dd4d
infisical export --path=/solanasis-site --format=dotenv > .env
infisical secrets set KEY=VALUE --path=/shared
infisical scan              # Scan for leaked secrets in git history

Env vars configured: INFISICAL_API_URL=http://localhost:8580, INFISICAL_DISABLE_UPDATE_CHECK=true


Syncing Secrets to Local .env Files (Legacy)

Prefer secret run instead — it injects secrets at runtime without creating .env files on disk. Use secret sync only when a tool specifically requires a .env file and cannot accept environment variables.

Script: _solanasis/infisical/sync_env.py

# Sync all repos
secret sync --all
 
# Sync a specific repo
secret sync solanasis-site
 
# Generate .env.master fallback file
secret sync --backup

Fallback (.env.master)

When Infisical is down, secret get, secret list, and secret run automatically fall back to .env.master (cross-platform: C:\_my\.env.master or /mnt/c/_my/.env.master).

# Generate/refresh the fallback file
secret sync --backup
 
# Manual fallback test
docker compose -f C:\_my\_solanasis\infisical\docker-compose.yml down
secret get BASEROW_BASE_URL --plain      # Should show [FALLBACK] warning + value
secret run shared -- echo "works too"    # secret run also falls back
docker compose -f C:\_my\_solanasis\infisical\docker-compose.yml up -d

What works in fallback mode: get, list, run What does NOT work: set, delete, init, folders (require Infisical to be running)

Environment Hierarchy

EnvironmentSlugUsage
DevelopmentdevDefault. Local development.
StagingstagingQA / pre-prod testing.
ProductionprodLive production values.
# Access different environments
secret get KEY -f matchkeyz --env staging    # QA environment
secret list -f shared --env prod             # Production secrets
python sync_env.py matchkeyz --env staging   # Sync QA .env

Folders (projects) x Environments (stages) form a 2D matrix:

  • /shared/ x dev = shared development secrets
  • /matchkeyz/ x staging = Matchkeyz QA secrets
  • /matchkeyz/ x prod = Matchkeyz production secrets

Backup & Restore

Automated Backup

  • Schedule: Daily at 2:00 AM (WSL cron via cron-wrapper.py)
  • Verification: Sunday 6:30 AM (WSL cron — decrypts + validates latest backup)
  • Script: solanasis-docs/scheduled-tasks/scripts/backup-infisical.py
  • Pipeline: pg_dump + .env → tar.gz → AES-256-CBC encrypt → git push to GitHub
  • Storage: dzinreach/infisical-backups (private repo) + local infisical-backups/
  • Retention: 7 daily + 4 weekly rolling
  • Logs: solanasis-docs/logs/infisical-backup-*.log, infisical-verify-*.log

Passphrase

  • Windows env var: INFISICAL_BACKUP_PASSPHRASE
  • Bitwarden: “Infisical Backup Encryption Passphrase”
  • Infisical: /shared/INFISICAL_BACKUP_PASSPHRASE

Manual Backup

python C:\_my\_solanasis\solanasis-docs\scheduled-tasks\scripts\backup-infisical.py

Restore Procedure

Full instructions: C:\_my\infisical-backups\README.md

# 1. Decrypt
openssl enc -aes-256-cbc -d -pbkdf2 -iter 600000 \
  -in daily/infisical-backup-YYYY-MM-DD.tar.gz.enc \
  -out backup.tar.gz
# Enter passphrase when prompted (from Bitwarden or env var)
 
# 2. Extract
tar xzf backup.tar.gz
# Yields: infisical_dump.sql, dot_env
 
# 3. Restore .env
cp dot_env C:\_my\_solanasis\infisical\.env
 
# 4. Restore database
docker exec -i infisical-db psql -U infisical -c "DROP DATABASE IF EXISTS infisical;"
docker exec -i infisical-db psql -U infisical -c "CREATE DATABASE infisical;"
docker exec -i infisical-db psql -U infisical -d infisical < infisical_dump.sql
 
# 5. Restart
docker compose -f C:\_my\_solanasis\infisical\docker-compose.yml restart
 
# 6. Verify — open https://sm.solanasis.com and check secrets are intact

Testing

Test file: C:\_my\_solanasis\infisical\test_sync_env.py

# Preflight health check (credential lookup, Infisical auth, repo paths)
python test_sync_env.py --check-only
 
# Full test suite (unit + live smoke test — needs Infisical running)
pytest test_sync_env.py -v
 
# Unit tests only (no Infisical dependency)
pytest test_sync_env.py -v -k "not smoke"
 
# Smoke test only (sets _TEST_CANARY key, syncs, verifies, cleans up)
pytest test_sync_env.py -v -k smoke

What’s covered:

  • _resolve_path — Windows-to-WSL path translation (9 cases)
  • get_client_secret — credential file parsing and error handling
  • write_env_file — output format, quoting, escaping, line endings
  • detect_repo — auto-detection from working directory
  • Smoke test — live round-trip: set → get → fetch → write .env → delete

WSL Cross-Platform Support

Both manage_secrets.py and sync_env.py work on Windows and WSL. Windows paths in the REPOS dict (C:\_my\...) are translated to WSL mount paths (/mnt/c/_my/...) at runtime via _resolve_path().


Docker Management

Config Files

Common Commands

# Check container status
docker ps --filter "name=infisical"
 
# View logs (follow)
docker compose -f C:\_my\_solanasis\infisical\docker-compose.yml logs -f backend
 
# Restart all containers
docker compose -f C:\_my\_solanasis\infisical\docker-compose.yml restart
 
# Restart just the backend
docker compose -f C:\_my\_solanasis\infisical\docker-compose.yml restart backend
 
# Stop everything
docker compose -f C:\_my\_solanasis\infisical\docker-compose.yml down
 
# Start everything
docker compose -f C:\_my\_solanasis\infisical\docker-compose.yml up -d
 
# Update to latest image
docker compose -f C:\_my\_solanasis\infisical\docker-compose.yml pull
docker compose -f C:\_my\_solanasis\infisical\docker-compose.yml up -d
 
# Check database health
docker exec infisical-db pg_isready -U infisical

Container Details

ContainerImagePortPurpose
infisical-backendinfisical/infisical:latest8580→8080API + Web UI
infisical-dbpostgres:14-alpine5432 (internal)Database
infisical-redisredis:7-alpine6379 (internal)Cache

Cloudflare Access Management

Current Config

  • Zero Trust org: solanasis.cloudflareaccess.com
  • Access app: “Infisical Vault” (ID: da38e27f-5a00-4378-afbe-4b7219ceff64)
  • Identity provider: One-Time PIN / email OTP (ID: 0e45b63d-da8a-45f8-8d46-a45b31019690)
  • Policy: Allow mr.sunshine@solanasis.com and ds@solanasis.com
  • Session duration: 24 hours
  • Cloudflare docs: https://developers.cloudflare.com/cloudflare-one/

API Credentials

  • Account ID: 5bc74cd88016b1dd85d05955675fdba8
  • Auth header: X-Auth-Email: mr.sunshine@solanasis.com
  • Auth key: CLOUDFLARE_GLOBAL_API_KEY (Windows env var + Infisical /shared/)

Add a New Allowed Email

CF_KEY=$(powershell -Command "[System.Environment]::GetEnvironmentVariable('CLOUDFLARE_GLOBAL_API_KEY', 'User')")
 
# Get current policy
curl -s "https://api.cloudflare.com/client/v4/accounts/5bc74cd88016b1dd85d05955675fdba8/access/apps/da38e27f-5a00-4378-afbe-4b7219ceff64/policies/3a898274-8606-41f7-9efd-c322f90aa21a" \
  -H "X-Auth-Email: mr.sunshine@solanasis.com" \
  -H "X-Auth-Key: $CF_KEY"
 
# Update policy to add new email (include ALL existing emails + new one)
curl -s -X PUT "https://api.cloudflare.com/client/v4/accounts/5bc74cd88016b1dd85d05955675fdba8/access/apps/da38e27f-5a00-4378-afbe-4b7219ceff64/policies/3a898274-8606-41f7-9efd-c322f90aa21a" \
  -H "X-Auth-Email: mr.sunshine@solanasis.com" \
  -H "X-Auth-Key: $CF_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Solanasis Team",
    "decision": "allow",
    "include": [
      {"email": {"email": "mr.sunshine@solanasis.com"}},
      {"email": {"email": "ds@solanasis.com"}},
      {"email": {"email": "NEW_EMAIL@solanasis.com"}}
    ]
  }'

WAF Rate Limiting

  • Ruleset ID: 63dd254071b6436fa7e377ecd54681a2
  • Rule: 10 req per 10s per IP on /api/ paths, block 10s
  • Zone ID: ceb3c9dcba422dc31900360da7117173

Security Layers

LayerWhat It DoesConfig Location
Cloudflare Access (OTP)Perimeter gate — email allowlist + OTPCloudflare Zero Trust dashboard
Infisical authApplication login (email + password)Infisical admin panel
Invite-only signupBlocks new registrationsINVITE_ONLY_SIGNUP=true in .env
Email domain restrictionOnly @solanasis.com can registerInfisical admin panel (allowedSignUpDomain)
WAF rate limiting10 req/10s per IP on API endpointsCloudflare WAF rulesets
Encrypted backupsAES-256-CBC encrypted daily backupsBackup script + GitHub

Emergency Procedures

ENCRYPTION_KEY Lost

Severity: Critical — ALL secrets in Infisical become unrecoverable.

  1. Check Bitwarden first: ENCRYPTION_KEY and AUTH_SECRET are stored in Bitwarden vault
  2. If not in Bitwarden: Decrypt the latest daily backup (see Restore Procedure above)
  3. The dot_env file in the archive contains the ENCRYPTION_KEY
  4. Copy it back to C:\_my\_solanasis\infisical\.env
  5. Restart containers

If neither Bitwarden nor backup has it: All stored secrets are permanently lost. You’ll need to:

  1. Delete Docker volumes: docker volume rm infisical_pg_data infisical_redis_data
  2. Set up Infisical from scratch with a new ENCRYPTION_KEY
  3. Re-enter all secrets manually

Cannot Access sm.solanasis.com

  1. Check Cloudflare tunnel: sudo systemctl status cloudflared (in WSL2)
  2. Check Docker containers: docker ps --filter "name=infisical"
  3. Check localhost directly: curl http://localhost:8580 (bypasses Cloudflare)
  4. Restart tunnel: sudo systemctl restart cloudflared (in WSL2)
  5. Restart containers: docker compose -f C:\_my\_solanasis\infisical\docker-compose.yml restart

Cloudflare Access Issues

  • Check identity providers: API GET /accounts/{acct}/access/identity_providers
  • Check app config: API GET /accounts/{acct}/access/apps
  • Cloudflare status: https://www.cloudflarestatus.com/