Problema detectado: credenciales expuestas en historial git
El commit a3f9b12 del 2024-11-03 contenia .env.staging con NUTRIPAW_DB_PASSWORD y STRIPE_SECRET_KEY en texto plano. Aunque fue eliminado del HEAD, persiste en el historial. Rotar inmediatamente y migrar a AWS Secrets Manager.
| Secreto | Servicio | Entorno | Criticidad | Rotacion | Ruta en AWS SM |
|---|---|---|---|---|---|
NUTRIPAW_DB_PASSWORD |
PostgreSQL RDS | prod staging | ⚡ Critica | 30 dias (auto) | nutripaw/prod/db/password |
NUTRIPAW_STRIPE_SECRET_KEY |
Stripe Payments | prod | ⚡ Critica | 90 dias (manual) | nutripaw/prod/stripe/secret |
NUTRIPAW_OPENAI_API_KEY |
OpenAI API | prod staging | ⚠ Alta | 60 dias (manual) | nutripaw/prod/openai/key |
NUTRIPAW_SENDGRID_API_KEY |
SendGrid Email | prod staging | ⚠ Alta | 90 dias (manual) | nutripaw/prod/sendgrid/key |
NUTRIPAW_JWT_SECRET |
Sesiones de usuario | prod staging | ✓ Media | 180 dias (auto) | nutripaw/prod/jwt/secret |
name: Deploy NutriPaw — Production on: push: branches: [main] permissions: id-token: write # Necesario para OIDC — sin claves AWS en GitHub Secrets contents: read jobs: deploy: runs-on: ubuntu-latest environment: production # Requiere aprobacion manual en GitHub steps: - uses: actions/checkout@v4 ## 1) Autenticacion con AWS via OIDC (sin claves hardcodeadas) - name: Configure AWS credentials (OIDC) uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: arn:aws:iam::123456789:role/nutripaw-github-actions aws-region: eu-west-1 ## 2) Recuperar secretos de AWS Secrets Manager - name: Retrieve secrets from AWS Secrets Manager run: | DB_PASSWORD=$(aws secretsmanager get-secret-value \ --secret-id nutripaw/prod/db/password \ --query SecretString --output text) STRIPE_KEY=$(aws secretsmanager get-secret-value \ --secret-id nutripaw/prod/stripe/secret \ --query SecretString --output text) OPENAI_KEY=$(aws secretsmanager get-secret-value \ --secret-id nutripaw/prod/openai/key \ --query SecretString --output text) # Enmascarar en logs — OBLIGATORIO echo "::add-mask::$DB_PASSWORD" echo "::add-mask::$STRIPE_KEY" echo "::add-mask::$OPENAI_KEY" # Inyectar como variables de entorno para pasos siguientes echo "NUTRIPAW_DB_PASSWORD=$DB_PASSWORD" >> $GITHUB_ENV echo "NUTRIPAW_STRIPE_SECRET_KEY=$STRIPE_KEY" >> $GITHUB_ENV echo "NUTRIPAW_OPENAI_API_KEY=$OPENAI_KEY" >> $GITHUB_ENV ## 3) Build y push imagen Docker a ECR - name: Build & push Docker image to ECR run: | aws ecr get-login-password | docker login --username AWS \ --password-stdin 123456789.dkr.ecr.eu-west-1.amazonaws.com docker build -t nutripaw-api:${{ github.sha }} . docker push 123456789.dkr.ecr.eu-west-1.amazonaws.com/nutripaw-api:${{ github.sha }} ## 4) Deploy en ECS (los secretos se pasan como Secrets, NO como env vars en la task def) - name: Deploy ECS service run: | aws ecs update-service \ --cluster nutripaw-prod \ --service nutripaw-api \ --force-new-deployment
name: Deploy NutriPaw — Staging on: push: branches: [develop] permissions: id-token: write contents: read jobs: deploy-staging: runs-on: ubuntu-latest environment: staging # Secretos de staging — distintos a los de prod steps: - uses: actions/checkout@v4 - name: Configure AWS credentials (OIDC — staging role) uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: arn:aws:iam::123456789:role/nutripaw-github-staging aws-region: eu-west-1 - name: Retrieve staging secrets run: | # Staging usa clave Stripe TEST, nunca la clave LIVE STRIPE_TEST=$(aws secretsmanager get-secret-value \ --secret-id nutripaw/staging/stripe/test-secret \ --query SecretString --output text) echo "::add-mask::$STRIPE_TEST" echo "NUTRIPAW_STRIPE_SECRET_KEY=$STRIPE_TEST" >> $GITHUB_ENV - name: Deploy to ECS staging run: | aws ecs update-service \ --cluster nutripaw-staging \ --service nutripaw-api-staging \ --force-new-deployment
#!/bin/bash # NutriPaw — Pre-commit hook: escaneo de secretos con TruffleHog # Instalar: chmod +x .git/hooks/pre-commit echo "[NutriPaw] Escaneando secretos antes del commit..." # Verificar si Docker esta disponible if ! command -v docker &>/dev/null; then echo "[ERROR] Docker no encontrado. Instala Docker para usar TruffleHog." exit 1 fi # Ejecutar TruffleHog solo sobre los archivos staged (no todo el repo) STAGED_FILES=$(git diff --cached --name-only) docker run --rm \ -v "$(pwd):/repo" \ trufflesecurity/trufflehog:3.88 \ git file:///repo \ --since-commit HEAD \ --only-verified \ --fail if [ $? -ne 0 ]; then echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo " COMMIT BLOQUEADO: se detectaron secretos " echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo " Elimina las credenciales del archivo y usa" echo " AWS Secrets Manager o variables de entorno." echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" exit 1 fi echo "[OK] Ningun secreto detectado. Commit permitido." exit 0
import boto3 import json import string import secrets def generate_secure_password(length=32) -> str: """Genera una contrasena criptograficamente segura.""" alphabet = string.ascii_letters + string.digits + "!@#$%^&*()" return "".join(secrets.choice(alphabet) for _ in range(length)) def lambda_handler(event, context): """ Lambda para rotacion automatica de la contrasena RDS de NutriPaw. Configurar en AWS Secrets Manager con schedule de 30 dias. """ client = boto3.client('secretsmanager', region_name='eu-west-1') rds_client = boto3.client('rds', region_name='eu-west-1') secret_id = 'nutripaw/prod/db/password' # 1. Obtener secreto actual response = client.get_secret_value(SecretId=secret_id) current = json.loads(response['SecretString']) # 2. Generar nueva contrasena new_password = generate_secure_password() # 3. Actualizar contrasena en RDS (NutriPaw usa PostgreSQL) rds_client.modify_db_instance( DBInstanceIdentifier='nutripaw-prod-postgres', MasterUserPassword=new_password, ApplyImmediately=True ) # 4. Actualizar secreto en AWS Secrets Manager client.put_secret_value( SecretId=secret_id, SecretString=json.dumps({ 'username': current['username'], 'password': new_password, 'host': current['host'], 'port': current['port'], 'dbname': current['dbname'], 'rotated_at': str(context.aws_request_id) }) ) return {'statusCode': 200, 'body': 'Rotacion completada con exito'}
- ✓Inventario completo de todos los secretos del proyecto
- ✎Rotar inmediatamente las credenciales del commit a3f9b12
- ✎Crear secretos en AWS Secrets Manager (5 paths)
- ✎Configurar OIDC entre GitHub Actions y AWS IAM (sin claves estaticas)
- ✎Instalar pre-commit hook TruffleHog en todos los dev machines
- ✎Configurar Lambda de rotacion RDS cada 30 dias
- ✎Habilitar audit logging en AWS CloudTrail para accesos a Secrets Manager
- ✎Revisar historial git con BFG Repo Cleaner para purgar .env del pasado
- ✎Separar secretos por entorno: staging nunca usa claves live
- ✓Documentar ubicacion de cada secreto y responsable de rotacion
Dia 1 — Rotacion de emergencia
Rotar NUTRIPAW_DB_PASSWORD y STRIPE_SECRET_KEY expuestos en el historial git.
Dias 2-3 — Setup AWS Secrets Manager
Crear los 5 paths, configurar politicas IAM con least-privilege, habilitar CloudTrail.
Dias 4-5 — Pipelines GitHub Actions
Migrar pipelines a OIDC + AWS Secrets Manager. Configurar entornos staging y production con aprobacion manual.
Dia 6 — Pre-commit TruffleHog
Instalar hook en repositorio y en todas las maquinas del equipo. Verificar con git commit de prueba.
Dia 7 — Rotacion automatica Lambda
Deploy Lambda de rotacion RDS, configurar schedule de 30 dias, test en staging primero.