Terraform Cloud / HCP Terraform
HCP Terraform (formerly Terraform Cloud) is HashiCorp’s managed platform for running Terraform. Instead of stitching together your own state backend, CI runners, secret storage, and approval gates, you get all of it as a hosted service: remote plan/apply execution, encrypted state with locking and versioning, shared variable sets, run tasks for third-party checks, and policy enforcement via Sentinel or OPA. It is the fastest way to give a team a safe, auditable Terraform workflow without building a CI/CD pipeline from scratch.
How HCP Terraform is organized
Everything in HCP Terraform lives under an organization. Inside an organization you create workspaces, and each workspace manages one state file (one logical environment, e.g. networking-prod). Workspaces are grouped into projects for RBAC and at-a-glance ownership.
There are two execution modes for a workspace:
| Workflow | How runs start | State storage | Best for |
|---|---|---|---|
| VCS-driven | A push or PR to a connected Git repo | HCP Terraform | Teams wanting GitOps and PR-based plans |
| CLI-driven | terraform plan/apply from a laptop or CI | HCP Terraform | Migrating existing local workflows, scripting |
| API-driven | Custom tooling calling the Runs API | HCP Terraform | Bespoke automation, internal platforms |
In all three modes the actual plan and apply execute on HCP Terraform’s remote agents, not on your machine — so credentials and logs stay centralized and auditable.
Connecting with the cloud block
Modern Terraform (1.5+) and OpenTofu both use the cloud block to bind a working directory to a remote workspace. This replaces the older backend "remote" configuration.
terraform {
cloud {
organization = "devcraftly"
workspaces {
name = "networking-prod"
}
}
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.60"
}
}
}
provider "aws" {
region = "us-east-1"
}
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
tags = {
Name = "core-vpc"
Environment = "prod"
}
}
Authenticate once, then run Terraform as usual:
terraform login # stores an API token in ~/.terraform.d
terraform init # binds the working dir to the remote workspace
terraform plan
Output:
Running plan in HCP Terraform. Output will stream here.
Preparing the remote plan...
To view this run in a browser, visit:
https://app.terraform.io/app/devcraftly/networking-prod/runs/run-7Hq2xK9pLm
Terraform will perform the following actions:
# aws_vpc.main will be created
+ resource "aws_vpc" "main" {
+ cidr_block = "10.0.0.0/16"
+ enable_dns_hostnames = true
+ id = (known after apply)
}
Plan: 1 to add, 0 to change, 0 to destroy.
The
cloudblock is supported by OpenTofu as well, so you can point OpenTofu at HCP Terraform or a compatible backend without rewriting configuration. The Sentinel policy engine, however, is HashiCorp-specific — use OPA if you need a vendor-neutral policy layer.
Variables and variable sets
HCP Terraform stores two kinds of variables per workspace: Terraform variables (mapped to input variables in your config) and environment variables (exported into the run shell, ideal for provider credentials like AWS_ACCESS_KEY_ID). Either can be marked sensitive so the value is write-only and never displayed.
To avoid duplicating the same values across dozens of workspaces, define a variable set once and attach it to a project or selected workspaces. A typical pattern is one variable set holding cloud credentials and another holding shared tags. Better still, use dynamic provider credentials so HCP Terraform exchanges a short-lived OIDC token with AWS at run time instead of storing static keys.
variable "instance_count" {
type = number
description = "Number of app instances"
default = 2
}
You set instance_count and any credentials in the workspace UI or via the API — never committed to Git.
Run tasks and policy enforcement
A run task lets you call an external service between the plan and apply phases — for example a cost estimate, a security scan (Snyk, Wiz, Aqua), or a compliance gate. The task receives the plan, returns pass/fail/advisory, and can block the apply.
Policy as code runs inside HCP Terraform itself. A policy set is a collection of Sentinel or OPA policies attached to workspaces; every plan is evaluated against them before it can be applied.
# Sentinel: deny any S3 bucket that isn't encrypted
import "tfplan/v2" as tfplan
violations = filter tfplan.resource_changes as _, rc {
rc.type is "aws_s3_bucket_server_side_encryption_configuration" and
rc.change.actions contains "create" is false
}
main = rule { length(violations) is 0 }
A failed hard-mandatory policy stops the run; soft-mandatory policies can be overridden by an authorized user with a recorded reason.
When the managed platform is worth it
The free tier covers small teams (up to 500 managed resources) with remote state and runs. Paid tiers add Sentinel/OPA, SSO, audit logs, self-hosted agents, and drift detection. It is worth it when you need: a shared source of truth for state, PR-driven plans with approvals, centralized credentials, and policy gates — without operating that infrastructure yourself. If you already have a mature CI/CD platform and only need remote state, a plain S3 + DynamoDB backend may be enough; see the CI/CD overview to compare.
Best Practices
- Use one workspace per environment per component; keep state files small and blast radius narrow.
- Prefer dynamic provider credentials (OIDC) over storing long-lived cloud keys in variable sets.
- Centralize shared values in variable sets and mark every secret as sensitive.
- Enforce a baseline policy set (encryption, tagging, allowed regions) on all production workspaces.
- Require manual apply approval on production; let non-prod auto-apply for fast iteration.
- Pin
required_versionand provider versions so remote runs are reproducible. - Enable drift detection to catch out-of-band changes before they cause failed applies.