DECOMMISSIONED 2026-06-21 — Infisical CE containers have been stopped and removed from vps-i1 as part of the SOPS+age migration (PR #806). This document is retained as a historical reference only.
All secrets are now managed via SOPS+age — see docs/secrets-management.md and docs/secrets-sops-age.md.
secrets named INFISICAL_ADMIN_EMAIL, INFISICAL_ADMIN_PASSWORD
The admin account is the first account created during initial setup. It has full org-owner access.
Reset procedure (when password is forgotten)
The “Forgot password” email flow requires SMTP to be configured in the Infisical container. If SMTP is not wired up, reset via Postgres directly:
# 1. Get a bcrypt hash for your new password (run locally)python3 -c "import bcrypt; print(bcrypt.hashpw(b'YOUR_NEW_PASSWORD', bcrypt.gensalt(12)).decode())"# 2. Update the hash in Infisical's Postgresssh root@217.154.82.162docker exec -it monitoring-infisical-postgres-1 psql -U infisical -d infisical \ -c "UPDATE users SET password_hash = 'HASH_FROM_STEP_1' WHERE email = 'radieu@gmail.com';"# 3. Verify login at https://infisical.vps-i1.infra.zintegrowana.online
Note: bcrypt is available via pip install bcrypt if not already installed.
1. Overview
Infisical Community Edition is the secrets vault for the entire p24-infra ecosystem. All other services (monitoring stack, n8n, audit-engine, GitHub Actions workflows) draw credentials from it via Machine Identity Universal Auth.
Three containers form the stack:
Container
Image
Role
monitoring-infisical-1
infisical/infisical:v0.161.0
API + web UI
monitoring-infisical-postgres-1
postgres:16.9-alpine
Secret storage (encrypted)
monitoring-infisical-redis-1
redis:7.4.2-alpine
Session cache
Projects (Infisical slugs):
Project slug
Used by
MI env var prefix
p24-monitoring-f5de
vps-i1 monitoring stack + audit-engine
INFISICAL_MI_P24_MONITORING_*
n8n-bms4-ywf-z (latest)
bms-4 n8n stack
INFISICAL_MI_N8N_BMS4_*
vps-h1-ntjx (latest)
vps-h1 WAHA stack
INFISICAL_MI_VPS_H1_*
bms-servers-mq-he (latest)
BMS server agents
INFISICAL_MI_BMS_SERVERS_*
github-actions-s-m15
All GitHub Actions workflows
INFISICAL_MI_GITHUB_ACTIONS_*
art-agency
Art Agency portal (Supabase, PayPal, KDP, Google Drive)
INFISICAL_MI_ART_AGENCY_*
radekkonarski-brand
Radek personal brand (LinkedIn, HeyGen, Wasabi, n8n, Anthropic)
INFISICAL_MI_RADEK_BRAND_*
brandpilot-ovb-0
BrandPilot AI brand automation (GitHub: p24-infra/brandpilot)
ENCRYPTION_KEY + JWT secrets extracted from container
monitoring.env
$WORK/monitoring.env
Full monitoring stack env (all credentials)
Destination:s3://ecotrans-backups/vps-i1/<YYYY-MM-DD>/backup.tar.zst.age Encryption: age (recipient = AGE_PUBKEY from /root/.backup-env) Retention: 30 days daily (managed by backup-common.sh parent job)
Critical: ENCRYPTION_KEY
The INFISICAL_ENCRYPTION_KEY env var is the AES master key that encrypts every secret value in the database. Without it, the database dump cannot be decrypted. It is captured two ways:
infisical-keys/infisical-env.txt — extracted from the running container
monitoring.env — full env file snapshot
Both are inside the age-encrypted archive, so the age private key (stored externally) is the single recovery prerequisite.
Age private key storage
The age private key is not stored on any VPS. It must be kept in an offline/out-of-band secret store (e.g. Bitwarden vault, paper backup, GPG-encrypted USB). Without it the backup archive cannot be decrypted.
A running Docker host with monitoring/docker-compose.yml deployed (vps-i1 or replacement)
Step 1 — Download and decrypt archive
# Install age and aws CLI if not presentapt-get install -y age awscli zstd# Download the backupaws --endpoint-url https://s3.eu-central-1.wasabisys.com \ s3 cp "s3://ecotrans-backups/vps-i1/<DATE>/backup.tar.zst.age" /tmp/backup.tar.zst.age# Decrypt and extractage -d -i /path/to/age-private-key /tmp/backup.tar.zst.age \ | zstd -d \ | tar -xf - -C /tmp/restore/
Step 2 — Recover INFISICAL_ENCRYPTION_KEY
# The key is in either of:cat /tmp/restore/infisical-keys/infisical-env.txt # extracted varsgrep INFISICAL_ENCRYPTION_KEY /tmp/restore/monitoring.envgrep INFISICAL_JWT /tmp/restore/monitoring.env
Note these values — you will need them in Step 4.
Step 3 — Start a fresh Infisical stack with the original keys
Ensure monitoring/.env on the recovery host contains the original values from /tmp/restore/monitoring.env. The critical vars are:
cd /opt/p24-infra/monitoringdocker compose up -d infisical-postgres infisical-redis# Wait for postgres healthydocker compose ps
Step 4 — Restore the database dump
# Copy dump into a temp location accessible by the containerdocker cp /tmp/restore/infisical_postgres.dump monitoring-infisical-postgres-1:/tmp/restore.dump# Drop and recreate the databasedocker exec -it monitoring-infisical-postgres-1 psql -U infisical -c "DROP DATABASE IF EXISTS infisical;"docker exec -it monitoring-infisical-postgres-1 psql -U infisical -c "CREATE DATABASE infisical;"# Restoredocker exec -it monitoring-infisical-postgres-1 \ pg_restore -U infisical -d infisical --no-owner --no-acl /tmp/restore.dump# Clean updocker exec monitoring-infisical-postgres-1 rm /tmp/restore.dump
Step 5 — Start Infisical and verify
docker compose up -d infisicalsleep 30docker compose ps # infisical should be healthy# Smoke test: health endpointcurl -k https://infisical.vps-i1.infra.zintegrowana.online/api/status# Expected: {"date":"...","message":"OK","..."}
Step 6 — Test Machine Identity auth
# From vps-i1 — test p24-monitoring MIsource /opt/infisical/monitoring.envcurl -sk -X POST "$INFISICAL_URL/api/v1/auth/universal-auth/login" \ -H 'Content-Type: application/json' \ -d "{\"clientId\":\"$INFISICAL_CLIENT_ID\",\"clientSecret\":\"$INFISICAL_CLIENT_SECRET\"}" \ | python3 -c "import sys,json; t=json.load(sys.stdin); print('OK' if t.get('accessToken') else 'FAIL')"
Step 7 — Restart all dependent services
# Restart monitoring stack to pick up Infisical secretscd /opt/p24-infra/monitoring./start.sh # re-runs infisical run -- docker compose up -d# On bms-4: restart n8n stackssh root@54.36.123.110 "cd /root && bash /root/start.sh"
4. Encryption key rotation
Machine Identity client secrets do not expire. Rotate manually if a MI is compromised:
Log in to Infisical UI → Settings → Machine Identities → select identity → Regenerate secret
Update the credential in the affected service’s env:
vps-i1 monitoring: update INFISICAL_CLIENT_SECRET in /opt/infisical/monitoring.env and restart
bms-4 n8n: update INFISICAL_CLIENT_SECRET in
/opt/infisical/n8n.env (canonical MI bootstrap file) and restart
Update .env.local on the developer workstation
INFISICAL_ENCRYPTION_KEY rotation requires decrypting and re-encrypting all secrets — do not rotate unless the key is confirmed compromised. Contact the Infisical CE docs for the rotation procedure.
The following vars are Infisical CE app secrets — they are not managed inside Infisical itself (chicken-and-egg). They must be kept in sync across three locations whenever rotated.
Secret
Role
Recoverable without it?
INFISICAL_ENCRYPTION_KEY
AES master key — encrypts every secret value in the DB
No — DB dump is unreadable
INFISICAL_AUTH_SECRET
General auth signing
Yes — regenerate, all sessions invalidated
INFISICAL_JWT_AUTH_SECRET
JWT auth tokens
Yes — regenerate, all sessions invalidated
INFISICAL_JWT_SIGNUP_SECRET
Signup flow JWTs
Yes
INFISICAL_JWT_REFRESH_SECRET
Refresh token signing
Yes
INFISICAL_JWT_MFA_OTP_SECRET
MFA OTP signing
Yes
INFISICAL_JWT_PROVIDER_AUTH_SECRET
OAuth provider tokens
Yes
INFISICAL_DB_PASSWORD
Postgres password
Yes — can reset via ALTER ROLE
Three mandatory backup locations
Every one of the above must exist in all three of these locations at all times:
Write-Output $newVal | gh secret set KEY --repo radieu/p24-infra
monitoring/.env on vps-i1 (runtime source)
Already updated by the rotation; verify with grep KEY /opt/p24-infra/monitoring/.env
INFISICAL_ENCRYPTION_KEY must also be recorded in the nightly backup. It is captured automatically from the running container by scripts/backup-ionos.sh — confirm backup ran successfully after rotation.
Rotation checklist
When rotating any of these secrets:
[ ] 1. Update monitoring/.env on vps-i1
[ ] 2. Restart Infisical container: docker compose -f /opt/p24-infra/monitoring/docker-compose.yml up -d --no-deps infisical
[ ] 3. Verify Infisical healthy: curl -sk https://infisical.vps-i1.infra.zintegrowana.online/api/status
[ ] 4. Update .env.local on developer workstation
[ ] 5. Sync to GH Secrets: Write-Output $newVal | gh secret set INFISICAL_XXX --repo radieu/p24-infra
[ ] 6. Append rotation entry to docs/secrets-rotation-log.md
[ ] 7. ENCRYPTION_KEY only: wait for next nightly backup and confirm BackupStale alert is green
secrets-rotation-log.md entry format (for these keys)
Replace <service> with the container name, e.g. alertmanager, cost-exporter, grafana.
Omit --no-deps and the service name to restart the entire stack.
If the secret also belongs to another project (n8n-bms4, vps-h1, github-actions) — update it there too and trigger that stack’s regen (see project table below).
Run scripts/sync-github-secrets.ps1 or push to main
All three regen scripts run automatically via daily cron (06:00/06:05/06:10 UTC).
Logs: /var/log/infisical-regen.log on each host.
6. Vault coverage and exceptions
Infisical CE is the single source of truth for all p24-infra credentials. Every secret that flows into a running container or script must live in Infisical first.
Developer workstation local override and rotation scratch-pad
Local file — not committed. Synced manually from Infisical or updated during rotation scripts
secrets/*.sops.yaml
Legacy SOPS-encrypted files from before Infisical rollout (2026-06). May contain stale values.
Git repo (encrypted). No longer the source of truth — migrate any remaining active secrets to Infisical and archive these files
Age private key
Required to decrypt SOPS backup archives — cannot be stored in Infisical
Bitwarden vault / offline backup (never on any VPS)
monitoring/.env.bak
Derived cache generated from Infisical — not a primary store
vps-i1 /opt/p24-infra/monitoring/.env.bak — regenerate after every Infisical change (see §5)
SOPS migration status
The secrets/*.sops.yaml files are legacy. After the Infisical rollout (2026-06-16), all active secrets should be in Infisical. The SOPS files are kept as a historical reference and for the age-encrypted Wasabi backup restore path. Do not add new secrets to SOPS files — add them to Infisical instead.
7. Health monitoring
Infisical is monitored via its Docker health check (wget -qO- http://localhost:8080/api/status). The Grafana monitoring stack scrapes container states via cAdvisor.
Current gaps:
No dedicated Prometheus exporter for Infisical secret-access metrics
Backup success is tracked via backup_last_success_timestamp metric on vps-i1