Introductie
In de wereld van modern infrastructuurbeheer blijft het omgaan met secrets en het roteren ervan een cruciaal maar uitdagend onderdeel van het beveiligen van systemen. Wachtwoordrotatie is een security best practice die vaak wordt verwaarloosd door de benodigde handmatige inspanning of complexiteit. Veel organisaties worstelen met het implementeren van robuuste rotatiebeleid zonder services te verstoren of extra operationele overhead te creëren. Gelukkig maakt Terraform een veilige en volledig geautomatiseerde aanpak voor secret rotation mogelijk, die we hier verder toelichten.
De oplossing
Stel je deze veelvoorkomende uitdaging voor: je moet een principal aanmaken met een automatisch geprovisioneerd wachtwoord dat periodiek roteert. Hieronder zie je een elegante oplossing voor dit probleem:
# main.tf
locals {
users = {
"user1" = {
name = "user1"
password_rotation = true
}
}
}
resource "time_rotating" "this" {
for_each = local.users
rotation_minutes = var.rotation_minutes
}
resource "random_password" "this" {
for_each = local.users
length = var.password_length
override_special = var.password_override_special
min_upper = var.password_min_upper
min_numeric = var.password_min_numeric
min_lower = var.password_min_lower
min_special = var.password_min_special
keepers = {
rotation_trigger = lookup(local.users[each.key], "password_rotation", true) ? time_rotating.this[each.key].id : null
}
depends_on = [
time_rotating.this
]
}
Copy code
Uitleg
De belangrijkste aandachtspunten van deze oplossing zijn:
- De time_rotating resource
- De random_password resource
- Het instellen van de time_rotating resource als keeper op de random_password resource wanneer wachtwoorden moeten roteren, anders wordt de keeper op null gezet
- Een variabele die de rotatiefrequentie bepaalt (var.rotation_minutes)
- Variabelen die de wachtwoordcomplexiteit bepalen (var.password_*)
De time_rotating resource is in essentie een UTC-timestamp die wordt bijgewerkt naar de huidige tijd zodra het aantal minuten, gelijk aan var.rotation_minutes, is verstreken sinds de vorige timestamp. De random_password resource genereert een wachtwoord bij de eerste Terraform apply en slaat dit op in de state. Dit gebeurt slechts één keer. Met zogeheten keepers kun je het opnieuw aanmaken van het wachtwoord aansturen.
Keepers zijn variabelen die je instelt op de random_password resource om de recreatie van de onderliggende resource te bepalen. Je kunt meerdere keepers meegeven en zodra één van deze waarden verandert, wordt het wachtwoord opnieuw gegenereerd. In het bovenstaande voorbeeld geven we één keeper mee: de timestamp van de time_rotating resource als password_rotation is ingeschakeld, anders null. Dit betekent dat telkens wanneer de time_rotating resource wordt bijgewerkt, ook de keeper van de random_password verandert en het wachtwoord dus roteert.
De oplossing toepassen
Met var.rotation_minutes ingesteld op 1 en een lijst met één gebruiker genaamd user1, ziet een eerste Terraform apply er als volgt uit (let op datum en tijd):
# date; tf apply -auto-approve
Fri Jun 27 09:16:00 AM UTC 2025
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# random_password.this["user1"] will be created
+ resource "random_password" "this" {
+ bcrypt_hash = (sensitive value)
+ id = (known after apply)
+ keepers = {
+ "rotation_trigger" = (known after apply)
}
+ length = 24
+ lower = true
+ min_lower = 1
+ min_numeric = 1
+ min_special = 1
+ min_upper = 1
+ number = true
+ numeric = true
+ override_special = "_-"
+ result = (sensitive value)
+ special = true
+ upper = true
}
# time_rotating.this["user1"] will be created
+ resource "time_rotating" "this" {
+ day = (known after apply)
+ hour = (known after apply)
+ id = (known after apply)
+ minute = (known after apply)
+ month = (known after apply)
+ rfc3339 = (known after apply)
+ rotation_minutes = 1
+ rotation_rfc3339 = (known after apply)
+ second = (known after apply)
+ unix = (known after apply)
+ year = (known after apply)
}
Plan: 2 to add, 0 to change, 0 to destroy.
time_rotating.this["user1"]: Creating...
time_rotating.this["user1"]: Creation complete after 0s [id=2025-06-27T09:16:01Z]
random_password.this["user1"]: Creating...
random_password.this["user1"]: Creation complete after 0s [id=none]
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
Copy code
Wanneer je zeven seconden later opnieuw een Terraform apply uitvoert, worden er geen wijzigingen doorgevoerd:
# date; tf apply -auto-approve
Fri Jun 27 09:16:07 AM UTC 2025
time_rotating.this["user1"]: Refreshing state... [id=2025-06-27T09:16:01Z]
random_password.this["user1"]: Refreshing state... [id=none]
No changes. Your infrastructure matches the configuration.
Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Copy code
Tot slot, wanneer er één minuut (var.rotation_minutes) is verstreken en je opnieuw een apply uitvoert, zie je dat het wachtwoord wordt bijgewerkt:
# date; tf apply -auto-approve
Fri Jun 27 09:17:01 AM UTC 2025
time_rotating.this["user1"]: Refreshing state... [id=2025-06-27T09:16:01Z]
random_password.this["user1"]: Refreshing state... [id=none]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
-/+ destroy and then create replacement
Terraform will perform the following actions:
# random_password.this["user1"] must be replaced
-/+ resource "random_password" "this" {
~ bcrypt_hash = (sensitive value)
~ id = "none" -> (known after apply)
~ keepers = { # forces replacement
~ "rotation_trigger" = "2025-06-27T09:16:01Z" -> (known after apply)
}
~ result = (sensitive value)
# (11 unchanged attributes hidden)
}
# time_rotating.this["user1"] will be created
+ resource "time_rotating" "this" {
+ day = (known after apply)
+ hour = (known after apply)
+ id = (known after apply)
+ minute = (known after apply)
+ month = (known after apply)
+ rfc3339 = (known after apply)
+ rotation_minutes = 1
+ rotation_rfc3339 = (known after apply)
+ second = (known after apply)
+ unix = (known after apply)
+ year = (known after apply)
}
Plan: 2 to add, 0 to change, 1 to destroy.
random_password.this["user1"]: Destroying... [id=none]
random_password.this["user1"]: Destruction complete after 0s
time_rotating.this["user1"]: Creating...
time_rotating.this["user1"]: Creation complete after 0s [id=2025-06-27T09:17:02Z]
random_password.this["user1"]: Creating...
random_password.this["user1"]: Creation complete after 0s [id=none]
Apply complete! Resources: 2 added, 0 changed, 1 destroyed.
Copy code
De laatste stap om dit volledig te automatiseren is het opnemen in een geplande CI/CD-pipeline die periodiek draait. Zorg ervoor dat je het schema van de pipeline afstemt op de ingestelde var.rotation_minutes.
Samenvatting
Zo implementeer je geautomatiseerde secret rotation met Terraform en voeg je direct praktische waarde toe aan je infrastructuurbeheer. Door handmatige secret rotation te elimineren, verklein je zowel de kans op menselijke fouten als de operationele last voor je team. Deze aanpak schaalt moeiteloos mee met je infrastructuur, of je nu een handvol systemen beheert of duizenden resources over meerdere omgevingen.
Het hier getoonde patroon is eenvoudig aan te passen voor verschillende typen credentials en te integreren in je bestaande CI/CD-pipelines, zodat je binnen de hele organisatie een consistente aanpak hanteert.
Ben je benieuwd hoe je dit kunt toepassen op downstream resources, zoals Linux-gebruikers, Active Directory-gebruikers of secret engines zoals HashiCorp Vault? Of wil je zien hoe je dit integreert in een CI/CD-pipeline? Neem gerust contact met ons op voor een gesprek.