Este módulo facilita la creación y gestión de secretos en AWS Secrets Manager con todas las mejores prácticas de seguridad, nomenclatura y configuración según los estándares. Permite crear secretos con cifrado obligatorio, políticas de acceso personalizadas y soporte para replicación entre regiones.
Consulta CHANGELOG.md para la lista de cambios de cada versión. Recomendamos encarecidamente que en tu código fijes la versión exacta que estás utilizando para que tu infraestructura permanezca estable y actualices las versiones de manera sistemática para evitar sorpresas.
- ✅ Creación de múltiples secretos usando mapas de objetos
- ✅ Opción para crear solo la estructura del secreto sin contenido sensible
- ✅ Soporte para secretos en formato JSON o texto plano (opcional)
- ✅ Cifrado obligatorio mediante AWS KMS
- ✅ Replicación de secretos entre regiones
- ✅ Políticas de acceso integradas en la configuración del secreto
- ✅ Etiquetado consistente según estándares organizacionales
- ✅ Validaciones de entrada para prevenir configuraciones incorrectas
El módulo cuenta con la siguiente estructura:
cloudops-ref-repo-aws-sm-terraform/
└── sample/
├── data.tf
├── main.tf
├── outputs.tf
├── providers.tf
├── terraform.auto.tfvars
└── variables.tf
├── .gitignore
├── CHANGELOG.md
├── data.tf
├── main.tf
├── outputs.tf
├── README.md
├── variables.tf
- Los archivos principales del módulo (
data.tf
,main.tf
,outputs.tf
,variables.tf
) se encuentran en el directorio raíz. CHANGELOG.md
yREADME.md
también están en el directorio raíz para fácil acceso.- La carpeta
sample/
contiene un ejemplo de implementación del módulo.
Este módulo requiere la configuración de un provider específico para el proyecto. Debe configurarse de la siguiente manera:
# sample/providers.tf
provider "aws" {
alias = "principal"
region = var.aws_region
profile = var.profile
default_tags {
tags = var.common_tags
}
}
# sample/main.tf
module "secrets_manager" {
source = "../"
providers = {
aws.project = aws.principal
}
# ... resto de la configuración
}
module "secrets_manager" {
source = "ruta/al/modulo"
providers = {
aws.project = aws.principal
}
# Common configuration
client = "pragma"
project = "idp"
environment = "dev"
additional_tags = {
backup-policy = "none"
service-tier = "standard"
}
# Configuración de secretos
secrets_config = {
# Secreto básico sin replicación
"db-credentials" = {
description = "Credenciales de base de datos"
kms_key_id = "alias/aws/secretsmanager"
create_secret_version = false
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:root"
},
"Action": [
"secretsmanager:GetSecretValue",
"secretsmanager:DescribeSecret"
],
"Resource": "*"
}
]
}
EOF
additional_tags = {
application = "database"
data-classification = "confidential"
}
},
# Secreto con replicación en múltiples regiones
"multi-region-secret" = {
description = "Secreto replicado en múltiples regiones"
kms_key_id = "alias/aws/secretsmanager"
replica = [
{
region = "us-west-2"
kms_key_id = "alias/aws/secretsmanager"
},
{
region = "eu-west-1"
kms_key_id = "alias/aws/secretsmanager"
}
]
create_secret_version = false
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:root"
},
"Action": [
"secretsmanager:GetSecretValue",
"secretsmanager:DescribeSecret"
],
"Resource": "*"
}
]
}
EOF
additional_tags = {
application = "global-app"
replication = "multi-region"
}
}
}
}
El módulo sigue un estándar de nomenclatura para los secretos:
{client}/{project}/{environment}/secret/{secret_name}
Por ejemplo:
pragma/idp/dev/secret/db-credentials
pragma/payments/prod/secret/api-keys
El módulo maneja el etiquetado de la siguiente manera:
-
Etiquetas obligatorias: Se aplican a través del provider AWS usando
default_tags
en la configuración del provider.provider "aws" { default_tags { tags = { environment = "dev" project-name = "idp" cost-center = "cloud-ops" owner = "cloudops" area = "infrastructure" provisioned = "terraform" datatype = "operational" } } }
-
Etiqueta Name: Se genera automáticamente siguiendo el estándar de nomenclatura para cada secreto.
-
Etiquetas adicionales por recurso: Se pueden especificar etiquetas adicionales para cada secreto individualmente mediante el atributo
additional_tags
en la configuración de cada secreto.
Nota importante: Este módulo no incluye la creación de alarmas CloudWatch. Para monitorear y auditar el acceso a los secretos, se recomienda:
Configurar AWS CloudTrail: Las operaciones de Secrets Manager se registran automáticamente en CloudTrail, lo que permite auditar quién accedió a qué secretos y cuándo.
Implementar un módulo de CloudWatch separado: Para crear alarmas y métricas personalizadas que monitoreen el acceso a los secretos.
Habilitar AWS Config: Para evaluar continuamente la configuración de los secretos y asegurar el cumplimiento de las políticas de seguridad.
Name | Version |
---|---|
terraform | >= 1.0.0 |
aws | >= 4.31.0 |
Name | Version |
---|---|
aws.project | >= 4.31.0 |
Name | Type |
---|---|
aws_secretsmanager_secret | resource |
aws_secretsmanager_secret_version | resource (opcional) |
aws_secretsmanager_secret_policy | resource (opcional) |
Name | Description | Type | Default | Required |
---|---|---|---|---|
client | Identificador del cliente | string |
n/a | yes |
project | Nombre del proyecto o aplicación que utilizará el secreto | string |
n/a | yes |
environment | Entorno de despliegue (dev, qa, pdn) | string |
n/a | yes |
additional_tags | Etiquetas adicionales para los recursos que no son secretos | map(string) |
{} |
no |
secrets_config | Configuración de secretos en AWS Secrets Manager | map(object) |
n/a | yes |
variable "secrets_config" {
type = map(object({
description = string
kms_key_id = string # Obligatorio para garantizar el cifrado
recovery_window_in_days = optional(number, 7)
force_overwrite_replica_secret = optional(bool, true)
replica = optional(list(object({
region = string
kms_key_id = string
})), [])
# Campos opcionales para el contenido del secreto
secret_json = optional(map(string))
secret_text = optional(string)
# Flag para controlar si se crea la versión del secreto
create_secret_version = optional(bool, false)
# Política del secreto (opcional)
policy = optional(string)
# Etiquetas adicionales
additional_tags = optional(map(string), {})
}))
}
Name | Description |
---|---|
secret_arns | ARNs de los secretos creados |
secret_names | Nombres de los secretos creados |
secret_versions | IDs de las versiones de los secretos creados (solo para secretos con versión) |
Después de crear la estructura del secreto con create_secret_version = false
, puede agregar el contenido sensible de varias maneras:
- Inicie sesión en la consola de AWS
- Navegue a AWS Secrets Manager
- Seleccione el secreto creado
- Haga clic en "Retrieve secret value" y luego en "Edit"
- Ingrese el valor del secreto y guarde los cambios
# Para secretos en formato JSON
aws secretsmanager put-secret-value \
--secret-id "pragma/idp/dev/secret/db-credentials" \
--secret-string '{"username":"admin","password":"SecurePassword123!","host":"db.example.com","port":"5432"}'
# Para secretos en formato texto
aws secretsmanager put-secret-value \
--secret-id "pragma/idp/dev/secret/api-key" \
--secret-string "api-key-value-here"
- Integre con herramientas de CI/CD como Jenkins, GitHub Actions o AWS CodeBuild
- Utilice AWS Lambda para gestionar los secretos
- Implemente soluciones como HashiCorp Vault para la gestión centralizada de secretos
La replicación de secretos entre regiones es útil para:
- Alta disponibilidad: Asegura que los secretos estén disponibles incluso si una región de AWS falla
- Baja latencia: Permite que las aplicaciones accedan a los secretos desde la región más cercana
- Recuperación ante desastres: Facilita la recuperación en caso de un desastre regional
Para configurar la replicación, use el campo replica
en la configuración del secreto:
replica = [
{
region = "us-west-2"
kms_key_id = "alias/aws/secretsmanager" # KMS key en la región secundaria
},
{
region = "eu-west-1"
kms_key_id = "alias/aws/secretsmanager" # KMS key en la región terciaria
}
]
Notas importantes sobre la replicación:
- Cada región de réplica debe tener su propia KMS key
- Las actualizaciones al secreto se propagan automáticamente a todas las réplicas
- Las políticas de acceso se aplican a todas las réplicas
La rotación automática de secretos es una característica importante para la seguridad, pero requiere una función Lambda específica para cada tipo de secreto. En esta versión del módulo, la rotación automática no está implementada.
En una versión futura, se planea agregar soporte completo para la rotación automática de secretos, incluyendo:
- Módulo complementario para crear funciones Lambda de rotación
- Plantillas para diferentes tipos de secretos (bases de datos, APIs, etc.)
- Integración con servicios de AWS como RDS, Redshift, etc.
Si necesita implementar la rotación de secretos, considere:
- Crear una función Lambda personalizada para la rotación
- Configurar la rotación manualmente a través de la consola de AWS
- Utilizar un módulo separado para la rotación de secretos
- Se requiere utilizar una KMS key para cifrar los secretos (puede ser la clave predeterminada de AWS o una personalizada)
- Configurar políticas de acceso restrictivas siguiendo el principio de privilegio mínimo
- Revisar regularmente los logs de CloudTrail para auditar el acceso a los secretos
- Considerar la replicación de secretos críticos en múltiples regiones para alta disponibilidad
- Nunca almacenar datos sensibles en el código Terraform o en sistemas de control de versiones
- Seguridad: Cifrado en reposo obligatorio con AWS KMS
- Nomenclatura: Estándar {client}/{project}/{environment}/secret/{secret_name}
- Etiquetado: Etiquetas completas según política (environment, project, owner, client) a través de
default_tags
- Modularización: Estructura modular y reutilizable
- Gestión de secretos: Opción para crear secretos sin contenido sensible
Recomendación importante: Para entornos de producción y colaboración en equipo, se recomienda configurar un backend remoto para almacenar el estado de Terraform (tfstate). Esto proporciona:
- Bloqueo de estado para prevenir operaciones concurrentes
- Respaldo y versionado del estado
- Almacenamiento seguro de información sensible
- Colaboración en equipo
Ejemplo de configuración con S3 y DynamoDB:
terraform { backend "s3" { bucket = "pragma-terraform-states" key = "secrets-manager/terraform.tfstate" region = "us-east-1" encrypt = true dynamodb_table = "terraform-locks" } }Asegúrese de que el bucket S3 tenga el versionado habilitado y que la tabla DynamoDB tenga una clave primaria llamada
LockID
.
- Nomenclatura de recursos conforme al estándar
- Etiquetas obligatorias aplicadas a todos los recursos
- Cifrado en reposo obligatorio con KMS
- Políticas de acceso personalizables e integradas
- Opción para crear secretos sin contenido sensible
- Soporte para replicación entre regiones
- Documentación sobre cómo gestionar secretos de forma segura
- Monitoreo y alertas (debe implementarse con el módulo CloudWatch)
- Revisión de seguridad completada
Este módulo ha sido desarrollado siguiendo los estándares de Pragma CloudOps, garantizando una implementación segura, escalable y optimizada que cumple con todas las políticas de la organización. Pragma CloudOps recomienda revisar este código con su equipo de infraestructura antes de implementarlo en producción.