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

Provision target deployment infrastructure dynamically with Terraform

Provision target deployment infrastructure dynamically using Terraform Plan and Apply steps.

Dynamic provisioning creates the target infrastructure on demand during pipeline execution, rather than deploying to pre-existing infrastructure. Configure Terraform Plan and Terraform Apply steps in the Environment section of your Deploy stage to run your Terraform scripts, map the outputs to the Infrastructure Definition, and deploy your application to the newly provisioned infrastructure.

This topic walks you through configuring dynamic provisioning with Terraform in a deployment pipeline. Go to Terraform provisioning to understand provisioning modes and concepts.


What you will learn from this topic


Before you begin

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

  • Terraform or OpenTofu installed on delegate: Terraform or OpenTofu must be installed on the delegate to execute provisioning commands. Go 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. Go to Connect to a Git repo for Git connectors.

  • Harness Secret Manager configured: Harness encrypts Terraform plan files using a Secret Manager before passing them between the Harness Manager and delegates. Go to Harness Secrets Manager overview to set up a Secret Manager.


Configure dynamic provisioning

Dynamic provisioning steps are configured in the Environment section of a Deploy stage. The steps provision infrastructure and map Terraform outputs to your Infrastructure Definition before deploying your application.

Perform the following steps to enable dynamic provisioning in your Deploy stage:

  1. In your Deploy stage, select Infrastructure.

  2. Specify your Environment and Infrastructure Definition if you have not already done so.

    The type of Infrastructure Definition you select determines what Terraform outputs you will need to map later.

  3. In Dynamic provisioning, select Provision your infrastructure dynamically during the execution of your pipeline.

Harness automatically adds the Terraform Plan, Harness Approval, and Terraform Apply steps. You can customize these steps, but plan, approve, and apply is the most common workflow.


Configure Terraform Plan step

The Terraform Plan step connects Harness to your repository and pulls your Terraform scripts. Go to Terraform Plan step reference for detailed configuration options.

Basic settings

Perform the following steps to configure basic settings for the Terraform Plan step:

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

    Harness creates an Entity Id from the name. This Id is used to reference the step in expressions and by the Terraform Apply step.

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

  3. Select Run on Remote Workspace if you want 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. This option is useful when you want to leverage Terraform Cloud features like remote state management, policy enforcement, and cost estimation.

  4. In Command, select Apply. This indicates the step can be used with a Terraform Apply step later.

  5. In Provisioner Identifier, enter a unique value.

    The Provisioner Identifier links the Terraform Plan step to the Terraform Apply step, allowing the Apply step to inherit the plan configuration. This identifier is project-wide and must be unique across all pipelines in your project.

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

    A Terraform plan is a sensitive file that could be misused if accessed. Harness encrypts the plan file and stores it in your Secret Manager, never passing it as plain text between the Harness Manager and delegates.

    Secret size limitations

    Some Secret Managers (HashiCorp Vault, Azure Key Vault, AWS Secrets Manager) have maximum secret size limitations. If your Terraform plan exceeds this limit, use a Key Management Service like Google Cloud KMS or AWS KMS instead. Consult your Secret Manager's documentation for size limits.

Connect to Terraform repository

Perform the following steps to connect Harness to your Terraform repository:

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

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

  3. Select or create a Connector for your repository. Go to Connect to a Git repo to create a connector.

  4. Configure the repository settings based on your provider. For example,

    • Git providers: Select Latest from Branch or Specific Commit ID in Git Fetch Type. Enter the Branch name and Folder Path to your Terraform configuration files.

  5. Select Submit.

Additional configuration options

The Terraform Plan step supports additional configuration options beyond the basic settings and repository connection. Go to Terraform Plan step reference for detailed information on these settings:

  • Workspace: Specify a Terraform workspace to isolate state for different environments.

  • Connector Credentials: Select a connector type to authenticate and pull Terraform child modules from private repositories.

  • Terraform Var Files: Add inline or remote variable files to pass input variables to your Terraform configuration.

  • Backend Configuration: Configure remote state backend settings for storing Terraform state files.

  • Targets: Specify resource addresses to limit the plan to specific modules or resources in your Terraform scripts.

  • Environment Variables: Set key-value pairs for Terraform environment variables.

  • Export JSON representation of Terraform Plan: Export the plan output in JSON format for programmatic processing.

  • Export Human Readable representation of Terraform Plan: Export the plan output in human-readable text format.

  • Store terraform plan on delegate: Store the Terraform plan file on the delegate instead of in the Secret Manager.

  • Skip state storage: Skip storing the Terraform state in the backend after planning.

  • Create remote workspace with prefix: Create a new Terraform Cloud workspace with a specified prefix if it does not exist.

  • Command Line Options: Enter additional Terraform CLI flags to pass to the plan command.

