Terraform

Guide for adding environment-specific variables in Terraform

Guide: Managing Environment Variables in Terraform

This guide provides an overview of managing environment variables in Terraform, covering two common approaches (using a single environments.auto.tfvars file and separate environment files), as well as an alternative approach with Terraform Workspaces. Additionally, the guide evaluates best practices for selecting the most suitable method based on project complexity and environment isolation requirements.

Method 1: Using a Single environments.auto.tfvars File

In this approach, all environment configurations are defined within a single .tfvars file, named environments.auto.tfvars. This file automatically loads into the Terraform configuration, making it convenient to manage all environment variables in one location.

Step 1: Create environments.auto.tfvars

Example content for environments.auto.tfvars:

environments = {
  development = {
    account_id    = "123456789101112"
    route53_zone  = "development.app.company.com"
    win_ami_name  = "windowsServer-2022-123456"
    rhel_ami_name = "LinuxServer-v8.8-123647"
    instance_config = {
      instance_1 = {
        itype    = "t3.2xlarge"
        vol_size = 100
      }
    }
  }
  preproduction = {
    account_id    = "111245650234"
    route53_zone  = "preproduction.app.company.com"
    win_ami_name  = "windowsServer-2022-123455"
    rhel_ami_name = "LinuxServer-v8.8-123646"
    instance_config = {
      instance_1 = {
        itype    = "t3.2xlarge"
        vol_size = 100
      }
    }
  }
  production = {
    account_id    = "9999354632345"
    route53_zone  = "production.app.company.com"
    win_ami_name  = "windowsServer-2022-123455"
    rhel_ami_name = "LinuxServer-v8.8-123646"
    instance_config = {
      instance_1 = {
        itype    = "t3.4xlarge"
        vol_size = 1000
      }
    }
  }
}

Each environment is created and in this example, we have the account_id which would be something like the AWS account id. The Route53 zone address, a Windows and Linux AMI Name. Then we open up a section for the instance settings.

Step 2: Define the Variables in variables.tf

To accommodate the structure in environments.auto.tfvars, add the following in variables.tf:

variable "environment" {
  type = string
  description = "Used to set the environment"
}

variable "environments" {
  type = map(object({
    account_id    = string
    route53_zone  = string
    win_ami_name  = string
    rhel_ami_name = string
    instance_config = map(object({
      itype    = string
      vol_size = number
    }))
  }))
}

Create a locals.tf file if you don’t have one, and add the whole block of code. If you already have a locals.tf file just copy the config line in to it.

locals {
  config = var.environments[var.environment]

}

Set an environment variable on your machine. In Lunix it will be:-

export environment=development

And Windows, PowerShell, (you will need to close PowerShell and reopen it to see the variable) will be:-

[Environment]::SetEnvironmentVariable("environment", "development", "Machine")

Method 2: Separate Environment Files for Each Environment

In this method, you create a separate .tfvars files for each environment (e.g., development.tfvars, preproduction.tfvars, production.tfvars). This provides isolated files, which improves clarity and reduces risk in production-critical settings.

Alternative Approach: Use Terraform Workspaces

Terraform Workspaces allow you to manage different states for different environments. Workspaces are particularly useful for isolating environment state files (e.g., one state for development, another for production), which can prevent accidental cross-environment contamination.

How to Use Workspaces:

  1. Define Environment-Specific Variables with Workspaces: Use a single terraform.tfvars file to define general variables, and then add environment-specific .tfvars files that load based on the active workspace.
  2. Switch Between Workspaces: Create and switch to new workspaces:
   terraform workspace new development
   terraform apply -var-file="development.tfvars"
  1. Use the Workspace Variable: Access the current workspace name directly in your configuration:
   locals {
     current_env = terraform.workspace
   }

   output "instance_type" {
     value = var.environments[local.current_env].instance_config.instance_1.itype
   }

Comparison of Best Practice Approaches

ApproachUse CaseProsCons
Single environments.auto.tfvarsSimple projects with minimal complexityEasy to manage in a single file, convenient for small teams or low-risk environmentsRisk of accidental changes affecting other environments, less control over isolation
Separate Environment FilesMore complex projects, critical environmentsStronger environment isolation, clearer configuration managementRequires more management, harder to maintain across many environments
Terraform WorkspacesStrict environment isolation requirementsState isolation, automatic environment selectionLimited to isolated environments; not ideal for branching or dynamic environments

Conclusion: Best Practices Recommendation

  • Simple Setups: Using a single environments.auto.tfvars may be sufficient, especially in low-risk environments.
  • Complex Environments: For complex infrastructure or critical environments, separate environment files give better clarity and control.
  • Robust Isolation: If you need robust isolation of state files and have limited environments (e.g., development, staging, production), Terraform workspaces are an effective solution.

Using separate environment files in conjunction with workspaces provides both the clarity of isolated files and the safety of workspace-based state separation, making it a powerful combination for larger projects or multi-team setups.