Saltar a contenido

Configuracion de Secretos

GexCom usa Pydantic Settings para gestionar configuracion y secretos via variables de entorno. La clave JWT es validada en startup — una clave por defecto en produccion causa un error inmediato.

Variables de Entorno

Variable Descripcion Por defecto Requerida en prod
DATABASE_URL URL de conexion PostgreSQL async SQLite local Si
DATABASE_SYNC_URL URL de conexion PostgreSQL sync (API) SQLite local Si
SECRET_KEY Clave secreta para firmar JWT changeme-insecure-key Si
JWT_ALGORITHM Algoritmo JWT HS256 No
JWT_EXPIRATION_MINUTES Duracion del token en minutos 480 No
ENVIRONMENT Entorno actual development No

Archivo .env (Desarrollo Local)

Crear .env en la raiz del proyecto (ignorado por git):

# .env — NO commitear
DATABASE_URL=sqlite+aiosqlite:///./gexcom_dev.db
DATABASE_SYNC_URL=sqlite:///./gexcom_dev.db
SECRET_KEY=mi-clave-secreta-local-solo-desarrollo
ENVIRONMENT=development

Docker Compose (PostgreSQL)

# docker-compose.yml (fragmento)
environment:
  - DATABASE_URL=postgresql+asyncpg://gexcom:gexcom_dev@postgres:5432/gexcom
  - DATABASE_SYNC_URL=postgresql+psycopg2://gexcom:gexcom_dev@postgres:5432/gexcom
  - SECRET_KEY=${SECRET_KEY:-changeme-insecure-key}
  - ENVIRONMENT=production

Para produccion, pasar SECRET_KEY como variable de entorno del host:

export SECRET_KEY="clave-segura-aleatoria-256-bits"
docker-compose up -d

Validacion en Startup

Settings valida que la clave JWT no sea el valor por defecto fuera de development/test:

# src/gexcom/infrastructure/config.py
_DEFAULT_SECRET = "changeme-insecure-key"

class Settings(BaseSettings):
    secret_key: str = _DEFAULT_SECRET
    environment: str = "development"

    @model_validator(mode="after")
    def validate_secret_key(self) -> "Settings":
        if self.environment not in ("development", "test"):
            if self.secret_key == _DEFAULT_SECRET:
                raise ValueError(
                    "SECRET_KEY must be changed in non-development environments. "
                    "Set the SECRET_KEY environment variable."
                )
        return self

Si el servidor arranca en environment=production con la clave por defecto, falla inmediatamente con un ValueError claro.

Generar una Clave Segura

# Generar clave aleatoria de 256 bits
import secrets
print(secrets.token_hex(32))
# → "a8f5f167f44f4964e6c998dee827110c..."

O con OpenSSL:

openssl rand -hex 32

Secretos de Dispatch

Los dispatchers leen credenciales desde variables de entorno:

# Email SMTP
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=notificaciones@csj-bello.gov.co
SMTP_PASSWORD=app-password-gmail

# WhatsApp Meta API
WHATSAPP_TOKEN=EAAxxxxx
WHATSAPP_PHONE_ID=1234567890

Nunca en el codigo fuente

Los tokens de API, contrasenas SMTP y claves JWT nunca deben aparecer hardcodeados en el codigo. Usar siempre variables de entorno o un gestor de secretos (Vault, AWS Secrets Manager, etc.).

Checklist de Produccion

  • SECRET_KEY generada con secrets.token_hex(32) y almacenada como variable de entorno
  • ENVIRONMENT=production configurado
  • DATABASE_URL apunta a PostgreSQL (no SQLite)
  • Credenciales SMTP configuradas
  • Tokens WhatsApp configurados
  • .env excluido de git (verificar .gitignore)
  • Dockerfile no contiene secretos hardcodeados