6.4 KiB
08 - Seguridad y Secretos
Cómo protegemos las contraseñas, llaves y datos sensibles de
proyectosacc.
1. ¿Qué es un "secreto"?
Un secreto es cualquier información que no debe ser pública. En proyectosacc, los secrets incluyen:
- Contraseñas de bases de datos.
- Llaves SSH privadas.
- Tokens de Telegram.
- Credenciales de AWS (
AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY).
💡 Regla de oro: si perder esa información causaría un problema de seguridad, es un secreto.
2. ¿Dónde viven los secrets?
Opción 1: Bitbucket Repository Variables (la más usada)
En Bitbucket Pipelines podemos guardar variables de entorno que los scripts usan sin exponer su valor.
Cómo configurarlas:
- Ve al repositorio en Bitbucket.
- Entra a Repository settings > Pipelines > Repository variables.
- Agrega el nombre y el valor.
- Marca la casilla "Secured" 🔒.
Ventaja: cuando el pipeline corre, las variables secured aparecen como *** en los logs. Nadie puede leerlas.
Opción 2: AWS Secrets Manager
AWS tiene un servicio llamado Secrets Manager que guarda secrets de forma segura y permite rotarlos automáticamente.
Ejemplo de uso en un pipeline de CodeBuild:
env:
secrets-manager:
DB_PASSWORD: "prod/database/password"
Opción 3: AWS Systems Manager Parameter Store
Similar a Secrets Manager, pero más simple y económico. Se usa para guardar configuraciones sensibles.
env:
parameter-store:
DATABASE_URL: "/app/database/url"
Opción 4: Archivo .env (solo local)
En tu computadora personal puedes tener un archivo .env con variables locales. Este archivo NUNCA debe subirse al repositorio.
El archivo .gitignore del proyecto ya debería incluir .env para evitar accidentes.
3. ¿Qué NUNCA poner en el repositorio?
❌ NUNCA hagas esto
# Mal ejemplo en bitbucket-pipelines.yml
- step:
script:
- export DB_PASSWORD="supersecreta123"
- export AWS_SECRET_ACCESS_KEY="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
# Mal ejemplo en Terraform
resource "aws_db_instance" "example" {
password = "mi-contrasena-123"
}
# Mal ejemplo en un script
API_KEY="sk-1234567890abcdef"
✅ SIEMPRE haz esto
# Bien: usa variables de entorno
- step:
script:
- export DB_PASSWORD="$DB_PASSWORD"
# Bien: usa variables de Terraform
resource "aws_db_instance" "example" {
password = var.db_password
}
# Bien: lee desde una variable de entorno
API_KEY="$API_KEY"
4. ¿Cómo rotar las llaves SSH?
Rotar una llave significa crear una nueva y dejar de usar la anterior. Es una buena práctica de seguridad, especialmente si alguien con acceso a la llave privada deja la empresa.
Paso 1: Generar un nuevo par de llaves
ssh-keygen -t ed25519 -b 4096 \
-C "bitbucket.pipeline.ci.cd.proyectosacc.thoth.develop@computocontable.com" \
-f bitbucket_pipeline_ci_cd_TO_proyectosacc_server_thoth_develop
Paso 2: Codificar la llave privada en base64
base64 -i bitbucket_pipeline_ci_cd_TO_proyectosacc_server_thoth_develop | tr -d '\n' > nueva_llave.b64
Paso 3: Actualizar la variable en Bitbucket
- Copia el contenido de
nueva_llave.b64. - Ve a Repository settings > Pipelines > Repository variables.
- Actualiza la variable
PROYECTOSACC_SSH_KEYcon el nuevo valor.
Paso 4: Colocar la llave pública en el servidor
# Copia el contenido del archivo .pub
cat bitbucket_pipeline_ci_cd_TO_proyectosacc_server_thoth_develop.pub
# Conéctate al servidor y agrégala a authorized_keys
ssh ubuntu@<IP_DE_LA_EC2>
sudo su - thoth
nano ~/.ssh/authorized_keys
# Pega la nueva llave pública al final del archivo
> 💡 **Tip**: en un despliegue automatizado con Terraform, esta llave pública se inyecta directamente desde el archivo `user_data`. No hace falta editar `authorized_keys` a mano.
### Paso 5: Probar la conexión
Ejecuta un pipeline de prueba o conéctate manualmente con la nueva llave privada para confirmar que funciona.
### Paso 6: Eliminar la llave anterior
Una vez confirmado que la nueva llave funciona:
1. Borra la llave pública antigua de `~/.ssh/authorized_keys`.
2. Borra la llave privada antigua de tu computadora.
3. Actualiza cualquier otra copia que exista.
---
## 5. Seguridad del frontend en S3 + CloudFront
### Bucket policy para CloudFront (OAI)
El bucket S3 del frontend NO debe ser público. Solo CloudFront puede leer los objetos:
```json
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "AllowCloudFrontOAI",
"Effect": "Allow",
"Principal": {
"CanonicalUser": "<OAI-canonical-user-id>"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::ccsoft-proyectosacc-frontend/*"
}]
}
CORS en S3 (si el frontend llama a la API)
Como el frontend React y la API backend comparten el mismo dominio https://sacc.ccsoft.mx (gracias al behavior /api/* de CloudFront), no hay problema de CORS. Si en el futuro decides mover la API a un subdominio diferente (por ejemplo, api.sacc.ccsoft.mx), ahí sí necesitarás configurar CORS en el backend.
Versionamiento de objetos en S3
Habilita el versionamiento en el bucket del frontend. Así puedes restaurar una versión anterior del sitio si un deploy falla:
aws s3api put-bucket-versioning \
--bucket ccsoft-proyectosacc-frontend \
--versioning-configuration Status=Enabled
6. Checklist de seguridad básica
- El archivo
.envestá en.gitignore. - Ningún archivo del repositorio contiene contraseñas escritas directamente.
- Las variables de Bitbucket están marcadas como Secured.
- La llave privada SSH dedicada para
proyectosaccestá en formato base64 en Bitbucket. - No se usa acceso SSH por contraseña ni herramientas como
sshpass. - El puerto SSH (22) de la EC2 solo está abierto a IPs conocidas.
- La base de datos RDS no es accesible desde internet (solo desde la VPC).
- Los certificados SSL están configurados correctamente en CloudFront (HTTPS obligatorio).
- El bucket S3 del frontend NO es público; solo CloudFront tiene acceso mediante OAI/OAC.
- El versionamiento de objetos está habilitado en el bucket S3 del frontend.
- Se ha programado una rotación de llaves SSH al menos una vez al año.
Anterior: 07-terraform-iac.md
Siguiente: 09-runbook-deploy.md