Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
5.3 KiB
Secrets Management
This document outlines how sensitive data is managed in the application using Docker secrets.
Overview
Instead of storing sensitive data in environment variables or configuration files, we use Docker secrets to securely manage sensitive information. This approach provides several benefits:
- Secrets are stored securely on disk
- Secrets are only mounted in containers that need them
- Secrets are never exposed in container inspection or logs
- Secrets are mounted as files, providing a consistent interface across services
Secret Files
All secrets are stored in the secrets/ directory at the project root. Each secret is stored in its own file:
Database Secrets
postgres_password- PostgreSQL admin password (used by 'postgres' user for administration)db_password_server- Application user password (used by 'app_user' for RLS-controlled access)db_password_hocuspocus- Hocuspocus service password
Redis Secrets
redis_password- Redis password
Email Secrets
email_password- SMTP server password
Security Secrets
crypto_key- Encryption key for sensitive datatoken_secret_key- JWT signing keynextauth_secret- NextAuth.js secret key
OAuth Secrets
google_oauth_client_id- Google OAuth client IDgoogle_oauth_client_secret- Google OAuth client secret
Usage in Docker Compose
Secrets are defined in the docker-compose.yaml file under the secrets section and mounted to services that need them. For example:
secrets:
postgres_password:
file: ./secrets/postgres_password
db_password_server:
file: ./secrets/db_password_server
services:
postgres:
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password
secrets:
- postgres_password
server:
environment:
DB_USER_SERVER: app_user
volumes:
- type: bind
source: ./secrets/db_password_server
target: /run/secrets/db_password_server
read_only: true
Accessing Secrets in Containers
Secrets are mounted at /run/secrets/<secret_name> inside containers. Services should read secrets from these mounted files rather than environment variables.
Example of reading a secret in Node.js:
const fs = require('fs');
const dbPassword = fs.readFileSync('/run/secrets/db_password_server', 'utf8').trim();
Database Authentication
The system uses a two-user database authentication model for security:
-
Admin User (postgres):
- Username: postgres
- Password: Stored in postgres_password secret
- Used for:
- Database administration
- Setup and migrations
- Schema changes
- Full database access
-
Application User (app_user):
- Username: app_user
- Password: Stored in db_password_server secret
- Used for:
- Application database access
- Limited access via RLS policies
- Regular database operations
- Security:
- Access controlled by Row Level Security (RLS)
- Cannot modify schema or bypass RLS
Security Considerations
- Never commit secret files to version control
- Add secret files to .gitignore
- Use different secrets for different environments
- Rotate secrets periodically
- Limit secret access to only the services that need them
- Use strong, unique passwords for each secret
- Ensure proper file permissions on secret files
- Follow principle of least privilege:
- Use app_user for application access
- Reserve postgres user for administration only
Setting Up Secrets
- Create the
secrets/directory - Create individual files for each secret:
# Use single quotes to avoid shell expansion of special characters in secret values.
# If a value contains a single quote ('), use a quoted heredoc instead:
# cat > secrets/email_password <<'EOF'
# your-secret-value
# EOF
# Database
echo 'your-secure-admin-password' > secrets/postgres_password
echo 'your-secure-app-password' > secrets/db_password_server
echo 'your-secure-hocuspocus-password' > secrets/db_password_hocuspocus
# Redis
echo 'your-secure-password' > secrets/redis_password
# Security
echo 'your-32-char-min-key' > secrets/crypto_key
echo 'your-32-char-min-key' > secrets/token_secret_key
echo 'your-32-char-min-key' > secrets/nextauth_secret
# Email & OAuth
echo 'your-email-password' > secrets/email_password
echo 'your-client-id' > secrets/google_oauth_client_id
echo 'your-client-secret' > secrets/google_oauth_client_secret
- Set appropriate permissions:
chmod 600 secrets/*
- Update docker-compose files to use secrets
- Update application code to read from secret files
Environment Variables
The .env.example file indicates which values are managed via Docker secrets. When setting up a new environment:
- Copy
.env.exampleto.env - Fill in non-sensitive values in
.env - Create corresponding secret files for sensitive values
Best Practices
- Always use secrets for sensitive data, never environment variables
- Read secrets from files at runtime, not during build
- Use consistent naming across all components
- Document any changes to secret management
- Keep secret files secure and backed up
- Implement proper secret rotation procedures
- Monitor secret usage and access patterns
- Follow the principle of least privilege:
- Use app_user for normal operations
- Limit postgres user access to administration
- Implement proper RLS policies