To encrypt a given secret for use in Terraform, you can use either the google_kms_secret or the google_kms_secret_asymmetric. As I find the ciphertext for google_kms_secret a bit short, I prefer to use google_kms_secret_asymmetric. In this blog I will show you how to use an asymmetric KMS key to deploy secrets using Terraform.
Encrypting a given secret in terraform
To encrypt a given secret in Terraform you perform the following steps:
- create an asymmetric KMS key
- encrypt the secret
- calculate the checksum
- base64 encode the encrypted secret
- use the encrypted secret in terraform
- store the secret in the secret manager
Create an asymmetric KMS key
To create the asymmetric KMS key, use the following Terraform snippet:
resource "google_kms_key_ring" "cicd" {
name = "cicd"
location = "global"
}
resource "google_kms_crypto_key" "terraform" {
name = "terraform"
key_ring = google_kms_key_ring.cicd.id
purpose = "ASYMMETRIC_DECRYPT"
version_template {
algorithm = "RSA_DECRYPT_OAEP_4096_SHA256"
}
}
data "google_kms_crypto_key_version" "terraform" {
crypto_key = google_kms_crypto_key.terraform.id
}
resource "local_file" "public_key" {
filename = "${path.module}/public-key.pem"
content = data.google_kms_crypto_key_version.terraform.public_key[0].pem
}
After this key is created, the public key is stored in the file public-key.pem
.
The nice thing is that you can give the public key to anybody. If
you give the public key to the supplier of the secret, the plain text
secret will never-ever have to be handed over to you.
Encrypt the secret with the public key
To encrypt the secret with the public key, type:
$ echo -n B0FCE1C3-AF9F-4E92-A2E8-18748AB3C591 |
openssl pkeyutl -in -
-encrypt
-pubin
-inkey public-key.pem
-pkeyopt rsa_padding_mode:oaep
-pkeyopt rsa_oaep_md:sha256
-pkeyopt rsa_mgf1_md:sha256
-out my-api-key.enc
The encrypted secret is now in the file my-api-key.enc
and is 512 bytes long!
Calculate the checksum
To ensure that the ciphertext is not tampered with, you can calculate and use the checksum too:
$ go install github.com/binxio/crc32@1.0.0
$ $HOME/go/bin/crc32
-polynomial castagnoli < my-api-key.enc
cbe83625
Base64 encode the encrypted secret
As Terraform does not support binary files, we do a base64 encoding of the secret:
$ openssl base64
-in my-api-key.enc
-out my-api-key.enc.b64
Use the encrypted secret in terraform
Now you can safely include the encrypted secret in your terraform template by using
the google_kms_secret_asymmetric data source:
data "google_kms_secret_asymmetric" "api_key" {
crypto_key_version = data.google_kms_crypto_key_version.terraform.id
crc32 = "cbe83625"
ciphertext = <<EOT
kumghZcadUm6pwraawMQr5amqM98lpSWd35GhUPtlIHK1AAXACI8s5zfh7PS7qGA
v37/mt9xVuLmNv1zdj4uEhvPm52E92d6CCn3HkAosRNmHaQ5x7d3SU5u5kjR5aRh
l3UoPsJCWOpdkJ1e/UcCDFqNfFL297cFUO0MWqW2ya2PIk5U8K8ujziy9sNMKSVi
Mb98+S/EAuGlNbk/KHTyNzCnicjoKNWZPFQipZCTrrxXpy27j5+9RJ+q7T/gAzGu
BWn85bbslMjL8ozjy5XWpBAZuhIjcrBAeSz8Wbahmnh4wcRTBM2sFWp0cW7rzeCk
adE8z6LvrIdz330O2iX8v8H+Q1z0tNVvB07fklvj3h5XjuwVixXSpVEwD9d6uDq7
i+fxQfER2eJvwI1NEzBsyNgJKDeilEz0obJq7ljyFZAbSxDnsog43GoJbg0JVe9s
CqXtk0DdmHgEym+jw1MdKeFVwNPeyghZBF74gGNJ/G1bkkXUlL6kIQ6gr+oA9En0
2hrUb4Nd+vECMby7r0mqtpkMA/7Fxq49CFLqfY3hSlMkNippruCGu5jArt5QksAa
Tg0XGPOt7oU7T3FjWnMOiab4AR9KpFTT5vCBOBXdssU41jt90lIpPM0kDUPpRPEG
+hvi7FdT9YsLxRTlVA0SFsXMvAt+MSdsAqgRk6BBCE4=
EOT
provider = google-beta
}
Deploy the secret in the secret manager
Finally you can deploy the secret in the secret manager:
resource "google_secret_manager_secret" "api_key" {
secret_id = "api-key"
replication {
automatic = true
}
}
resource "google_secret_manager_secret_version" "api_key" {
secret = google_secret_manager_secret.api_key.id
secret_data = data.google_kms_secret_asymmetric.api_key.plaintext
}
After apply the secret, you can access the secret in the secret manager:
$ gcloud secrets versions access latest --secret api-key
Conclusion
With the google_kms_secret_asymmetric data source, you can encrypt a given secret to obtain
a 512 byte long ciphertext which can safely be included in a Terraform template.
The asymmetric key can be used for relatively short secrets up to ~200 bytes.
As the secret will be visible in your Terraform state file, we recommend to avoid the use of given secrets whenever possible. If you do have a given secret to deploy, the asymmetric data source is a good second best.