Command line options

In Command Line Options, enter any additional Terraform CLI flags you want to pass to the terraform plan command.

For example, you can use -parallelism=n to limit the number of concurrent operations, or -lock-timeout=DURATION to specify how long to wait for a state lock. Enter flags without the terraform plan prefix (for example, enter -parallelism=5 not terraform plan -parallelism=5).

  • Select Skip Refresh Command to skip running terraform refresh before generating the plan.

    By default, Terraform refreshes the state before planning to detect any 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. Use this option only when you are certain no manual changes have been made.


Configure approval step

Harness automatically adds a Manual Approval step between the Terraform Plan and Terraform Apply steps. You can customize or remove this step.

Go to Using Manual Harness Approval Steps or Using Jira and ServiceNow Approval Steps to configure approval steps.


Configure Terraform Apply step

The Terraform Apply step inherits its configuration from the Terraform Plan step and applies the Terraform plan to provision infrastructure.

Perform the following steps to configure the Terraform Apply step:

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

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

  3. In Configuration Type, select Inherit From Plan.

    This option tells the Apply step to use the plan generated by the Terraform Plan step with the matching Provisioner Identifier. Harness retrieves the encrypted plan from the Secret Manager and applies it.

  4. In Provisioner Identifier, enter the same value you used in the Terraform Plan step.

    The Provisioner Identifier links the Apply step to the Plan step. This identifier must match exactly so the Apply step can inherit the plan configuration.

Match Provisioner Identifiers

You must use the same Provisioner Identifier in both the Terraform Plan and Terraform Apply steps. If the identifiers do not match, the Apply step will fail because it cannot find the plan to apply.

Go to Terraform Apply step reference for detailed configuration options.


Map Terraform outputs to infrastructure

After the Terraform Apply step provisions infrastructure, you must map Terraform outputs to your Infrastructure Definition. The required outputs depend on your deployment type.

Terraform outputs are values exported from your Terraform configuration using output blocks. Harness uses these outputs to configure the target infrastructure for your deployment. For example, a Kubernetes deployment requires a connector reference and namespace, while an AWS Lambda deployment requires a region and IAM role.

Go to the deployment-specific documentation for detailed instructions on mapping outputs for your deployment type:


Configure Terraform Rollback step

Harness automatically adds a Terraform Rollback step to the Rollback section of your stage when you enable dynamic provisioning. This step ensures that infrastructure changes are reverted if the deployment fails.

The Terraform Rollback step is pre-configured when you enable dynamic provisioning. You can customize its settings if needed.

Perform the following steps to configure the Terraform Rollback step:

  1. In Name, the default name is Terraform Rollback. You can change this if needed.

  2. In Timeout, enter how long Harness should wait to complete the rollback before failing it.

  3. In Provisioner Identifier, enter the same value you used in the Terraform Plan and Apply steps.

    The Provisioner Identifier determines which Terraform state to roll back. It must match the identifier used in your Plan and Apply steps so Harness knows which provisioned resources to revert.

When rollback happens, Harness rolls back the provisioned infrastructure to the previous successful Terraform state for the Provisioner Identifier. Harness performs a hard rollback to the exact version of the state, without incrementing the serial.

Go to Terraform Rollback step reference to configure rollback.


Terraform output expressions

Terraform steps output the commit ID of configuration files stored in Git. You can reference these outputs using Harness expressions in subsequent steps or stages.

For example, for a Terraform Apply step with the identifier TerraformApply, you can access the following outputs:

  • Config files: <+pipeline.stages.test.spec.execution.steps.TerraformApply.git.revisions.TF_CONFIG_FILES>

  • Backend config files: <+pipeline.stages.test.spec.execution.steps.TerraformApply.git.revisions.TF_BACKEND_CONFIG_FILE>

  • Var file with identifier varfile1: <+pipeline.stages.test.spec.execution.steps.TerraformApply.git.revisions.varfile1>


Pipeline examples

The following examples show complete pipeline YAML for both dynamic and ad hoc provisioning using Terraform.

Dynamic provisioning example

This example provisions a Kubernetes namespace with resource quotas and limit ranges in the Environment > provisioner section, then verifies the provisioned infrastructure in the Execution section. The Infrastructure Definition can reference Terraform outputs to deploy to the dynamically provisioned namespace.

