Aquesta documentació descriu el procediment recomanat per CTTI per a la gestió de secrets i certificats en els principals proveïdors de núvol (AWS, Azure, Google Cloud), tenint en compte les restriccions d’accés i el flux de treball mitjançant Terraform i el sistema d’integració contínua SIC+.
Recomanacions clau
- No emmagatzemar valors sensibles en text pla en variables, fitxers o recursos de Terraform.
- Utilitzar sempre que sigui possible, secrets autogenerats (amb recursos com
random_passwordde Terraform) o les contrasenyes generades automàticament per uns certs serveis de cada proveïdor, per a així controlar el cicle de vida d’aquests des del codi. - Per a secrets que existeixin prèviament, usar la solució CloudOps de l’organització.
Gestió de Secrets amb Terraform
Terraform permet dues estratègies principals per a treballar amb secrets sense exposar-los:
Autogeneració de secrets mitjançant Terraform
Terraform i els seus proveïdors permeten generar valors sensibles automàticament, per exemple contrasenyes, claus i certificats.
Exemple: Generació de contrasenya aleatòria en Terraform
resource "random_password" "db_password" {
length = 16
special = true
override_special = "_%@"
}
Exemple: Pujada del secret autogenerat al servei de secrets del proveïdor Cloud corresponent (AWS en aquest cas)
resource "aws_secretsmanager_secret" "db_secret" {
name = "${var.acronimapp}-${var.entorn}-sm-${var.region_code}-dbsecret-001"
}
resource "aws_secretsmanager_secret_version" "db_secret_value" {
secret_id = aws_secretsmanager_secret.db_secret.id
secret_string = jsonencode({
password = random_password.db_password.result
})
}
Detalls clau:
random_passwordgenera el valor sensible sense exposar-lo en el pla de Terraform.- El valor es guarda automàticament en l’estat de Terraform (
tfstate) de manera segura. - Es puja directament a AWS Secrets Manager, Azure Key Vault o Google Secret Manager segons el proveïdor.
Recursos que generen valors sensibles
Alguns serveis dels diferents hiperescalares generen automàticament claus d’accés, que poden ser referenciades per altres recursos directament i emmagatzemades sense passar cap valor secret en text pla per codi. Aquests valors poden ser recuperats amb Terraform i emmagatzemats de manera segura.
Exemple: API Key generada per servei (Azure Cognitive Services)
resource "azurerm_cognitive_account" "example" {
name = "example-cognitive"
location = "westeurope"
resource_group_name = "rg-app"
kind = "CognitiveServices"
sku_name = "S0"
}
resource "azurerm_key_vault_secret" "cognitive_key" {
name = "cognitive-primary-key"
value = azurerm_cognitive_account.example.primary_access_key
key_vault_aneu = data.azurerm_key_vault.kv.id
}
La clau és generada per Azure i es transfereix directament a Key Vault sense intervenció manual.
Gestió de secrets existents
Per a secrets o certificats preexistents, que no puguin ser generats automàticament, l’organització proporciona una solució CloudOps.
Què és CloudOps?
És un sistema de workflows (Github Actions en SIC+) dissenyat per a executar operacions en el núvol que no poden realitzar-se per consola.
https://canigo.ctti.gencat.cat/plataformes/public_cloud/operacions/cloud-ops_protected/
Entre les múltiples operacions disponibles, es permet la pujada, modificació, o esborrament de secrets i certificats dels diferents proveïdors Cloud.
Totes les operacions són traçables i segures.
Els usuaris poden consultar els valors dels secrets mitjançant accés de lectura en la consola, però no modificar-los directament.
Flux recomanat
- Consultar en la consola els valors existents (si es tracta d’una actualització).
- Executar l’operació desitjada mitjançant CloudOps:
- Pujada de secret o certificat (o re-import d’un certificat existent).
- Esborrament.
- Modificació (específic per a secrets).
- Verificar l’efecte de l’operació en la consola.
Exemple d’ús de CloudOps
Pujar un secret existent a AWS Secrets
Crear una Issue en el repositori de CloudOps corresponent
Seleccionar el Issue Template desitjat
Completar el formulari
Visualitzar el flux d’execució des de la secció de Actions
Comprovar el resultat de la ejecucion des de consola
(S’ofereixen CloudOps equivalents per a secrets i certificats en els 3 principals proveïdors Cloud, en els repositoris corresponents (<codi aplicació>-<acrònim>-cloudops-
Notes:
- Els secrets pujats poden ser consultats per lectura des de la consola.
- La traçabilitat assegura que es registri qui va realitzar l’operació.
Recuperació i consum de secrets i certificats gestionats per CloudOps
Aquest apartat descriu com referenciar des de Terraform secrets i certificats que han estat creats o importats prèviament mitjançant CloudOps, tenint en compte que existeixen dues casuístiques diferenciades:
- Casos en els quals només és necessari referenciar l’identificador del secret o certificat (ARN, ANEU, nom), sense accedir mai al seu valor. Aquest cas és sempre el dels certificats, on només és necessari indicar quin certificat es vol vincular al recurs.
- Casos en els quals és necessari consumir el valor del secret (per exemple, contrasenyes de bases de dades) per a passar-ho com a paràmetre d’entrada a un altre recurs, sense que aquest valor es mostri per pantalla ni s’exposi en logs.
Recuperació de secrets (referència per identificador/ARN)
Exemple: Recuperar el ARN d’un secret existent en AWS perquè ECS pugui obtenir automàticament el valor
data "aws_secretsmanager_secret" "existing_secret" {
name = "my-existing-secret"
}
resource "aws_ecs_task_definition" "example" {
family = "example-task"
container_definitions = jsonencode([
{
name = "app"
image = "my-image"
secrets = [
{
name = "DB_PASSWORD"
valueFrom = "${data.aws_secretsmanager_secret.existing_secret.arn}:db_password::"
}
]
}
])
}
Recuperació del valor d’un secret per a consum per altres recursos
Exemple: Recuperar una clau per a una base de dades en Azure des d’un secret de Key Vault
data "azurerm_key_vault_secret" "db_password" {
name = "db-admin-password"
key_vault_id = data.azurerm_key_vault.kv.id
}
resource "azurerm_mssql_server" "sql_server" {
name = "example-sql-server"
resource_group_name = "rg-db"
location = "westeurope"
administrator_login = "sqladmin"
administrator_login_password = data.azurerm_key_vault_secret.db_password.value
}