For the complete documentation index, see llms.txt. This page is also available as Markdown.

Preview with the Terraform Plan step

Configure the Terraform Plan step to preview infrastructure changes before applying them.

The Terraform Plan step runs a Terraform plan to preview infrastructure changes before applying them. You can use it with a Terraform Apply step to apply the plan, or standalone to preview changes only.

This topic explains how to configure the Terraform Plan step in your deployment pipeline.


What you will learn from this topic


Before you begin

  • Harness project access: View, Create/Edit, and Execute permissions on Pipelines and Environments. For more information, refer to RBAC in Harness to configure roles.

  • Terraform or OpenTofu installed on delegate: Terraform or OpenTofu must be installed on the delegate to execute Terraform commands. For more information, refer to Build custom delegate images with third-party tools to install Terraform.

  • Terraform configuration files: Your Terraform scripts must be accessible via a Harness connector. For more information, refer to Connect to a Git repo for Git connectors or Artifactory Connector Settings Reference for Artifactory.

  • Secret Manager configured: Terraform plans contain sensitive data. Harness encrypts the plan using a Secret Manager before storing it. For more information, refer to Harness Secrets Manager overview to configure a Secret Manager.

  • Understanding of Terraform concepts: This guide assumes familiarity with Terraform workspaces, backends, modules, and state files. For more information, refer to Terraform documentation.


Configure the Terraform Plan step

You can add the Terraform Plan step in two locations within your Deploy stage:

  • Environment > Dynamic Provisioning section: Use this location when provisioning target infrastructure for deployment. You must pair it with a Terraform Apply step to apply the plan. For detailed workflow examples, refer to Provision infrastructure dynamically with Terraform.

  • Execution steps: Use this location for ad hoc planning or standalone plan previews. The Terraform Apply step is optional in this flow.


Basic settings

Configure the following basic settings for the Terraform Plan step.

Name

In Name, enter a name for the step (for example, plan).

The name is important because you can use it in expressions to refer to settings in this step.

For example, if the stage name is Terraform and the step name is plan, and you want to reference its timeout setting, use:

<+pipeline.stages.Terraform.spec.execution.steps.plan.timeout>

Timeout

In Timeout, enter how long Harness should wait to complete the Terraform Plan step before failing it.

Run on Remote Workspace

Select Run on Remote Workspace to execute Terraform commands in a Terraform Cloud or Terraform Enterprise workspace instead of on the Harness Delegate.

When enabled, Harness triggers a run in your remote workspace and monitors its status. The workspace must be configured with your Terraform configuration and variables.

The remote backend is supported only when the Configuration Type is Inline.

Example remote backend configuration:

Command

In Command, select Apply or Destroy.

  • Apply: Use this option if you will apply the plan later with a Terraform Apply step. This indicates the plan can be used with a Terraform Apply step.

  • Destroy: Use this option if you will destroy resources later with a Terraform Destroy step.

Provisioner Identifier

The Provisioner Identifier is a unique label that links this Terraform Plan step to Terraform Apply, Destroy, and Rollback steps.

In Provisioner Identifier, enter a unique value.

The most common use is between Terraform Plan and Terraform Apply steps. The Terraform Apply step uses the same Provisioner Identifier to apply the plan from the Plan step.

You also use the same Provisioner Identifier with the Terraform Destroy step to remove provisioned resources.

You also use the same Provisioner Identifier with the Terraform Rollback step to roll back provisioned resources.

Secret Manager

Terraform plans contain sensitive data. Harness encrypts the plan using a Secret Manager before storing it.

In Secret Manager, select the Secret Manager to use for encrypting and storing the Terraform plan file.

For more information, refer to Harness Secrets Manager overview.

A Terraform plan is a sensitive file that could be misused to alter 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 Secrets Manager.

