Search code examples
google-cloud-platformterraformkubernetes-secretsgoogle-secret-manager

terraform create k8s secret from gcp secret


I have managed to achieve the flow of creating sensitive resources in terraform, without revealing what the sensitive details are at any point and therefore won't be stored in plain text in our github repo. I have done this by letting TF create a service account, it's associated SA key, and then creating a GCP secret that references the output from the SA key for example.

I now want to see if there's any way to do the same for some pre-defined database passwords. The flow will be slightly different:

  • Manually create the GCP secret (in secrets manager) which has a value of a list of plain text database passwords which our PGbouncer instance will use (more info later in the flow)
  • I import this using terraform import so terraform state is now aware of this resource even though it was created outside of TF, but the secret version I've just added as secret_data = "" (otherwise putting the plain text password details here defeat the object!)
  • I now want to grab the secret_data from the google_secret_manager_version to add into the kubernetes_secret so it can be used within our GKE cluster.

However, when I run terraform plan, it wants to change the value of my manually created GCP secret

  # google_secret_manager_secret_version.pgbouncer-secret-uat-v1 must be replaced
-/+ resource "google_secret_manager_secret_version" "pgbouncer-secret-uat-v1" {
      ~ create_time  = "2021-08-26T14:42:58.279432Z" -> (known after apply)
      + destroy_time = (known after apply)
      ~ id           = "projects/********/secrets/pgbouncer-secret-uat/versions/1" -> (known after apply)
      ~ name         = "projects/********/secrets/pgbouncer-secret-uat/versions/1" -> (known after apply)
      ~ secret       = "projects/********/secrets/pgbouncer-secret-uat" -> "projects/*******/secrets/pgbouncer-secret-uat" # forces replacement
      - secret_data  = (sensitive value) # forces replacement 

Any ideas how I can get round this? I want to import the google secret version to use in kubernetes but not set the secret_data value in the resource as I don't want it to overwrite what i created manually. Here is the relevant terraform config I'm talking about:

resource "google_secret_manager_secret" "pgbouncer-secret-uat" {
  provider = google-beta

  secret_id = "pgbouncer-secret-uat"

  replication {
    automatic = true
  }

  depends_on = [google_project_service.secretmanager]
}

resource "google_secret_manager_secret_version" "pgbouncer-secret-uat-v1" {
  provider = google-beta

  secret      = google_secret_manager_secret.pgbouncer-secret-uat.id
  secret_data = ""
}

Solution

  • If you just want to retrieve/READ the secret without actively managing it, then you can use the associated data instead:

    data "google_secret_manager_secret_version" "pgbouncer-secret-uat-v1" {
      provider = google-beta
      
      secret = google_secret_manager_secret.pgbouncer-secret-uat.id
    }
    

    You can then use the value in your Kubernetes cluster as a secret with the data's exported resource attribute: data.google_secret_manager_secret_version.pgbouncer-secret-uat-v1.secret_data. Note that the provider will likely mark this exported resource attribute as sensitive, and that carries the normal consequences with it.

    You can also check the full documentation for more information.

    Additionally, since you imported the resource into your state to manage it within your Terraform config, you will need to remove it from your state concurrently with removing it from your config. You can do that most easily with terraform state rm google_secret_manager_secret_version.pgbouncer-secret-uat-v1. Then you may safely remove the resource from your config and solely include the data in your config.