Chapter 11: Terraform Cloud & Enterprise#
π― Learning Objectives#
- Understand Terraform Cloud features and architecture
- Configure remote execution and state management
- Implement VCS-driven workflows
- Use Sentinel policy as code
- Manage workspaces and teams in Terraform Cloud
11.1 What is Terraform Cloud?#
Terraform Cloud is HashiCorp’s managed service that provides:
- Remote state management
- Team collaboration
- Policy as code (Sentinel)
- VCS integration (GitHub, GitLab, etc.)
- Private module registry
- Run tasks and cost estimation
Terraform Cloud vs Open Source#
| Feature | Open Source | Terraform Cloud | Terraform Enterprise |
|---|---|---|---|
| State management | Local/S3/etc. | Managed remote | Managed remote |
| Team collaboration | Manual | Built-in | Built-in |
| VCS integration | Manual | Automatic | Automatic |
| Sentinel policies | β | Limited | β Full |
| Private module registry | β | β | β |
| Cost estimation | β | β | β |
| SSO/SAML | β | β | β |
| Audit logging | β | β | β |
| Run tasks | β | β | β |
| Self-hosted | β | β | β |
11.2 Terraform Cloud Architecture#
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Your VCS (GitHub/GitLab) β
ββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββ
β Push/Pull Request
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Terraform Cloud β
β β
β ββββββββββββ ββββββββββββ ββββββββββββ ββββββββββββββ β
β β Workspaceβ β Runs β β State β β Policies β β
β β (Dev) β β β β (Shared)β β (Sentinel) β β
β ββββββββββββ€ ββββββββββββ€ ββββββββββββ€ ββββββββββββββ€ β
β β Workspaceβ β Runs β β State β β Policies β β
β β (Prod) β β β β (Shared)β β (Sentinel) β β
β ββββββββββββ ββββββββββββ ββββββββββββ ββββββββββββββ β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β API / CLI ββ
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ11.3 Remote State in Terraform Cloud#
Free Tier State Storage#
# main.tf
terraform {
cloud {
organization = "my-company"
workspaces {
name = "my-app-production"
}
}
}Using Remote State from Other Workspaces#
# Read outputs from another workspace
data "terraform_remote_state" "vpc" {
backend = "remote"
config = {
organization = "my-company"
workspaces = {
name = "vpc-production"
}
}
}
resource "aws_instance" "web" {
subnet_id = data.terraform_remote_state.vpc.outputs.public_subnet_ids[0]
}11.4 VCS-Driven Workflow#
Connecting VCS#
# Link a workspace to a VCS repo
# In Terraform Cloud UI:
# 1. Settings β Version Control β Connect to VCS
# 2. Select repository
# 3. Configure working directoryPull Request Workflow#
Developer creates PR
β
Terraform Cloud runs `terraform plan`
β
Plan comment posted on PR
β
Team reviews PR + plan
β
PR merged to main branch
β
Terraform Cloud runs `terraform apply`
β
Infrastructure updatedSpeculatives Plans#
# Trigger a speculative plan on a PR
# Terraform Cloud automatically creates a plan
# Plan output is posted as a PR comment
# Plan is NOT applied until merge11.5 Workspace Configuration in Terraform Cloud#
Workspace Types#
# CLI-driven workspace
terraform {
cloud {
organization = "my-company"
workspaces {
name = "my-app-dev"
}
}
}
# VCS-driven workspace (set in cloud UI)
# Workspace connected to GitHub repo
# Auto-triggers on push to specific branchWorkspace Variables#
# Terraform variables are set in workspace UI or API
# Two types:
# 1. Terraform variables (Terraform inputs)
# 2. Environment variables (for providers, etc.)
# In workspace UI:
# Key: AWS_ACCESS_KEY_ID
# Value: AKIAIOSFODNN7EXAMPLE
# Type: Environment Variable (sensitive)
# Key: instance_type
# Value: t2.micro
# Type: Terraform VariableWorkspace Settings#
# Workspace execution mode
# - Local: Runs on your machine
# - Remote: Runs on Terraform Cloud
# - Agent: Runs on self-hosted agent
# Workspace terraform version
# - Version specified or "latest"11.6 Remote Execution#
Local vs Remote Execution#
# Local execution (default for CLI-driven)
terraform {
cloud {
organization = "my-company"
workspaces {
name = "my-app-local"
}
# Default: Runs plan locally, state stored in cloud
}
}# Running locally
terraform plan # Reads remote state, plans locally
terraform apply # Applies locally, state stored in cloud# Remote execution
# Set in workspace settings: Execution Mode = "Remote"
# All runs happen on Terraform Cloud servers# With remote execution:
# terraform plan/apply runs on Terraform Cloud
# No local credentials needed!11.7 Sentinel Policy as Code#
Sentinel is HashiCorp’s policy-as-code framework.
Policy Structure#
# policy/require-approval.sentinel
import "tfplan"
import "strings"
# Require all resources to have mandatory tags
mandatory_tags = ["Environment", "Owner", "CostCenter"]
# Get all resources that support tags
all_resources = filter tfplan.resource_changes as _, rc {
rc.mode is "managed" and strings.has_prefix(rc.type, "aws_")
}
# Check each resource
main = rule {
all all_resources as _, rc {
all mandatory_tags as tag {
rc.change.after.tags contains tag
}
}
}Policy Types#
| Policy | Scope | Example |
|---|---|---|
| Hard mandatory | Cannot be overridden | “Block all public S3 buckets” |
| Soft mandatory | Can be overridden with reason | “Require tags on all resources” |
| Advisory | Informational only | “Suggest using encryption” |
Common Sentinel Policies#
# 1. Restrict allowed regions
import "tfplan"
allowed_regions = ["us-east-1", "us-west-2", "eu-west-1"]
providers = filter tfplan.providers as _, p {
p.type is "aws"
}
main = rule {
all providers as _, p {
p.config.region in allowed_regions
}
}
# 2. Block public S3 buckets
import "tfplan"
s3_buckets = filter tfplan.resource_changes as _, rc {
rc.type is "aws_s3_bucket_public_access_block"
}
main = rule {
all s3_buckets as _, bucket {
bucket.change.after.block_public_acls is true and
bucket.change.after.block_public_policy is true
}
}
# 3. Enforce cost limits
import "tfplan"
ec2_instances = filter tfplan.resource_changes as _, rc {
rc.type is "aws_instance"
}
main = rule {
all ec2_instances as _, instance {
instance.change.after.instance_type not in ["m5.24xlarge", "m5.12xlarge"]
}
}11.8 Private Module Registry#
Terraform Cloud provides a private module registry for sharing modules within your organization.
Publishing Modules#
# Steps to publish a module:
# 1. Create a GitHub repo named terraform-<PROVIDER>-<NAME>
# 2. Push with git tags (v1.0.0, etc.)
# 3. Add to Terraform Cloud registry# Using a private module
module "vpc" {
source = "app.terraform.io/my-company/vpc/aws"
version = "1.2.0"
name = "my-vpc"
cidr = "10.0.0.0/16"
}Module Version Constraints#
module "vpc" {
source = "app.terraform.io/my-company/vpc/aws"
version = "~> 1.0" # >= 1.0, < 2.0
}11.9 Run Tasks#
Run tasks integrate third-party services into the Terraform Cloud workflow.
# Examples:
# - Checkov: Security scanning
# - Infracost: Cost estimation
# - tfsec: Security linting
# - Custom webhook integrationsAPI-Driven Run Tasks#
# A run task makes an API call to a third-party service
# Service returns pass/fail/error result
# Result appears in the Terraform Cloud run UI11.10 Terraform Cloud Teams and Permissions#
Team Structure#
| Team | Permissions | Responsibilities |
|---|---|---|
| Owners | Full access | Manage organization, billing |
| Admins | Manage workspaces | Configure VCS, variables |
| Writers | Plan and apply | Deploy infrastructure |
| Readers | Read-only | View state and plans |
| Plan-only | Plan only | View plans, no apply |
Team-Based Workspace Access#
# Managed in Terraform Cloud UI
# Assign teams to workspaces with permissions:
# - Read
# - Plan
# - Write
# - Admin11.11 Cost Estimation#
Terraform Cloud provides cost estimation on each plan.
# Cost estimation shows:
# - Monthly cost of new resources
# - Monthly cost change from current state
# - Per-resource cost breakdown# Cost estimation appears in the plan output
# Example:
# Resource changes: +5 to create, 0 to change, 0 to destroy
# Monthly cost: +$234.56 (if applied)11.12 API and CLI Integration#
TFE Provider#
# Manage Terraform Cloud resources with Terraform!
provider "tfe" {
hostname = var.tfc_hostname # app.terraform.io or custom
token = var.tfc_token
}
# Create a workspace
resource "tfe_workspace" "production" {
name = "my-app-production"
organization = tfe_organization.my_org.name
execution_mode = "remote"
vcs_repo {
identifier = "my-company/my-app"
branch = "main"
oauth_token_id = tfe_oauth_client.github.oauth_token_id
}
}
# Create a variable
resource "tfe_variable" "instance_type" {
workspace_id = tfe_workspace.production.id
key = "instance_type"
value = "t3.large"
category = "terraform"
}
# Create an environment variable
resource "tfe_variable" "aws_access_key" {
workspace_id = tfe_workspace.production.id
key = "AWS_ACCESS_KEY_ID"
value = var.aws_access_key
category = "env"
sensitive = true
}
# Create an organization
resource "tfe_organization" "my_org" {
name = "my-company"
email = "admin@my-company.com"
}11.13 Migration to Terraform Cloud#
Migrating from State File#
# 1. Add cloud block to configuration
# 2. Run init with migration
terraform init -migrate-state
# Terraform will:
# - Ask for workspace name
# - Copy state to Terraform Cloud
# - Update local configurationMigrating from S3 Backend#
# Before: S3 backend
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "prod/terraform.tfstate"
}
}
# After: Terraform Cloud
terraform {
cloud {
organization = "my-company"
workspaces {
name = "my-app-prod"
}
}
}# Migrate existing state to Terraform Cloud
terraform init -migrate-state11.14 Terraform Enterprise#
Terraform Enterprise is the self-hosted version of Terraform Cloud.
When to Use Terraform Enterprise#
- Air-gapped environments (no internet access)
- Compliance requirements (data residency)
- Custom integrations
- Enterprise SSO requirements
- Audit requirements
Deployment Options#
| Environment | Method | Requirements |
|---|---|---|
| AWS | EC2 + RDS + S3 | AWS account |
| Azure | Azure VM + DB + Storage | Azure subscription |
| VMware | vSphere VM | vSphere environment |
| Docker | Docker containers | Docker hosts |
| Kubernetes | Helm chart | Kubernetes cluster |
π Exam Tips#
- Terraform Cloud manages state β No more manual S3 configuration
- VCS-driven workflow β Plan on PR, apply on merge
- Sentinel β Policy as code for governance
- Private module registry β Share modules within organization
- Cost estimation β See cost impact before applying
- Run tasks β Integrate third-party tools (Checkov, Infracost)
- Remote execution β Run Terraform on Cloud servers
- Team permissions β Control who can plan/apply
- Cloud block replaces backend block β For Terraform Cloud
- Free tier β Includes 5 users, state storage, and more
β Chapter 11 Quiz#
-
What are the two variable types in Terraform Cloud workspaces?
- a) Terraform variables and Environment variables
- b) Input variables and Output variables
- c) String variables and Number variables
- d) Sensitive and Public
-
What is Sentinel?
- a) A Terraform provider
- b) A policy as code framework
- c) A state backend
- d) A module registry
-
True or False: Speculative plans are applied automatically.
-
What happens when a VCS pull request is opened for a connected workspace?
- a) Terraform applies the changes
- b) Terraform creates a speculative plan
- c) Nothing β manual trigger required
- d) The PR is automatically merged
-
Which TFE resource would you use to create a workspace programmatically?
- a)
tfe_workspace - b)
tfe_org - c)
tfe_variable - d)
tfe_run
- a)
π Answers
- a β Terraform variables and Environment variables
- b β Sentinel is HashiCorp’s policy-as-code framework
- False β Speculative plans show what would happen but are not applied
- b β Terraform Cloud creates a speculative plan (does not apply)
- a β
tfe_workspacecreates a workspace programmatically
Continue to β Chapter 12: Importing, Refactoring & State Migrations