.env?
So you have a project which needs environment variables, and now you want
to run it locally. Setting environment variables manually is cumbersome.
Another option is to source a file with those variables, but you will need
to do that for every terminal session, and what if you weren’t using a
terminal in the first place? That’s exacly what .env
files are for. You
create an env files which holds your local test values, and your application
will pick those up when it runs. Pretty hand, right?
Terraform?
Terraform is an infrastructure-as-code tool. You simply define how your infrastructure should look like, use the correct Terraform provider and let it take care of spinning up, updating, and destroying the needed resources. Explaining Terraform itself in details is out of the scope of this post, but you can find tons of posts and tutorials about it.
Both?
Now let’s say that you want to define an Azure Container Group resource but with some secure environment variables. We can do something like this
resource "azurerm_container_group" "example" {
name = "example"
... few other things
container {
... few other things
secure_environment_variables = {
CONNECTION_STRING = "<the connection string>"
}
}
}
We have two problems here:
- the connection string is included in the resource, we’ll have to repeat it for other resources
- the string may contain a username and a password, which is never something we want to check in with our source control
We can easily solve the first one by using variables, but the second isn’t as straightforward. You’d expect Terraform to support something like that out-of-the-box but unfortunately it doesn’t. So I found this solution on Stackoverflow
locals {
dotenv = { for tuple in regexall("(.*)=(.*)", file(".env")) : tuple[0] => tuple[1] }
}
This solution is actually brilliant. It’s pure Terraform, concise, and gets the job done. Actually, kind of gets the job done. If let’s say your variable has “=” anywhere then it’ll take the last ‘=’ as the separator.
However, a very small but non-standard modification can help
locals {
dotenv = { for tuple in regexall("(.*) = (.*)", file(".env")) : tuple[0] => tuple[1] }
}
We just added spaces around the ‘=’ in the regex, and we’ll also need to add spaces around ‘=’, and that just solves it. Keep in mind that it only superficially solves that particular problem. It’s not a general-purpose solution.