Terraform Cloud with multiple environments

By Andreas Spak
Published on 2021-09-26 (Last modified: 2023-08-07)

...

Terraform is a great tool for providing consistent workflows and integrity when provisioning infrastructure. For many use cases, running Terraform CLI or from SVN is a perfect solution, keeping the state file either locally or in a remote storage such as S3, with all team members having access to the state file. However, in more complex architectures, with multiple teams with multiple access levels, and multiple Terraform workspaces, controlling access to state and workspaces can be a difficult task. Hashicorp's managed service Terraform Cloud is a tool to help solve many of the issues that comes with running Terraform in more complex scenarios, such as multi-team, multi-environment with more complex access control. In this article we will introduce how to set up Terraform Cloud for a multi-environment architecture, i.e. with environments dev, stage and prod in separate AWS accounts.

 

The use case

To try it out, let's provision an S3 bucket to three AWS accounts, one for each environment, using the Terraform Cloud API. You will also need to create three Terraform Cloud accounts, one for each environment, i.e. dev, stage and prod. Encapsulating your environments by using one AWS cloud account for each environment, is good practice that I strongly recommend you follow, for all your projects. Create an IAM user in each account. This user could have admin privileges but I recommend to narrow privileges down to minimum requirements for what this user will need in order to provision our infrastructure. You also need to create AWS access key and secret for this user. Make sure to save keys and secrets, because you will need them later when we configure the Terraform Cloud workspaces.

 

Create Terraform Cloud workspaces

Let's start with the workspaces we need. For larger projects, you need to pay close attention to your workspace architecture, because much of the value from running Terraform Cloud comes from how you structure your workspaces. In this article however, we are going to keep it simple, and create one workspace per environment. 

For workflow, choose CLI-driven workflow. This type of workflow will make it possible for us to trigger plan and apply directly from a terminal, just as you would when running Terraform locally. You can read more about the different Terraform Cloud workflows if you want to dig a little deeper. The CLI workflow can also be used when automating, using tools such as Gitlab runner etc.

 

Next, name your environment. Call them what you want, but it is important to suffix these workspaces with -dev, -stage and -prod, like so:

  • myapp-dev
  • myapp-stage
  • myapp-prod

This will make it possible to select our target workspace based on a workspace name and a suffix, using the Terraform cli workspace command. 

 

 

Go ahead and click Create workspace. The next screen will output a snippet of Terraform code, which will be used for our backend configuration. However, since this is a multi-environment project we will make some slight changes to this code.

 

Configure your Terraform workspaces

When your workspace has been created we need to add some minimum configuration, in order to be able to use it to provision infrastructure to our AWS accounts. 

Navigate to Variables and add AWS_SECRET_ACCESS_KEY and AWS_ACCESS_KEY under Environment Variables, with the values you got when creating your IAM user in AWS, for the corresponding environment (dev in this case). Remember to mark the secret as sensitive by checking the checkbox on the right. 

The option to configure your provisioning directly in Terraform Cloud is a really neat feature in my opinion, which saves the work of handling secrets using other tools, outside of the provisioning workflow.

In addition, we also add the variable ENV with the value "dev" (for the dev environment), as a Terraform variable. Adding variables under Terraform Variables is equal to setting variables in the terraform.tfvars file.

 

There are a lot more you can configure when creating a workspace in Terraform Cloud, but we will keep it as simple as possible for now. So far we have created and configured one workspace, for our dev environment. You need to repeat this process for your stage and prod environments.

You should now have 3 AWS accounts (dev, stage and prod) and 3 corresponding Terraform workspaces, named with a suffix of -dev, -stage and -prod (this is important as I mentioned earlier).

 

The Terraform code

At this point, we are going to create some Terraform code, in order to have something to provision. Using your favourite code editor, create the following files:

config.tf

The remote configuration file. Note the "prefix" property in the workspaces block. Add the value of your Terraform workspace prefix.

terraform {
  backend "remote" {
    organization = "<your organization>"

    workspaces {
      prefix = "myapp-"
    }
  }
}

 

provider.tf

Since Terraform has APIs for multiple cloud providers, we need to specify that we want to use AWS. Required property is region, which must correspond with your AWS region.

provider "aws" {
  region = <aws region>
}

s3.tf

Create an S3 bucket with private access. 

resource "aws_s3_bucket" "myapp-bucket" {
  bucket = "myapp-bucket"
  acl    = "private"

  tags = {
    Name        = "myapp-bucket"
    Environment = "dev"
  }
}

 

Run your Terraform code

When these files are in place, let's head over to our terminal. It is important that you have installed Terraform CLI on your machine. To be able to handle multiple Terraform versions I recommend you to checkout the tool tfswitch. You can verify your Terraform version by running (in your terminal).

$ terraform version


In your project folder, let's initialize your Terraform project.

$ terraform init

 

The output from this command should look like this. Terraform CLI has detected multiple workspaces with the same prefix, and is giving us the choice of selecting which one we want to use for provisioning. Go ahead and select "1" and press enter.

 

This will select the "dev" workspace, as defined in your remote configuration. When Terraform has completed the initialization successfully, you can run plan to verify that the output is what you expect, i.e. provisioning an S3 bucket etc.

$ terraform plan

 

Run apply. This will trigger an apply, not locally on your machine, but on your remote Terraform Cloud account, for the workspace you have selected. Terraform Cloud streams the output back to your terminal so it looks just if you were running Terraform locally. You can go into your Terraform Cloud account, under your workspace and the tab Runs and view the output from this apply there. Here you can also cancel a run, re-run it etc. The environment variables you defined in your Terraform Cloud workspace, i.e. the key and secret, allows Terraform to access your AWS account and provision the infrastructure in your project.

$ terraform apply

 

From your terminal, you can easily switch workspace and provision infrastructure to your stage and prod accounts, using the terraform workspace command:

$ terraform workspace select stage

 

Other commands you can check out are:

$ terraform workspace list

$ terraform workspace show

 

Conclusion

This article has showed how you can utilize Terraform Cloud workspaces to provision infrastructure to multiple environments (AWS accounts). By using a prefix instead of a workspace name in your remote configuration, you can dynamically switch between your different Terraform Cloud environments (workspaces) using the terraform workspace CLI command. This also makes it quite easy to implement this workflow using for instance a Gitlab runner, or any other tool that lets you trigger Terraform CLI commands.

 




About the author



Andreas Spak

Andreas is a Devops and AWS specialist at Spak Consultants. He is an evangelist for building self-service technologies for cloud platforms, in order to offer clients a better experience on their cloud journey. Andreas has also strong focus on automation and container technologies.

Comments