Add Terraform Scripts

Updated 2 weeks ago by Michael Cretzman

This topic describes how to set up a Harness Infrastructure Provisioner for Terraform.

Once the Harness Infrastructure Provisioner is set up, you can use it to define a deployment target in a Harness Infrastructure Definition.

Once you add the Infrastructure Definition to a Workflow, you add a Terraform Provisioner step to the Workflow. The Terraform Provisioner step uses the same Harness Infrastructure Provisioner to run your scripts and build the target infrastructure.

Harness supports first class Terraform provisioning for AWS-based infrastructures (SSH, ASG, ECS, Lambda) and Google Kubernetes (GKE).

Harness Terraform Infrastructure Provisioner are only supported in Canary and Multi-Service Workflows. For AMI/ASG and ECS deployments, Terraform Infrastructure Provisioners are also supported in Blue/Green Workflows.

In this topic:

Before You Begin

Visual Summary

This topic describes step 1 in the Harness Terraform Provisioning implementation process:

Once you have completed this topic, you can move onto the next step: Map Terraform Infrastructure.

Step 1: Add a Terraform Provisioner

To set up a Terraform Infrastructure Provisioner, do the following:

  1. In your Harness Application, click Infrastructure Provisioners.
  2. Click Add Infrastructure Provisioner, and then click Terraform. The Add Terraform Provisioner dialog appears.
  3. In Name, enter the name for this provisioner. You will use this name to select this provisioner in Harness Infrastructure Definitions and Workflows.
  4. Click Next. The Script Repository section appears. This is where you provide the location of your Terraform script in your Git repo.

Step 2: Select Your Terraform Script Repo

  1. In Script Repository, in Git Repository, select the Source Repo Provider you added for the Git repo where your script is located.
  2. In Commit, select Latest from Branch or Specific Commit ID.
    1. If you selected Latest from Branch, in Git Repository Branch, enter the repo branch to use. For example, master. For master, you can also use a dot (.).
    2. If you selected Specific Commit ID, in Commit ID, enter the Git commit ID to use.
  3. In Terraform Configuration Root Directory, enter the folder where the script is located. Here is an example showing the Git repo on GitHub and the Script Repository settings:
  4. Click Next. The Variables section is displayed. This is where you will specify the script input variables that must be given values when the script is run.

Before you move onto Variables, let's review the option of using expressions in Script Repository.

Option 1: Use Expressions for Script Repository

You can also use expressions in the Git Repository Branch and Terraform Configuration Root Directory and have them replaced by Workflow variable values when the Terraform Provisioner is used by the Workflow. For example, a Workflow can have variables for branch and path:

In Script Repository, you can enter variables as ${workflow.variables.branch} and ${workflow.variables.path}:

You cannot use variables in the Script Repository fields to populate the Variables section. To populate the Variables section, click Populate from Example and enter in actual values.

When the Workflow is deployed, you are prompted to provide values for the Workflow variables, which are then applied to the Script Repository settings:

This allows the same Terraform Provisioner to be used by multiple Workflows, where each Workflow can use a different branch and path for the Script Repository.

Step 3: Add Input Variables

You can enter input variables manually or have the Harness Delegate use the Source Repo Provider you added to pull the variables from your script and populate the Variables & Commands section.

  1. In Variables & Commands, click Populate Variables.
  2. In Populate from Example, click Submit.
    If Harness cannot pull the variables from your script, check your settings and try again. Ensure that your Source Repo Provisioner is working by clicking its TEST button.
    Once Harness pulls in the variables from the script, it populates the Variables section.

In the Type column for each variable, you can specify Text or Encrypted Text.

When you add the provisioner to a Workflow, you will have to provide text values for Text variables, and select Harness Encrypted Text variables for Encrypted Text variables. See Encrypted Text variables in Secrets Management.

Step 4: Select Secret Manager for Terraform Plan

In Terraform Plan Storage Configuration, select a Secrets Manager to use for encrypting/decrypting and saving the Terraform plan file.

See Add a Secrets Manager.

A Terraform plan is a sensitive file that could be misused to alter cloud provider resources if someone has access to it. Harness avoids this issue by never passing the Terraform plan file as plain text.

