Safely rotate secrets with terraform
Rotating secrets is a Good Thingâ„¢ as it limits the length of a time a compromised set of credentials can be used for.
It's quite difficult to make secret rotation atomic i.e. changing a secret in your identity provider at exactly the same time you change the secret in the system that uses it for authentication. Mismatches between the values will result in authentication failures.
The ideal is where the identity provider supports multiple valid secrets for a single identity e.g. Azure Service Principals. If that's the case, you can have 2 secrets active at the same time and rotate them on offset time periods e.g.:
info
This example uses secrets that expire after 60 days and rotates them each month. The mechanism supports rotating secrets more frequently so pick an expiry window that meets your risk appetite. The limiting factor is often when infrastructure needs to be redeployed after a secret is rotated.
In the terraform below, I've set up 2 passwords, one called even
and one called odd
.
The odd
password rotates at the beginning of the odd months and is the current password for those months i.e.:
- January, March, May, July, September, November
And the even
password rotates at the beginning of the even months and is the current password for those months i.e.:
- February, April, June, August, October, December
And now for the terraform:
variable "date" { type = string}
locals { date = tonumber(var.date) odd_keeper = floor((local.date + 1) / 2) even_keeper = floor(local.date / 2) use_even = local.date % 2 == 0}
resource "random_password" "odd" { keepers = { "date" = local.odd_keeper } length = 64 special = true}
resource "random_password" "even" { keepers = { "date" = local.even_keeper } length = 64 special = true}
# this example just outputs the password# but you'd typically use this as a property of# the system(s) that need the password.output "current_secret" { value = local.use_even ? random_password.even.result : random_password.odd.result}
For this to work, you need to supply a date
variable when you call terraform that contains the current year and month e.g.:
terraform apply -auto-approve -var="date=`date +%Y%m`"
caution
Terraform will store these secrets in terraform state, so make sure you're using a backend that is appropriately secured.