Best way to store Terraform variable values without having them in source control - azure

We have a code repo with our IaC in Terraform. This is in Github, and we're going to pull the code, build it, etc. However, we don't want the values of our variables in Github itself. So this may be a dumb question, but where do we store the values we need for our variables? If my Terraform requires an Azure subscription id, where would I store the subscription id? The vars files won't be in source control. The goal is that we'll be pulling the code into an Azure Devops pipeline so the pipeline will have to know where to go to get the input variable values. I hope that makes sense?

You can store your secrets in Azure Key Vault and retrieve them in Terraform using azurerm_key_vault_secret.
data "azurerm_key_vault_secret" "example" {
name = "secret-sauce"
key_vault_id = data.azurerm_key_vault.existing.id
}
output "secret_value" {
value = data.azurerm_key_vault_secret.example.value
}
https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/key_vault_secret

There has to be a source of truth eventually.
You can store your values in the pipeline definitions as variables themselves and pass them into the Terraform configuration.
Usually it's a combination of tfvar files (dependent on target environment) and some variables from the pipeline. If you do have vars in your pipelines though, the pipelines should be in code.
If the variables are sensitive then you need to connect to a secret management tool to get those variables.
If you have many environments, say 20 environments and the infra is all the same with exception of a single ID you could have the same pipeline definition (normally JSON or YAML) and reference it for the 20 pipelines you build, each of those 20 would have that unique value baked in for use at execution. That var is passed through to Terraform as the missing piece.
There are other key-value property tracking systems out there but Git definitely works well for this purpose.

You can use Azure DevOps Secure files (pipelines -> library) for storing your credentials for each environment. You can create a tfvar file for each environment with all your credentials, upload it as a secure file in Azure DevOps and then download it in the pipeline with a DownloadSecureFile#1 task.

Related

Azure passing secrets without depending on Azure Keyvaults

I am building an Azure ML Pipeline for batch scoring. In one step I need to access a key stored in the workspace's Azure Keyvault.
However, I want to strictly separate the authoring environment (responsible for creating the datasets, building the environment, building and running the pipeline) and the production environment (responsible for transforming data, running the prediction etc.).
Therefore, code in the production environment should be somewhat Azure agnostic. I want to be able to submit my inference script to Google Cloud Compute Instances, if needed.
Thus my question is:
What is the best practise to pass secrets to remote runs without having the remote script retrieve it from the keyvault itself?
Is there a way to have redacted environment variables or command line arguments?
Thanks!
Example of what I would like to happen:
# import all azure dependencies
secret = keyvault.get_secret("my_secret")
pipeline_step = PythonScriptStep(
script_name="step_script.py",
arguments=["--input_data", input_data, "--output_data", output_data],
compute_target=compute,
params=["secret": secret] # This will create an env var on the remote?
)
pipeline = Pipeline(workspace, steps=[pipeline_step])
PipelineEndpoint.publish(...)
An within step_script.py:
# No imports from azureml!
secret = os.getenv("AML_PARAMETER_secret")
do_something(secret)

Terraform Destroy does not work with Azure Devops Variables in terraform.tfvars

