Cloud  /  Terraform

IaC Terraform 50 guides · updated 2026

Infrastructure as code done right — providers, state, reusable modules, and the workflow patterns that keep multi-cloud deployments sane in 2026.

Terraform Cloud and Terraform Enterprise

HashiCorp offers two managed products built on top of Terraform: HCP Terraform (formerly Terraform Cloud, SaaS) and Terraform Enterprise (self-hosted). Both provide remote state storage, remote execution, team access controls, policy enforcement, and a private module registry beyond what open-source Terraform offers.


HCP Terraform vs Terraform Enterprise

FeatureHCP Terraform (Free)HCP Terraform (Plus)Terraform Enterprise
Remote state
Remote execution
Private registry
Team managementLimited
Sentinel policies
Audit logging
SSO/SAML
Self-hosted
Custom agents
Air-gapped deployment

Connecting to HCP Terraform

Terminal window
# Log in to HCP Terraform (stores token in ~/.terraform.d/credentials.tfrc.json)
terraform login
# Verify login
terraform login --help
# Configure the cloud block in main.tf
terraform {
cloud {
organization = "mycompany"
workspaces {
name = "production-aws"
}
}
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
Terminal window
terraform init # Downloads providers, registers workspace
terraform plan # Runs remotely in HCP Terraform
terraform apply # Remote apply with approval workflow

Workspaces in HCP Terraform

Each workspace in HCP Terraform is a fully isolated unit with:

# Multiple workspaces via tags (target all workspaces matching a tag)
terraform {
cloud {
organization = "mycompany"
workspaces {
tags = ["production", "aws"] # Match workspaces with these tags
}
}
}

Managing workspace variables via Terraform:

# Use the tfe provider to manage HCP Terraform programmatically
provider "tfe" {
token = var.tfe_token
}
resource "tfe_workspace" "production" {
name = "production-aws"
organization = "mycompany"
terraform_version = "1.9.5"
execution_mode = "remote"
auto_apply = false # Require approval
tag_names = ["production", "aws"]
}
resource "tfe_variable" "aws_region" {
key = "TF_VAR_region"
value = "us-east-1"
category = "env"
workspace_id = tfe_workspace.production.id
}
resource "tfe_variable" "db_password" {
key = "TF_VAR_database_password"
value = var.database_password
category = "env"
sensitive = true
workspace_id = tfe_workspace.production.id
}

Sentinel Policy as Code

Sentinel (HCP Terraform Plus+) enforces policies before terraform apply runs:

sentinel/require-all-resources-tagged.sentinel
import "tfplan/v2" as tfplan
# Require all resources to have Environment and Team tags
main = rule {
all tfplan.resource_changes as _, changes {
all changes.change.after.tags as k, _ {
k in ["Environment", "Team", "CostCenter"]
}
}
}
# sentinel.hcl — policy set configuration
policy "require-all-resources-tagged" {
source = "./sentinel/require-all-resources-tagged.sentinel"
enforcement_level = "hard-mandatory" # Block apply on failure
}
policy "restrict-instance-types" {
source = "./sentinel/restrict-instance-types.sentinel"
enforcement_level = "soft-mandatory" # Warn but allow override
}

Enforcement levels:


Private Module Registry

Host internal modules in HCP Terraform’s private registry:

Terminal window
# Publish a module to the private registry
# Module must be in a git repo with naming convention:
# terraform-<provider>-<module>
# e.g., terraform-aws-networking, terraform-aws-ecs-service
# Reference a private registry module
module "networking" {
source = "app.terraform.io/mycompany/networking/aws"
version = "~> 2.0"
environment = var.environment
cidr_block = "10.0.0.0/16"
}

Private registry modules are:


Team Access Controls

resource "tfe_team" "platform" {
name = "platform-engineering"
organization = "mycompany"
}
resource "tfe_team" "developers" {
name = "developers"
organization = "mycompany"
}
# Platform team: admin on production
resource "tfe_team_access" "platform_production" {
access = "admin"
team_id = tfe_team.platform.id
workspace_id = tfe_workspace.production.id
}
# Developers: read + plan on production, write on staging
resource "tfe_team_access" "dev_production" {
access = "read"
team_id = tfe_team.developers.id
workspace_id = tfe_workspace.production.id
}
resource "tfe_team_access" "dev_staging" {
access = "write"
team_id = tfe_team.developers.id
workspace_id = tfe_workspace.staging.id
}

Run Triggers

Automatically start a downstream workspace when an upstream workspace successfully applies:

# When networking workspace applies, trigger application workspace
resource "tfe_run_trigger" "app_after_networking" {
workspace_id = tfe_workspace.application.id
sourceable_id = tfe_workspace.networking.id
}

This creates a dependency graph of workspaces — networking must apply before application, which must apply before database, etc. All managed in HCP Terraform without manual orchestration.