When the terraform plan command runs on the Harness Delegate, the Delegate encrypts the plan and saves it to the Secrets Manager you selected. When the plan is applied, the Harness Manager passes the encrypted data to the Delegate, which decrypts and applies it using the terraform apply command.

Secret size limitations

Some Secret Managers (HashiCorp Vault, Azure Key Vault, AWS Secrets Manager) have maximum secret size limitations. For example, AWS Secrets Manager has a 64KB limit. If your Terraform plan exceeds this limit, use a Key Management Service like Google Cloud KMS or AWS KMS instead.

Configuration File Repository

The Configuration File Repository is where your Terraform scripts and configuration files are located.

Perform the following steps to connect to your Terraform repository:

  1. In Configuration File Repository, select Specify Config File or select the edit icon.

    The Terraform Config File Store settings appear.

  2. Select the provider where your files are hosted (GitHub, GitLab, Bitbucket, AWS S3, Artifactory, etc.).

  3. Select or create a Connector for your repository. Harness supports the following connector types for Terraform configuration files:

    • Git providers (GitHub, GitLab, Bitbucket, etc.): Store Terraform scripts in version-controlled repositories. For more information, refer to Connect to a Git repo.

    • AWS S3: Store Terraform scripts in S3 buckets. For more information, refer to Add an AWS connector.

    • Artifactory: Store Terraform scripts as archived artifacts in Artifactory repositories. For more information, refer to Artifactory Connector Settings Reference (see Artifactory with Terraform Scripts).


Optional configuration

The following settings are available under Optional Configuration in the Terraform Plan step.

Workspace

A Terraform workspace is a separate instance of state data, allowing you to manage multiple environments (Dev, QA, Production) from the same Terraform configuration.

Harness supports Terraform workspaces. A Terraform workspace is a logical representation of your infrastructure, such as Dev, QA, Stage, or Production.

Workspaces are useful when testing changes before moving to production infrastructure. Each workspace isolates its state from other workspaces.

Example script with workspace configuration:

In Workspace, enter the name of the workspace to use. You can also use a stage variable in Workspace to specify a different workspace name each time the pipeline runs.

Connector credentials

You can use a connector to authenticate with the target cloud provider. This optional configuration takes the connector reference and the Terraform step uses it to authenticate with the cloud provider targeted for infrastructure provisioning.

This connector configuration is available in the Terraform Plan step. It also appears in Terraform Apply and Terraform Destroy steps when Configuration Type is set to Inline.

AWS Connector

Requirements

This feature requires Harness Delegate version 81202 or later. Contact Harness Support to enable this feature.

You can use an AWS connector to have the Terraform Plan and Apply steps assume a role to perform infrastructure provisioning. It takes the AWS connector, a region, and a Role ARN. The Terraform step uses these parameters to authenticate with the AWS account targeted for infrastructure provisioning.

By default, AWS assumes the role session duration as 900 seconds. To increase the session duration, use the HARNESS_AWS_ASSUME_ROLE_DURATION environment variable (requires Harness Delegate version 82700 or later). Set the value in seconds in the environment variable section of the Terraform step.

When configured, these fields can be passed as a fixed value, runtime input, or an expression.

Sample YAML

Azure Connector

Harness Terraform steps support authenticating with Azure using Azure connectors for target provisioning. This enables seamless integration with Azure infrastructure when running Terraform Plan, Apply, and Destroy steps with inline Terraform configuration.

Supported authentication methods:

  • Manual credentials

  • Delegate-based credentials

  • OIDC token-based authentication

Certificate-based authentication is not supported yet.

For more information, refer to Azure Connector Settings Reference.

Sample YAML

GCP Connector

Requirements

This feature requires Harness Delegate version 88303 or later.

Harness Terraform steps support authenticating with Google Cloud Platform (GCP) using GCP connectors for target infrastructure provisioning.

For information on setting up a GCP connector, refer to Connect to Google Cloud Platform (GCP).

