Choose a secrets backend
AgentArea handles two different kinds of secret, and they are stored in different places by different mechanisms. Confusing them is the usual reason a deployment ends up with credentials somewhere the operator did not expect.
This guide covers both. The secret manager backend is the choice with
consequences; the deployment secrets are mostly about supplying your own instead
of letting the chart generate them.
Prerequisites
- A running or planned deployment — see Kubernetes or Docker Compose
- For Infisical: a project, a machine identity, and its client ID and client secret
Steps
1. Choose a workspace secret backend
Two backends exist.SECRET_MANAGER_TYPE selects between them, and any other
value raises Invalid SECRET_MANAGER_TYPE at startup rather than falling back.
database (default). Secrets are encrypted with Fernet and stored in the
encrypted_secrets table in the platform’s own PostgreSQL database, scoped by
workspace_id. Pick this when you do not already run a secret manager: it adds
no operational surface, and the ciphertext is covered by your existing database
backup. The tradeoff is that the encryption key travels as an environment
variable next to the database that holds the ciphertext, so anyone who can read
both the pod environment and the database can read every stored credential.
infisical. Secrets are read from and written to an Infisical instance
through the infisical-sdk client. Pick this when you already operate
Infisical and want credential storage outside the application database.
2. Configure the database backend
Generate a Fernet key. It must be a real Fernet key, not an arbitrary string.
agentarea-app-secrets Secret under key encryption-key, and reuses the
existing value on every subsequent upgrade. To supply your own, create the
Secret before installing:
encryption-key leaves the API crash-looping at startup.
Under Compose, set it in .env:
Fernet raises InvalidToken on decrypt, and there is no
re-encryption path in the platform. Treat it as permanent for the life of the
database, and back it up separately from the database itself, or a restore gives
you ciphertext you cannot open.
3. Configure the infisical backend
SECRET_MANAGER_ENDPOINT defaults to https://app.infisical.com when unset.
Both SECRET_MANAGER_ACCESS_KEY and SECRET_MANAGER_SECRET_KEY are required;
the factory raises Infisical credentials not configured at startup if either
is missing, before any request is served.
The infisical-sdk package must be installed in the image. If it is not, the
factory raises Infisical SDK not installed.
4. Supply the deployment secrets
On Kubernetes the chart generates any of these that do not already exist, and annotates each withhelm.sh/resource-policy: keep so helm uninstall leaves
them behind. On upgrade it looks each one up and reuses the existing value, so
credentials do not rotate underneath a running deployment.
Rename any of them through
global.secrets.postgresql, global.secrets.redis,
global.secrets.rustfs, and global.secrets.application to point at Secrets you
manage yourself — with an external secrets operator, for instance.
When you disable a bundled dependency, the chart stops generating its Secret.
Setting postgresql.enabled=false means you must create
agentarea-postgresql-secret with username and password yourself, because
the migration Jobs and every service still read it.
5. Replace the development credentials under Compose
.env.example ships values that are fine to develop against and not fine to
deploy:
SECRET_MANAGER_ENCRYPTION_KEY— a real Fernet key, committed to the repositorySANDBOX_ACTIVATION_AUTH_SECRETandSANDBOX_CLEANUP_AUTH_SECRET— placeholders that saychange-in-prod; both must be at least 32 bytesKRATOS_JWKS_B64— a test JWKS including the private keyd, so anyone with the repository can mint tokens the API will acceptPOSTGRES_PASSWORD=postgres,RUSTFS_ACCESS_KEY=minioadmin,RUSTFS_SECRET_KEY=minioadmin
${VAR:?...}, so an empty value
aborts the run instead of starting an unauthenticated sandbox activation path.
The others have working defaults and will not stop you.
Verify
Confirm the backend the API actually selected.SecretManagerFactory logs its
type on initialization:
encrypted_value prefix should be Fernet ciphertext (gAAAAA...), not the
key you typed. If you configured Infisical, the table stays empty and the secret
appears in your Infisical project instead.
Troubleshooting
API exits at startup withSECRET_MANAGER_ENCRYPTION_KEY environment variable must be set. The database backend has no key. This is validated in
SecretManagerFactory.__init__, so it fails at construction rather than on the
first secret read — the process will not serve traffic in a state where secret
storage is broken.
Reads fail with InvalidToken after a restore or a redeploy. The encryption
key no longer matches the ciphertext. Restore the original key. There is no
recovery path from the database side, and no re-encryption command; if the key
is genuinely lost, every stored credential has to be re-entered.
Agents fail on tool calls with a missing credential, but the UI shows the
secret saved. The worker and the API disagree on SECRET_MANAGER_TYPE or on
the key. Both processes construct their own secret manager. Compare the
Initialized SecretManagerFactory with type: line in each.
helm upgrade rotates a password and breaks the database connection. This
happens when the Secret was deleted between operations — the chart’s lookup
finds nothing and generates a fresh value, while the PostgreSQL volume still has
the old one. The helm.sh/resource-policy: keep annotation prevents this on
uninstall, but not against a manual kubectl delete secret.
Infisical is configured but startup raises Infisical SDK not installed.
The infisical-sdk package is absent from the image. It is an optional
dependency of the platform.