Dynamic provisioning pipeline YAML

Key points:

  • Provisioner section: Terraform steps run in Environment > provisioner section before deployment

  • Infrastructure Definition: References environment-level infrastructure dynamicTF configured with <+provisioner.tf_working.namespace_name> expression

  • Critical configurations:

    • storeTfPlanOnDelegate: true - Stores plan file on delegate (prevents Secret Manager API errors)

    • skipStateStorage: true - Skips Harness state storage (prevents version conflicts)

    • provisionerIdentifier - Links Plan, Apply, and Destroy steps together (must match across all steps)

    • delegateSelectors - Must be identical on Plan and Apply steps (ensures plan file accessibility)

  • Terraform outputs: Available via <+provisioner.PROVISIONER_ID.OUTPUT_NAME> in Infrastructure Definition

  • Execution steps: Verify and display provisioned infrastructure, optional destroy for cleanup

Ad hoc provisioning example

This example provisions infrastructure in the Execution section as a standalone task without deploying an application.

Ad hoc provisioning pipeline YAML

Key configurations:

  • storeTfPlanOnDelegate: true - Stores plan on delegate to avoid null pointer issues

  • skipStateStorage: true - Skips Harness state storage to avoid version conflicts

  • delegateSelectors - Ensures Plan and Apply run on same pod

Terraform outputs expression: <+execution.steps.Terraform_Apply.output.OUTPUT_NAME>


Troubleshooting

Error acquiring the state lock in Terraform Plan step

Ensure no other process is holding a lock on the Terraform state. Harness retries state lock acquisition automatically.

Terraform plan file exceeds Secret Manager size limit

Switch to a Key Management Service like Google Cloud KMS or AWS KMS, which do not have the same size limitations as vault-based Secret Managers.

Terraform module source authentication fails with private Git repositories

In the Terraform Plan step, enable 'Use Connector credentials' under Source Module and ensure your Harness Git Connector uses SSH or HTTPS authentication.

Provisioner Identifier conflict across multiple pipelines

Provisioner Identifiers are project-wide. Use unique identifiers for each pipeline or coordinate with your team to avoid reusing identifiers.

NullPointerException in Terraform Plan step after successful terraform init and refresh

This occurs when the Harness backend fails to encrypt or store the Terraform plan file in the Secret Manager. Enable 'Store terraform plan on delegate' (storeTfPlanOnDelegate: true) in the Terraform Plan step to store the plan on the delegate at /opt/harness-delegate/tf-plan/ instead of in Secret Manager. This bypasses the Secret Manager encryption step.

Unable to update StateFile version for entityId error in Terraform Plan

This state version conflict occurs when the Provisioner Identifier was used in a previous execution with different state. Enable 'Skip state storage' (skipStateStorage: true) in the Terraform Plan step to skip Harness local state upload and download operations. Alternatively, use a different Provisioner Identifier or clear the existing state for that identifier.

Terraform Apply fails with 'Terraform Plan File not present in local terraform directory'

This occurs when Terraform Plan and Apply steps run on different delegate pods. When using 'storeTfPlanOnDelegate: true', you must add the same 'delegateSelectors' to both Terraform Plan and Terraform Apply steps to ensure they execute on the same pod where the plan file is stored.

Terraform Apply fails with 'resource already exists' error (e.g., namespace already exists)

This occurs when resources from a previous execution were not cleaned up. Add a Shell Script step before Terraform Plan to delete existing resources (e.g., kubectl delete namespace), or use a different resource name. For production workflows, implement proper state management with remote backends to track resource ownership.

Infrastructure definition fails with 'Not found provisioner output, provisionerIdentifier: input'

Your infrastructure definition is configured with 'provisionerIdentifier: <+input>' but the pipeline is not providing this runtime input. Add 'provisionerIdentifier: <+pipeline.variables.provisioner_id>' under 'infrastructureDefinitions > inputs > spec' in your pipeline YAML to explicitly provide the Provisioner Identifier value.

Terraform command not found on delegate during Terraform Plan step

Terraform is not pre-installed on Harness delegates by default. Add a Shell Script step before Terraform Plan to install Terraform: download the binary from releases.hashicorp.com, extract it, and move it to /usr/local/bin/ or add it to PATH. Alternatively, use a custom delegate image with Terraform pre-installed.


Next steps

Explore these related topics for more details on Terraform steps and deployment types.

Last updated

Was this helpful?