Supported authentication methods:

  • Manual Credentials (ManualConfig): Use GCP service account credentials stored in Harness Secret Manager. The connector references a secret containing the GCP Service Account Key in JSON format.

  • Inherit From Delegate (InheritFromDelegate): Use credentials from the delegate's IAM role, such as a GCE instance service account or GKE workload identity. At least one delegate selector must be specified.

  • OIDC Authentication (OidcAuthentication): Enable federated authentication using OpenID Connect for workload identity federation. This is the recommended approach for production environments as it eliminates long-lived credentials.

Manual Credentials Connector YAML example

This example uses a GCP service account key stored in Harness Secret Manager:

GCP Connector configuration (Manual Credentials):

Inherit From Delegate Connector YAML example

This example uses credentials from the delegate's IAM role (GCE instance service account or GKE workload identity):

GCP Connector configuration (Inherit From Delegate):

OIDC Authentication Connector YAML example

This example uses OpenID Connect for workload identity federation (recommended for production):

GCP Connector configuration (OIDC Authentication):

Terraform var files

You can specify Terraform variables inline and fetch remote variable files during runtime. For more information, refer to Specify Terraform variables.

Backend configuration

The Backend Configuration section contains the remote state values.

You can use an inline or remote state file.

Remote backend config file

Perform the following steps to use a remote backend config file:

  1. In Backend Configuration, select Remote.

  2. Select Specify Terraform Backend Config File Store.

  3. Select your provider (GitHub, Artifactory, S3, etc.) and select or create a Connector to the repository where the files are located.

For Git providers:

  1. In Git Fetch Type, select Latest from Branch or Specific Commit ID.

  2. In Branch, enter the name of the branch.

  3. In File Path, add the file path from the root of the repository to the backend config file.

  4. Select Submit.

For AWS S3:

  1. In Region, select the region where your bucket is stored.

  2. In Bucket, select the bucket where your backend config file is stored.

  3. In File Path, add the file path from the root of the bucket to the backend config file.

You can also use files in the Harness File Store.

To use the same remote state file set in the Terraform Plan step, Terraform Apply steps must use the same Provisioner Identifier.

For an example of how the config file should look, refer to Backend Configuration from HashiCorp.

Inline State

Enter values for each backend config (remote state variable).

For example, if your config.tf file has the following backend:

In Backend Configuration, provide the required configuration variables for the backend type. For a remote backend configuration, the variables should be in a .tfvars file format:

For more information, refer to GCS Standard Backend from Terraform.

Targets

You can use the Targets setting to target one or more specific modules in your Terraform script, similar to using the terraform plan -target command.

For more information, refer to Resource Targeting from Terraform.

Identify the module using the standard format module.name, such as terraform plan -target="module.s3_bucket".

If you have multiple modules in your script and you do not select one in Targets, all modules are used.

Environment variables

If your Terraform script uses environment variables, you can provide values for those variables here.

Example:

You can use Harness encrypted text for values. For more information, refer to Add text secrets.

Export JSON representation of Terraform plan

Enable this setting to export a JSON representation of the Terraform plan.

In subsequent Execution steps, such as a Shell Script step, you can reference the Terraform plan using this expression format:

<+execution.steps.[Terraform Plan step Id].plan.jsonFilePath>

Example usage in a Shell Script step:

If the Terraform Plan step is in Dynamic Provisioning in Infrastructure, and the step Id is TfPlan, the expression is:

<+infrastructure.infrastructureDefinition.provisioner.steps.TfPlan.plan.jsonFilePath>

JSON representation of the Terraform plan can be accessed across different stages. In this case, the fully qualified name (FQN) is required:

<+pipeline.stages.TfStage.spec.execution.steps.TfPlan.plan.jsonFilePath>

When the Terraform Plan step is in a step group:

<+pipeline.stages.[stage name].spec.execution.steps.[step group name].steps.[step name].plan.jsonFilePath>