Harness only passes the Terraform plan between the Harness Manager and Delegate as an encrypted file using a Harness Secrets Manager.

When the terraform plan command is run on the Harness Delegate, the Delegate encrypts the plan and saves it to the Secrets Manager you selected. The encrypted data is passed to the Harness Manager.

When the plan is going to be applied, the Harness Manager passes the encrypted data to the Delegate.

The Delegate decrypts the encrypted plan and applies it using the terraform apply command.

Option 2: Skip Terraform Refresh When Inheriting Terraform Plan

To understand this setting, let's review some of the options available later when you will use this Terraform Infrastructure Provisioner with a Terraform Provision or Terraform Apply step in your Workflow.

When you add either of those steps, you can run them as a Terraform plan using their Set as Terraform Plan setting.

Next, you have the option of exporting the Terraform plan from one Terraform step (using the Export Terraform Plan to Apply Step setting) and inheriting the Terraform plan in the next Terraform step (using the Inherit following configurations from Terraform Plan setting).

Essentially, these settings allow you to use your Terraform Provision step as a Terraform plan dry run (terraform plan -out=tfplan).

During this inheritance, Harness runs a Terraform refresh, then a plan, and finally executes the new plan.

If do not want Harness to perform a refresh, enable the Skip Terraform Refresh when inheriting Terraform plan option in your Terraform Infrastructure Provisioner.

When this setting is enabled, Harness will directly apply the plan without reconciling any state changes that might have occurred outside of Harness between plan and apply.

This setting is available because a Terraform refresh is not always an idempotent command. It can have some side effects on the state even when no infrastructure was changed. In such cases, terraform apply tfplan commands might fail.

Option 3: Add Remote State Variables

By default, Terraform uses the local backend to manage state, in a local Terraform language file named terraform.tfstate on the disk where you are running Terraform.

With a local backend, Harness stores the state file in the Harness Store (currently, in GCS), acting as a remote backend artificially. When a new run starts, the tf file is pulled from GCS onto the Harness Delegate. After the run, the updated state file is uploaded back to GCS (MongoDB for Harness On-Prem).

With remote state, Terraform writes the state data to a persistent remote data store (such as an S3 bucket or HashiCorp Consul), which can then be shared between all members of a team.

You can add the backend configs (remote state variables) for remote state to your Terraform Provisioner in Backend Configuration (Remote state).

  1. In Backend Configuration (Remote state), enter the backend configs from your script.

Depending on which platform you store your remote state data, Terraform allows you to pass many different credentials and configuration settings, such as access and secret keys. For example, see the settings available for AWS S3 from Terraform.

Option 4: Reference Script Environment Variables

You can reference environment variables in your script by adding them as Terraform environment variables in your Harness Terraform Infrastructure Provisioner.

Once you have referenced the environment variables in your Terraform Infrastructure Provisioner, you can provide values when you add the Terraform Infrastructure Provisioner to a Workflow.

During deployment, Harness uses the values for the Terraform environment variables.

  1. In Terraform Environment Variables, click Add.
  2. Enter a name, type, and value for the environment variable. For example: TF_LOGText, and TRACE.
    If you select Encrypted Text, you must select an existing Harness Encrypted Text secret.
    You can use Harness Workflow variables and expression variables for the name and value.
  3. Later, when you add the Terraform Infrastructure Provisioner to your Workflow, provide values for the referenced environment variables.

See Add Environment Variables in the Terraform Provisioning and Terraform Apply steps.

Environment variables can also be deleted using the Terraform Destroy step. See Remove Provisioned Infra with Terraform Destroy.

Step 5: Complete the Terraform Provisioner

When you are done, the Terraform Provisioner will look something like this:

Now you can use this provisioner in both Infrastructure Definitions and Workflows.

Next Steps

  • Infrastructure Definitions — Use the Terraform Infrastructure Provisioner to define a Harness Infrastructure Definition. You do this by mapping your script outputs to the required Harness Infrastructure Definition settings. Harness supports provisioning for many different platforms. See the following:
  • Workflows — Once you have created the Infrastructure Definition and added it to a Workflow, you add a Terraform Provisioner Step to the Workflow to run your script and provision the infra: Provision using the Terraform Provisioner Step.

How did we do?