Terraform-provider-kubernetes: --from-env-file Implementation to kubernetes_secret resource

Created on 17 Jun 2020  路  6Comments  路  Source: hashicorp/terraform-provider-kubernetes

Description

I want to be able to use kubectl functionality when creating a secret with flag --from-env-file what does this do is to iterate over the input file and line by line (Code) split the = from the line (Code) so you can have the key-value pair and use those values as the data map[string][]byte.

Potential Terraform Configuration

Code in resource_kubernetes_secret.go should be modify so now it can accept an env-file field.

Schema: map[string]*schema.Schema{
    "metadata": namespacedMetadataSchema("secret", true),
    "data": {
        Type:        schema.TypeMap,
        Description: "A map of the secret data.",
        Optional:    true,
        Sensitive:   true,
    },
    "type": {
        Type:        schema.TypeString,
        Description: "Type of secret",
        Default:     "Opaque",
        Optional:    true,
        ForceNew:    true,
    },
    "from_env_file": {
        Type:        schema.TypeMap,
        Description: "Path to a file to read lines of key=val pairs to create a secret.",
        Optional:    true,
        Sensitive:   true,
    }
}

So then we can use:

resource "kubernetes_secret" "foo-env" {
  metadata {
    name = "foo-env"
  }
  from_env_file = {
    "foo-env" = "${file("foo.env")}"
  }
}

References

I did study how kubectl does this solution and I might be able to apply that in Terraform, the process in kubectl is:

Input foo.env:

TEST=teststring
NODE_ENV=development
kubectl create secret generic foo-env --from-env-file=foo.env

Then -> create_secret.go Complete() -> secret.go StructuredGenerate() -> secret.go handleFromEnvFileSource() -> env_file.go addFromEnvFile() -> env_file.go proccessEnvFileLine() -> secret.go addKeyFromLiteralToSecret()

Output Kubernetes secret object created with flag --from-env-file:

apiVersion: v1
data:
  TEST: base64string
  NODE_ENV: base64string
kind: Secret
metadata:
  name: foo-env
  namespace: default
type: Opaque

Community Note

  • Please vote on this issue by adding a 馃憤 reaction to the original issue to help the community and maintainers prioritize this request
  • If you are interested in working on this issue or have submitted a pull request, please leave a comment
acknowledged enhancement help wanted sizM themcoverage

Most helpful comment

Thanks for opening this @albertorm95 this is an interesting issue, and I think there are a few paths forward here:

  1. It's possible to do this purely with Terraform's built-in functions, as the data field of secret is of type map:
resource "kubernetes_secret" "test" {
  metadata {
    name = "test"
  }

  data = {
    for line in compact(split("\n", file("vars.env"))):
      split("=",line)[0] => split("=",line)[1]
  }
}

This will work for now, but it's pretty ugly and will lead to copypasta if you use this a lot. This approach also has a few gotaches, i.e if the values in your dotenv contain = or spread across multiple lines.

  1. Like you suggested, we could add support for this in the provider by adding a from_env_file attribute that will parse the env file format for us. We're open to accepting a PR that implements this feature so we can do something like this:
from_env_file = file("vars.env")

We will have to add this to both ConfigMap and Secret.

  1. Adding envdecode() to Terraform's set of functions for encoding/decoding files. This would mean we could do something like this:
data = envdecode(file("path.env"))

This feels like the most reusable way to enable this sort of behaviour, but for this we would have to open a PR against Terraform's core repo.

All 6 comments

Thanks for opening this @albertorm95 this is an interesting issue, and I think there are a few paths forward here:

  1. It's possible to do this purely with Terraform's built-in functions, as the data field of secret is of type map:
resource "kubernetes_secret" "test" {
  metadata {
    name = "test"
  }

  data = {
    for line in compact(split("\n", file("vars.env"))):
      split("=",line)[0] => split("=",line)[1]
  }
}

This will work for now, but it's pretty ugly and will lead to copypasta if you use this a lot. This approach also has a few gotaches, i.e if the values in your dotenv contain = or spread across multiple lines.

  1. Like you suggested, we could add support for this in the provider by adding a from_env_file attribute that will parse the env file format for us. We're open to accepting a PR that implements this feature so we can do something like this:
from_env_file = file("vars.env")

We will have to add this to both ConfigMap and Secret.

  1. Adding envdecode() to Terraform's set of functions for encoding/decoding files. This would mean we could do something like this:
data = envdecode(file("path.env"))

This feels like the most reusable way to enable this sort of behaviour, but for this we would have to open a PR against Terraform's core repo.

Ok, so let me then create an Issue in the core repo in order te add the envdecode() function to Terraform's set of functions for encoding/decoding files.

So once thats done I could use it to resolve this issue!

So once thats done I could use it to resolve this issue!

It takes a fair bit of time to get something into Terraform core (if they are willing to accept it) so I am happy to help add this to this provider in the mean time.

Looks like there is already an open issue about this on the main Terraform repo, see here: https://github.com/hashicorp/terraform/issues/23906

Any progress toward this? I've got the for loop in my terraform files but would be nice to simplify that!

I would be interested in that feature as well.

Was this page helpful?
0 / 5 - 0 ratings