When Run on Remote Workspace is selected, you will not be able to export the JSON representation of the Terraform plan.

Scope of Expression

JSON representation of the Terraform plan is available only between the Terraform Plan step and subsequent Terraform Apply step. The expression will fail to resolve if used after the Terraform Apply step.

If used across stages, the Terraform Plan step can be in one stage and the Terraform Apply step in a subsequent stage. The expression will resolve successfully in this case.

The JSON of the Terraform Plan step is not available after Rollback.

Export human readable representation

Enable this option to view the Terraform plan file path and contents as human-readable JSON in subsequent steps, such as a Shell Script step.

Once you enable this option and run a Deploy stage with the Terraform Plan step, you can view the Output tab and copy the Output Value for the humanReadableFilePath output.

The format for the expression is:

<+terraformPlanHumanReadable."pipeline.stages.[stage Id].spec.execution.steps.[step Id].[Provisioner Identifier]_planHumanReadable">

Example:

If there are no changes in the plan, the standard Terraform message is shown:

Store Terraform plan on delegate

Here is a video demo of how to store Terraform Plan files on delegate:

Requirements

This setting requires Harness Delegate version 24.04.82705 or later.

Use this option when your Secret Manager has file size limits or you want to avoid storing plans in Secret Manager.

Enable Store terraform plan on delegate to store the Terraform Plan on Harness Delegate temporarily. This is useful if you do not want to save Terraform Plan files in Secrets Manager or if there is a file size limit on Secrets Manager.

After you enable this option, select Inherit From Plan in the Terraform Apply or Terraform Destroy step's Configuration Type field and enter the Provisioner Identifier used by the Terraform Plan step.

Important notes:

  • You must execute the Terraform Plan and Terraform Apply/Destroy steps on the same pod. If your delegate has multiple pod replicas, make sure to run the Terraform steps on the same pod.

  • Harness stores Terraform Plan files at /opt/harness-delegate/./tf-plan/ inside the working directory.

  • If delegate pods are restarted, Terraform plan files are lost. To prevent this, set up a persistent volume with ReadWriteMany access mode if you have multiple pod replicas.

  • The Terraform plan file is cleaned up after the Terraform Apply/Destroy step executes or after pipeline execution completes.

Skip state storage

Requirements

This feature requires Harness Delegate version 812xx or later.

While running Terraform commands on the delegate, Harness by default detects if there is a local state file in the Terraform working directory.

If a local state file is identified, at the end of execution it is saved on Harness storage with a key based on the provisioner identifier. That state file is downloaded in the Terraform working directory for subsequent executions, and the updated state is uploaded after execution ends.

This method allows maintaining the state of infrastructure even if there is no Terraform backend configured. This is more for testing purposes. For production environments, Harness advises you configure a backend in your Terraform config files. For more information, refer to Backend Configuration from HashiCorp.

With Skip state storage enabled, Harness skips the local state upload and download operations.

This option is useful only if you do not have a Terraform backend configured in your Terraform config files. If you have a Terraform backend configured, the Terraform CLI will not create local state files.

Create remote workspace with prefix

Requirements

This option requires Harness Delegate version 86400 or later.

When using a remote backend with a workspace prefix, Terraform does not automatically create the workspace if it does not already exist. This can cause pipeline failures with errors like:

Error: Currently selected workspace "my-app-dev" does not exist

To address this, Harness provides the Create remote workspace with prefix option. When enabled:

  • If the remote workspace does not exist, Harness automatically creates it and continues execution.

  • If the remote workspace does exist, Harness exports it to the TF_WORKSPACE environment variable so Terraform uses it.

  • If both the step configuration and environment variable specify a workspace, the step configuration takes precedence.

To enable automatic workspace selection when a workspace is configured in the step settings, this flag must be enabled.

If you prefer not to use this flag, you can manually configure the workspace using the TF_WORKSPACE environment variable.

