Reading/Writing Secrets within Terraform
When writing Terraform configurations for resources such as managed databases, compute instance key pairs, TLS certificates, etc., you generate sensitive information such as database passwords, private keys, API keys etc. These secrets need to be managed securely and it is recommended to store this sensitive information in HashiCorp Vault. Any future references to these secrets can be fetched from Vault.
Consider the example of an SSH keypair. In the code below, a key pair generated randomly is stored in Vault and also used while provisioning an AWS instance. Future references to this private key can then be fetched from Vault and used.
# Generate SSH Key Pair
resource "tls_private_key" "example" {
algorithm = "RSA"
rsa_bits = 4096
}
# Store SSH Key Pair in Vault
resource "vault_kv_secret_v2" "ssh_keys" {
path = var.ssh-key-path
data_json = jsonencode({
private_key = tls_private_key.example.private_key_pem
public_key = tls_private_key.example.public_key_openssh
})
}
# Create AWS Key Pair
resource "aws_key_pair" "example" {
key_name = var.aws-ssh-key-name
public_key = tls_private_key.example.public_key_openssh
}
# Create AWS Compute Instance using the SSH Key Pair
resource "aws_instance" "example" {
ami = "ami-0c55b159cbfafe1f0" # Example AMI ID for Amazon Linux 2 in us-west-2 region
instance_type = "t2.micro"
key_name = aws_key_pair.example.key_name
tags = {
Name = "example-instance"
}
}
Taking this pattern a step further, we can look to integrate some of these secrets and rotate them with HashiCorp Vault. Consider the scenario of a Google Cloud SQL instance. When a Cloud SQL for MSSQL(opens in new tab) is created using Terraform, you must pass a root_password parameter. Usually, this root password is randomly generated within the Terraform code itself and passed to the google_sql_database_instance Terraform resource.
HashiCorp Vault has the MSSQL Database secrets engine(opens in new tab), which can be used to generate dynamic username and password combinations bound by TTLs and leases. Once the google_sql_database_instance resource is created, a database secrets engine for the same can be created in Vault along with multiple roles for each kind of database user (eg: administrator, write, read etc on specific tables and schemas). Additionally, the root credentials can be rotated (opens in new tab) and the password created earlier can no longer be used. Whenever a new user has to log in to the database, they can generate dynamic credentials(opens in new tab) with TTL according to their role and use that to log in to the database. This pattern can further be refined using HashiCorp Boundary(opens in new tab) for securing access to your MSSQL database(opens in new tab).
Note
This pattern means that only Vault has access to the root password of the database and the root password can no longer be retrieved by a normal user. It may be preferable to store the root password rather in the KV store of Vault and create a secondary user dedicated to Vault for managing the database users.