# 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 data - `token_secret_key` - JWT signing key - `nextauth_secret` - NextAuth.js secret key ### OAuth Secrets - `google_oauth_client_id` - Google OAuth client ID - `google_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: ```yaml 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/` inside containers. Services should read secrets from these mounted files rather than environment variables. Example of reading a secret in Node.js: ```javascript 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: 1. Admin User (postgres): - Username: postgres - Password: Stored in postgres_password secret - Used for: * Database administration * Setup and migrations * Schema changes * Full database access 2. 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 1. Never commit secret files to version control 2. Add secret files to .gitignore 3. Use different secrets for different environments 4. Rotate secrets periodically 5. Limit secret access to only the services that need them 6. Use strong, unique passwords for each secret 7. Ensure proper file permissions on secret files 8. Follow principle of least privilege: - Use app_user for application access - Reserve postgres user for administration only ## Setting Up Secrets 1. Create the `secrets/` directory 2. Create individual files for each secret: ```bash # 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 ``` 3. Set appropriate permissions: ```bash chmod 600 secrets/* ``` 4. Update docker-compose files to use secrets 5. 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: 1. Copy `.env.example` to `.env` 2. Fill in non-sensitive values in `.env` 3. Create corresponding secret files for sensitive values ## Best Practices 1. Always use secrets for sensitive data, never environment variables 2. Read secrets from files at runtime, not during build 3. Use consistent naming across all components 4. Document any changes to secret management 5. Keep secret files secure and backed up 6. Implement proper secret rotation procedures 7. Monitor secret usage and access patterns 8. Follow the principle of least privilege: - Use app_user for normal operations - Limit postgres user access to administration - Implement proper RLS policies