Skip to main content
InfraAudit stores cloud provider credentials (AWS access keys, GCP service account JSON, Azure service principal secrets, kubeconfig files) in the database. Before writing any credential to disk, the API encrypts it using AES-256-GCM. This page explains how that encryption works, how to manage the key, and what to do when you need to rotate secrets.

How credential encryption works

When you connect a cloud account, InfraAudit encrypts the credentials before inserting them into the database:
  • Algorithm: AES-256-GCM
  • Key source: ENCRYPTION_KEY environment variable
  • Key format: 32-byte value, hex-encoded (64 hex characters)
  • Nonce: A unique random nonce is generated for each encrypted value and prepended to the ciphertext
The ENCRYPTION_KEY is never written to the database. If someone gains access to the database but not the key, the stored credentials are unreadable.

Generate an encryption key

openssl rand -hex 32
# Example output: a3f1b2c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5e6f7a8b9c0d1e2
Set the output as ENCRYPTION_KEY in your .env or Kubernetes Secret.
If you lose ENCRYPTION_KEY, all stored cloud credentials become permanently unreadable. You will need to disconnect and reconnect every provider. Back up the key in a secrets manager (AWS Secrets Manager, GCP Secret Manager, HashiCorp Vault) before going to production.

JWT authentication

InfraAudit validates JWTs using the SUPABASE_JWT_SECRET from your Supabase project. Requests with expired or invalid tokens return 401 Unauthorized. The SUPABASE_SERVICE_ROLE_KEY is used server-side for privileged Supabase operations such as looking up users by ID. This key bypasses Supabase row-level security — keep it confidential and never expose it to the browser or public APIs.

Managing secrets in production

Choose the approach that fits your deployment:
Avoid committing secrets to the .env file if the file is visible in CI or on a shared server. Pass secrets as environment variables directly at runtime:
SUPABASE_JWT_SECRET=your-secret \
ENCRYPTION_KEY=your-key \
docker compose up -d
Alternatively, use Docker Swarm secrets for more structured secret management.

Rotating the encryption key

InfraAudit does not automatically re-encrypt credentials when the key changes. You must manually re-enter provider credentials after rotation.
1

Export your provider list

Note all connected providers and their credential details. You’ll need to re-enter them after the rotation.
2

Stop the API

docker compose stop api
Or for Kubernetes, scale the deployment to zero:
kubectl scale deployment infraudit-api --replicas=0 -n infraudit
3

Update the encryption key

Generate a new key and update it in your secrets store or .env file:
openssl rand -hex 32
4

Restart the API

docker compose start api
Or restore the Kubernetes replica count:
kubectl scale deployment infraudit-api --replicas=1 -n infraudit
5

Reconnect all providers

In the InfraAudit UI, disconnect each cloud provider and reconnect it with fresh credentials. The new credentials will be encrypted with the new key.

Rotating the Supabase JWT secret

Rotating the JWT secret in Supabase invalidates all active user sessions immediately. Update your deployment at the same time to avoid downtime.
1

Rotate the secret in Supabase

In your Supabase project, go to Settings → API → JWT Settings and click Rotate JWT Secret. Copy the new value.
2

Update your deployment

Update SUPABASE_JWT_SECRET in your .env file or Kubernetes Secret with the new value.
3

Restart the API

docker compose restart api
The API will start validating tokens against the new secret immediately.
Users will need to log in again after a JWT secret rotation. Their data is unaffected.

Production security checklist

Review these items before going live:
  • ENCRYPTION_KEY was generated with openssl rand -hex 32 — not a placeholder or default value
  • DB_PASSWORD is unique and not the default infraudit123
  • SUPABASE_SERVICE_ROLE_KEY is not in version control
  • ENVIRONMENT=production is set (disables Swagger UI and debug endpoints)
  • DB_SSLMODE=require is set if the database is not on localhost
  • ALLOWED_ORIGINS is set to your frontend URL, not *
  • /metrics endpoint is protected with METRICS_AUTH_TOKEN if internet-accessible
  • ENCRYPTION_KEY is backed up in a secrets manager