I have very simple pipeline, classic pipeline with Terraform Init, Plan and Apply, how ever deployment failed in middle, so I wanted to destroy all resources…
(backend is remote sitting on Azure blob container
so I enabled only Init and Destroy Task in pipeline, In Init parameters I have provided remote backend details, but when I run pipeline with destroy command it says " variable not allowed"
Actually in terraform.tfvars file I have used azure variable group variable substitution like below
and I have destory task like below
error i get is:
"It isn’t possible to define anything other than static values in a .tfvars file.", see Reference environment variables in .tfvars file.
Alternativly, you can rename the environment variables to start with TF_VAR_ prefix, e.g. TF_VAR_resource_group or you can try to pass the values via -var parameter.
I normally recommend against this type of solutions as it's non-canonical; e.g. there are ways to solve the problem, as #sschmeck has posted, so adding a third-party tool can just create more of a headache.
That said, this article details the use a "Replace Tokens" task in Azure DevOps.
Simply put, you can tell this task to scan for *.tfvars files, and have it replace some tokens with a pattern such as __example__, so in your example:
resource_group = __resource_group__
And set the resource_group variable in a Azure DevOps variable group; it will then search for your specified pattern and replace it.
Again, I would say use TF_VARs as it's canonical, but this may also work for you.

How to place folder with terraform files in a docker container and further deploy it to azure

I have my infrastructure as a code folder with distinct terraform files stored on Azure in a storage account on a resource group that is only used for storing state or secrets used for automation.
How can I place the folder in a docker container and further use it so that secrets remain private?
Never put secrets in a docker image. They are easily reversible and aren't treated as secret.
You would normally store your Terraform files (without secrets) in a source repository that has a pipeline attached. The pipeline could have the secrets defined as "secret variables" (different pipeline tools have different terms for the same thing).
For example, say you need to provide a particular API key to talk to a service with Terraform. Often the provider supports an environment variable out for the credential by default (check their docs), in cases where it doesn't you can create a Terraform variable to do so and set the secret on the pipeline as mentioned earlier.
e.g.
In terraform:
variable "key" {
type = "string"
sensitive = true
}
provider "someprovider" {
project = "..."
region = "..."
key = var.key
}
Then in the pipeline you would define something like:
TF_VAR_key=xxxx-xxxx-xxxx-xxxx
Normally within the pipeline tools you can provide variables to the various steps or docker images (such as Terraform image).

Create variable in Azure pipeline to use in a different pipeline

We have separate pipelines for our infrastructure and our application deployments. For our infrastructure, we are using terraform and i know that you can use terraform outputs as variables in later tasks within the same pipeline but is it possible to save the output as a variable in azure so that it can be used in a different pipeline.
We are looking to use this for S3 bucket names to use in the application code and for VPC subnet and SG ids in serverless.
Is this possible to save variables in the pipeline?
There is a variable group in Azure DevOps to share static values across pipelines.
In your case, if you want to save the terraform output as a variable in the variable group, you need to do something e.g. call the REST API dynamically to set the variable in the variable group, then you can use it in another pipeline.
You could also refer to this similar issue.

exclude azure data factory connections and integration runtime from azure devops sync

So we have configured ADF to use GIT under DevOps.
Problem is our connection details are getting synced between dev\qa\master branches which are causing issues as each environment has its own SQL Servers.
Is there any way to keep connections and IR out of sync operation between branches?
Look at this similar post Which also asks how to use parameters for SQL connection information in ADF.
Your solution should also leverage Managed Identities for creating the access policies in the Key Vault this can be done via ARM.
One additional comment would be that the Linked Services would be where the parameter substitutions of these values would occur.
Connections rather have to be parameterized than removed from a deployment pipeline.
Parameterization can be done by using "pipeline" and "variable groups" variables
As an example, a pipeline variable adf-keyvault can be used to point to a rigt KeyVault instance that belongs to a certain environment:
adf-keyvault = "adf-kv-yourProjectName-$(Environment)"
Variable $Environment is declared on a variable groups level, so each environment has own value mapped, for instance:
$Environment = 'dev' #development
$Environment = 'stg' #staging
$Environment = 'prd' #production
Therefore the final value of adf-keyvault, depending on environment, resolves into:
adf-keyvault = "adf-kv-yourProjectName-dev"
adf-keyvault = "adf-kv-yourProjectName-stg"
adf-keyvault = "adf-kv-yourProjectName-prd"
And each Key Vault stores connection string to a database server in secret with the same name across environments. For instance:
adf-sqldb-connectionstring = Server=123.123.123.123;Database=adf-sqldb-dev;User Id=myUsername;Password=myPassword;
Because an initial setup of CI/CD pipelines in Azure Data Factory can be complex in a first glance, I blogged recently a step-by-step guide about this topic: Azure Data Factory & DevOps – Setting-up Continuous Delivery Pipeline

Resources