Secrets¶
Every credential has a name: IB_ACCOUNT, IB_USER_NAME, IB_PASSWORD, IB_TRADING_MODE, COINBASE_API_KEY, COINBASE_API_SECRET, POSTGRES_DSN, REDIS_URL, TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID, POLYGON_API_KEY and IEX_CLOUD_API_KEY. execution/secrets_io.py finds each one, first match wins, in:
- the file named by
AETHER_<NAME>_FILE(the Docker and Kubernetes convention) - the Docker secret
/run/secrets/aether_<name> - the environment variable
AETHER_<NAME>, which is what every service read before; with only that set, nothing changes - the OS keyring, service
aether-quant(aq secrets set NAME)
A named account reads AETHER_<ACCOUNT>_<NAME> instead, so two accounts never share a credential by accident. A value travels as a SecretValue, whose repr, str and f-string forms are ***.
aq secrets status # names, whether each resolves, from where; never a value
aq secrets set COINBASE_API_KEY # prompted, stored in the OS keyring (pip install keyring)
aq render-lean-config # lean.live.json for the default account, from those sources
aq render-lean-config --account live-1 # lean.live.live-1.json
With Docker, docker-compose.secrets.yml mounts secrets/postgres_password and secrets/postgres_dsn (gitignored and dockerignored) as Docker secrets, and Postgres reads POSTGRES_PASSWORD_FILE:
docker compose -f docker-compose.yml -f docker-compose.secrets.yml up -d
Never in a repo file. The tracked lean.json stays empty: aq secrets-check, the pre-commit hook and gitleaks in CI fail a commit that fills a secret field. Rotation is RUNBOOK "Secrets": set the new value, render again, restart the deployment, then revoke the old key at the venue.