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
How to configure the Terraform Plan step in your Deploy stage.
How to connect Harness to your Terraform repository using Git, S3, or Artifactory.
How to use Provisioner Identifiers to link Plan, Apply, and Rollback steps.
How to configure optional settings like workspaces, var files, backend configuration, and targets.
How to export JSON and human-readable plan outputs for use in subsequent steps.
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.
Provisioner Identifier scope
The Provisioner Identifier is project-wide. You can reference it across pipelines in the same project. Coordinate with your team to ensure identifiers are unique and not reused across pipelines to avoid conflicts.
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.
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:
In Configuration File Repository, select Specify Config File or select the edit icon.
The Terraform Config File Store settings appear.
Select the provider where your files are hosted (GitHub, GitLab, Bitbucket, AWS S3, Artifactory, etc.).
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
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.
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
For more information, refer to Azure Connector Settings Reference.
GCP Connector
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.
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:
In Backend Configuration, select Remote.
Select Specify Terraform Backend Config File Store.
Select your provider (GitHub, Artifactory, S3, etc.) and select or create a Connector to the repository where the files are located.
For Git providers:
In Git Fetch Type, select Latest from Branch or Specific Commit ID.
In Branch, enter the name of the branch.
In File Path, add the file path from the root of the repository to the backend config file.
Select Submit.
For AWS S3:
In Region, select the region where your bucket is stored.
In Bucket, select the bucket where your backend config file is stored.
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>
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:
Use this option when your Secret Manager has file size limits or you want to avoid storing plans in Secret Manager.
Plans are lost if the delegate pod restarts.
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
ReadWriteManyaccess 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
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
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_WORKSPACEenvironment variable so Terraform uses it.If both the step configuration and environment variable specify a workspace, the step configuration takes precedence.
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: error2: 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:
Delegate Selector: Select specific delegates to run this step.
Conditional Execution: Define conditions for when to execute this step.
Failure Strategy: Define what happens when the step fails.
Looping Strategy: Run the step multiple times with different configurations.
Policy Enforcement: Apply governance policies to this step.
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
Troubleshooting
Next steps
Terraform Apply step: Apply the plan generated by this step.
Terraform Rollback step: Roll back provisioned infrastructure if needed.
Terraform Destroy step: Remove provisioned infrastructure.
Provision infrastructure dynamically with Terraform: Complete dynamic provisioning workflow.
Last updated
Was this helpful?