Config & Secrets Management

The tawa config command manages environment variables and encrypted secrets for your services on the Tawa platform. Plain config vars and secrets are stored in the builder, injected into your pod on every deploy, and never need to touch your codebase.

CLI commands

All config and secret management flows through the tawa config subcommand. Changes are stored in the builder and take effect on the next deploy.

Set a plain config var

# Set one or more plain config vars (visible in logs and API responses)
tawa config set LOG_LEVEL=debug API_TIMEOUT=30000

Set an encrypted secret

# Set a secret (encrypted at rest with AES-256-GCM, value never returned by API)
tawa config set STRIPE_SECRET_KEY=sk_live_... --secret

List config

# List all config vars and secret key names (secret values are hidden)
tawa config list

Output shows plain config values in full. For secrets, only the key name is displayed — the value is replaced with ********.

Remove a config var

# Remove a config var or secret
tawa config unset STRIPE_SECRET_KEY

Pull config to local

# Pull all config + decrypted secrets to .env.local
tawa config pull

Writes a .env.local file with 0600 permissions (owner read/write only). Useful for running your service locally with the same config as the deployed environment.

Push local config

# Push .env.local values to the builder
tawa config push

Reads your local .env.local and uploads each key-value pair to the builder as a plain config var. Secrets must be set individually with the --secret flag.

Remember: After setting or changing config, you must redeploy with tawa deploy for the changes to take effect in your running pod.

How secrets work

Secrets follow a different path than plain config vars. Here is what happens end to end:

  1. You run tawa config set MY_KEY=value --secret
  2. The builder encrypts the value with AES-256-GCM and stores the ciphertext in its MongoDB database
  3. On deploy, the builder decrypts all secrets for your service and creates a Kubernetes Secret named {service}-managed-secrets in your namespace
  4. The secret is mounted into your pod via envFrom.secretRef, making each key available as an environment variable
  5. Your app reads the value with process.env.MY_KEY — no decryption needed in your code
Secret values are never returned by the API. When you run tawa config list, secret keys are shown but values are masked. The only way to retrieve a secret value is tawa config pull, which writes the decrypted value to .env.local on your local machine.

Auto-provisioned variables

The builder automatically injects certain environment variables based on declarations in your catalog-info.yaml. You do not need to set these with tawa config — they are generated fresh on every deploy.

SourceVariableProvisioned from
DatabasesMONGODB_URIspec.databases with type: mongodb
DatabasesREDIS_URLspec.databases with type: redis
DatabasesNEO4J_URIspec.databases with type: neo4j
OAuthBIO_CLIENT_IDAuto-created OAuth client in Bio-ID
OAuthBIO_CLIENT_SECRETAuto-created OAuth client in Bio-ID
Internal deps{SERVICE}_URLspec.internalDependencies resolved to K8s DNS

For example, if your catalog declares spec.internalDependencies with service: iec-wallet, the builder resolves it to a K8s cluster DNS URL and injects it as IEC_WALLET_URL.

Precedence

When the same variable is defined in multiple places, the highest precedence wins. From lowest to highest:

  1. catalog-info.yaml defaults — platform defaults derived from your catalog declarations (e.g., NODE_ENV)
  2. Managed config — plain vars set via tawa config set
  3. Kubernetes Secret — encrypted secrets set via tawa config set --secret, mounted via envFrom.secretRef

This means a secret always overrides a plain config var with the same name, and a config var always overrides a platform default. If you need to revert to the platform default, remove your override with tawa config unset.

Local development

Use tawa config pull to download your deployed config into a local .env.local file:

tawa config pull
# Writes .env.local with all config + decrypted secrets
# File permissions: 0600 (owner read/write only)

The resulting file looks like a standard dotenv file:

# .env.local (auto-generated by tawa config pull)
LOG_LEVEL=debug
API_TIMEOUT=30000
STRIPE_SECRET_KEY=sk_live_abc123...
MONGODB_URI=mongodb://db.tawa.insureco.io:27017/my-svc-sandbox
REDIS_URL=redis://db.tawa.insureco.io:6379/0

Most Node.js frameworks (Next.js, Vite, dotenv) load .env.local automatically. Your app code reads process.env.STRIPE_SECRET_KEY the same way whether running locally or in a pod.

Add .env.local to your .gitignore. This file contains decrypted secrets. Never commit it to version control.

Common mistakes

Hardcoding secrets in code

// WRONG: hardcoded secret
const apiKey = "sk_live_abc123..."

// CORRECT: read from environment
const apiKey = process.env.STRIPE_SECRET_KEY
if (!apiKey) throw new Error('STRIPE_SECRET_KEY not configured')

Use tawa config set --secret to store the value, then read it from process.env in your code.

Committing .env.local to git

The .env.local file contains decrypted secrets pulled from the builder. Make sure it is listed in your .gitignore:

# .gitignore
.env.local
.env*.local

Forgetting to redeploy after setting secrets

Running tawa config set stores the value in the builder's database, but it does not update your running pod. You must run tawa deploy for the new value to be injected into the Kubernetes Secret and picked up by your service.

Setting auto-provisioned vars manually

Variables like MONGODB_URI and BIO_CLIENT_ID are generated by the builder on every deploy. Setting them with tawa config set will create a conflict — your manual value may be overwritten by the auto-provisioned one. Instead, declare databases and OAuth in catalog-info.yaml and let the builder handle the connection strings.

Related