hashicorp / terraform-provider-vault

Terraform Vault provider
https://www.terraform.io/docs/providers/vault/
Mozilla Public License 2.0
465 stars 544 forks source link

Terraform won't create a multiline secret #307

Open DamaniN opened 5 years ago

DamaniN commented 5 years ago

Terraform Version

terraform -v Terraform v0.11.11

Affected Resource(s)

Terraform Configuration Files

resource "vault_generic_secret" "multiline" {
  path = "secret/multiline"

  data_json = <<EOT
{
  "Private_Key_JSON": "test 
  test"
}
EOT
}

Expected Behavior

A secret with multiple lines should have been created.

Actual Behavior

Secret creation fails with this error message:

Error: vault_generic_secret.gaia-service-account-key: invalid character '\n' in string literal

Steps to Reproduce

  1. terraform plan -out theplan.out

Important Factoids

I'm attempting to create a secret with multiple lines. If there are any carriage returns in the value portion of the key/value pair terraform fails. Creating the same secret in the Vault UI works fine.

lawliet89 commented 5 years ago

JSON does not allow carriage returns in strings. You have to escape them as \n.

resource "vault_generic_secret" "multiline" {
  path = "secret/multiline"

  data_json = <<EOT
{
  "Private_Key_JSON": "test\ntest"
}
EOT
}
HannesBBR commented 5 years ago

Just posting this in case anybody has the same problem:

In our use case we wanted to generate a certificate from Vault PKI, and directly add that to a secret in Vault (with TF). Initially we had the same issue as described above, as e.g. vault_pki_secret_backend_cert.test.certificate returns a multiline string, which causes an error when creating the vault secret.

Solution for this was replacing \n with \\n:

resource "vault_generic_secret" "cert" {                                              
  path = "secret/multiline"                                         

  data_json = <<EOT                                                                            
{                                                                                              
  "certificate": "${replace(vault_pki_secret_backend_cert.test.certificate, "\n", "\\n")}",     
}                                                                                              
EOT                                                                                                                                                                                     
}                                                                                              
AndresPineros commented 4 years ago

I'm getting this issue after using the replace(\n,\n):

Error: invalid character 'r' looking for beginning of value

I'm not sure if my certificate has something else that's breaking the provider. It looks like a regular PEM file.

AndresPineros commented 4 years ago

I had to base64encode it. Not ideal but it works. Decoding base64 is very simple anywhere else where this cert will be consumed.

lawliet89 commented 4 years ago

You can do something like

resource "vault_generic_secret" "cert" {                                              
  path = "secret/multiline"                                         

  data_json = jsonencode({
      certificate = "<CERT>"
    })                                                                                                                                                                                                                                                            
} 
chrw commented 4 years ago

You can do something like

resource "vault_generic_secret" "cert" {                                              
  path = "secret/multiline"                                         

  data_json = jsonencode({
      certificate = "<CERT>"
    })                                                                                                                                                                                                                                                            
} 

This worked for me. Thanks! 👍

mantoniocc commented 3 years ago

Just posting this in case anybody has the same problem:

In our use case we wanted to generate a certificate from Vault PKI, and directly add that to a secret in Vault (with TF). Initially we had the same issue as described above, as e.g. vault_pki_secret_backend_cert.test.certificate returns a multiline string, which causes an error when creating the vault secret.

Solution for this was replacing \n with \\n:

resource "vault_generic_secret" "cert" {                                              
  path = "secret/multiline"                                         

  data_json = <<EOT                                                                            
{                                                                                              
  "certificate": "${replace(vault_pki_secret_backend_cert.test.certificate, "\n", "\\n")}",     
}                                                                                              
EOT                                                                                                                                                                                     
}                                                                                              

This works for me. Thanks a lot.

lgg42 commented 16 hours ago

Just posting this in case anybody has the same problem:

In our use case we wanted to generate a certificate from Vault PKI, and directly add that to a secret in Vault (with TF). Initially we had the same issue as described above, as e.g. vault_pki_secret_backend_cert.test.certificate returns a multiline string, which causes an error when creating the vault secret.

Solution for this was replacing \n with \\n:

resource "vault_generic_secret" "cert" {                                              
  path = "secret/multiline"                                         

  data_json = <<EOT                                                                            
{                                                                                              
  "certificate": "${replace(vault_pki_secret_backend_cert.test.certificate, "\n", "\\n")}",     
}                                                                                              
EOT                                                                                                                                                                                     
}                                                                                              

I love you so hard my man!! you the goat! after a whole day of TF fuckery this is what works for me :face_holding_back_tears: My case: generating a provider.tf block inside a terragrunt.hcl module with a multiline string from a kubernetes certificate. Here's the code for the souls in disgrace:

generate "provider_helm" {
  path      = "provider_helm.tf"
  if_exists = "overwrite"
  contents  = <<-EOF
    provider "helm" {
      kubernetes {
        host                   = "${dependency.eks.outputs.cluster_endpoint}"
        cluster_ca_certificate = "${replace(base64decode(dependency.eks.outputs.cluster_certificate_authority_data), "\n", "\\n")}"
        exec {
          api_version = "client.authentication.k8s.io/v1beta1"
          args        = ["eks", "get-token", "--cluster-name", "${dependency.eks.outputs.cluster_name}"]
          command     = "aws"
        }
      }
    }
  EOF
}