Rollback does not delete workspaces created using this option. Workspace cleanup must be handled manually.

Sample YAML

Command line options

This setting allows you to set Terraform CLI options for Terraform commands. For example: -lock=false, -lock-timeout=0s.

Skip Terraform refresh

Select Skip Terraform refresh to skip running terraform refresh before generating the plan.

By default, Terraform refreshes the state before planning to detect changes made outside of Terraform. Enable this option to skip the refresh step, which can speed up plan execution but may result in a plan that does not account for manual changes to your infrastructure.

Access detailed exit code output

Harness automatically captures the detailed exit code from the Terraform CLI and makes it available as a step output. The detailed exit code follows the standard terraform plan -detailed-exitcode convention:

  • 0: succeeded with empty diff (no changes)

  • 1: error

  • 2: succeeded with non-empty diff (changes present)

You can access the detailed exit code in subsequent steps using the following expression format:

<+pipeline.stages.STAGE_ID.spec.execution.steps.STEP_ID.plan.detailedExitCode>

Example:

<+pipeline.stages.TfStage.spec.execution.steps.TfPlan.plan.detailedExitCode>


Advanced settings

In Advanced, you can configure the following options:


Working directory cleanup

Each Terraform step runs in a specific working directory on the delegate.

The Terraform working directory is located at /opt/harness-delegate/./terraform-working-dir/.

To that directory path, Harness adds additional directories named after the organization, account, project, and provisioner identifier such that the final working directory is /opt/harness-delegate/./terraform-working-dir/org-name/account-name/project-name/provisionerId/.

In this final working directory, Harness stores the Terraform configuration and all fetched files such as var-files and backend-config.

Once the Terraform step execution is complete, Harness cleans up the main working directory /opt/harness-delegate/./terraform-working-dir/. This cleanup happens immediately after the step completes successfully or fails.

If you generate local resources on the delegate in the directory where Terraform configurations are located, those resources are also removed. If you need those resources, generate them outside the Terraform working directory.


YAML example

Terraform Plan step YAML

Key configuration options:

  • provisionerIdentifier: Links this Plan step to Apply, Destroy, and Rollback steps

  • storeTfPlanOnDelegate: true: Stores plan file on delegate at /opt/harness-delegate/tf-plan/ instead of Secret Manager (use when Secret Manager has size limits or to avoid null pointer issues)

  • skipStateStorage: true: Skips Harness local state upload/download (use when you have a remote backend configured or to avoid state version conflicts)

  • delegateSelectors: Ensures Terraform Plan and Apply steps run on the same delegate pod (required when storeTfPlanOnDelegate: true)


Troubleshooting

Terraform Plan step fails with 'Provisioner Identifier not found' error

Ensure the Provisioner Identifier is unique within the project. If using with Terraform Apply, verify both steps use the exact same identifier (case-sensitive).

Terraform Plan step fails with Secret Manager encryption error

Verify the Secret Manager is configured correctly and the delegate can access it. Check that the Terraform plan size does not exceed the secret size limit (e.g., AWS Secrets Manager has a 64KB limit).

Terraform Plan step fails to fetch configuration files from Git repository

Verify the Git connector is configured correctly with valid credentials. Check the branch name and folder path are correct. For SSH authentication, ensure the SSH key has no passphrase.

Terraform Plan remote workspace does not exist error

Enable 'Create remote workspace with prefix' in the Terraform Plan step settings, or manually create the workspace in your Terraform Cloud/Enterprise instance before running the pipeline.

Terraform execution on a Docker delegate managed by ECS fails with NoCredentialProviders error

When your Docker delegate is managed by ECS and set to assume an IAM role, ensure the delegate has permissions to assume the role. If using a proxy, ensure the proxy instance also has permissions. Set HTTP_PROXY and HTTPS_PROXY environment variables in Terraform steps if needed.


Next steps

Last updated

Was this helpful?