Skip to content

Terraform Cloud — Remote Execution & Workspace Management Guide

DodaTech Updated 2026-06-24 6 min read

In this tutorial, you'll learn about Terraform Cloud. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

Terraform Cloud (TFC) is HashiCorp's managed service for Terraform that provides remote state storage, remote plan/apply execution, VCS-driven workflows, policy enforcement with Sentinel, and team-based access controls.

What You'll Learn

Why It Matters

Running Terraform from local machines creates bottlenecks — state is locked per-user, plans are invisible to the team, and audit trails require manual setup. Terraform Cloud provides a centralized platform where teams run Terraform remotely, review plans before applying, enforce policies, and maintain a complete audit history. DodaTech manages 200+ workspaces across 5 cloud providers using Terraform Cloud, enabling 30+ engineers to collaborate on infrastructure safely.

Real-World Use

DodaZIP's platform team uses Terraform Cloud workspaces per environment (dev, staging, production) and per component (networking, databases, compute). Every Pull Request triggers a speculative plan visible to the team. Production applies require at least two approvals via Terraform Cloud's run reviews.

flowchart TD
    A[Git Push] --> B[VCS Connection]
    B --> C[Terraform Cloud]
    C --> D[Workspace: prod-networking]
    C --> E[Workspace: prod-database]
    C --> F[Workspace: prod-compute]
    D --> G[Speculative Plan]
    G --> H[Plan Review]
    H --> I{Approved?}
    I -->|YES| J[Remote Apply]
    I -->|NO| K[PR Blocked]
    J --> L[AWS / GCP / Azure]
    C --> M[Sentinel Policies]
    C --> N[Run Tasks]
    C --> O[State Versions]
    style C fill:#844FBA,color:#fff
â„šī¸ Info

Prerequisites: An Terraform understanding and HCL syntax. A Terraform Cloud account (free tier available).

Getting Started

# Install the Terraform CLI
sudo apt-get update && sudo apt-get install -y gnupg software-properties-common
wget -O- https://apt.releases.hashicorp.com/gpg | gpg --dearmor | sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt-get update && sudo apt-get install terraform

# Login to Terraform Cloud
terraform login

# Expected output:
# Terraform will request an API token for app.terraform.io
# Generate a token in TFC > User Settings > Tokens
# Enter a value: <your-token>
# Success! Terraform has obtained and saved an API token.

Remote Backend Configuration

# main.tf
terraform {
  cloud {
    organization = "dodatech"

    workspaces {
      name = "production-networking"
    }
  }
}

# Or use tags for workspace selection
terraform {
  cloud {
    organization = "dodatech"

    workspaces {
      tags = ["production", "networking"]
    }
  }
}

provider "aws" {
  region = "us-east-1"
}

Workspace Configuration

# variables.tf — mark sensitive variables
variable "aws_access_key" {
  description = "AWS access key"
  type        = string
  sensitive   = true
}

variable "aws_secret_key" {
  description = "AWS secret key"
  type        = string
  sensitive   = true
}

variable "instance_count" {
  description = "Number of EC2 instances"
  type        = number
  default     = 3
}

variable "environment" {
  description = "Environment name"
  type        = string
  validation {
    condition     = contains(["dev", "staging", "production"], var.environment)
    error_message = "Environment must be dev, staging, or production."
  }
}

Remote Execution

# Initialize with remote backend
terraform init

# Expected output:
# Initializing Terraform Cloud...
# Initializing provider plugins...
# Terraform has been successfully initialized!

# Plan (runs on TFC, not locally)
terraform plan

# Expected output:
# Running plan in Terraform Cloud. Output will stream here.
# ...
# Plan: 5 to add, 0 to change, 0 to destroy.

# Apply (runs on TFC)
terraform apply

# Expected output:
# Running apply in Terraform Cloud. Output will stream here.
# ...
# Apply complete! Resources: 5 added, 0 changed, 0 destroyed.

VCS Integration

# terraform.tfc.hcl — VCS branch configuration
# This file lives in your repository root

terraform {
  cloud {
    organization = "dodatech"

    workspaces {
      tags = ["production"]
    }
  }
}

Configure in TFC UI: Workspace > Settings > Version Control:

  • VCS Provider: GitHub
  • Repository: dodatech/Terraform-infra
  • Working Directory: networking/production
  • Trigger Patterns: networking/production/**/*.tf
  • Automatic Run Triggering: On push to main branch
  • Speculative Plans: On pull requests

Sentinel Policies

# policies/enforce-mandatory-tags.sentinel
import "tfplan"

mandatory_tags = ["Environment", "Owner", "CostCenter", "ManagedBy"]

all_resources = filter tfplan.resource_changes as _, rc {
    rc.mode == "managed" and
    rc.type not in ["null_resource", "terraform_data"]
}

violations = []

for all_resources as _, resource {
    for mandatory_tags as tag {
        if tag not in resource.applied.tags else null {
            violations = append(violations,
                resource.address + " is missing tag: " + tag)
        }
    }
}

main = rule {
    length(violations) == 0
}
# policies/restrict-instance-types.sentinel
import "tfplan"

allowed_instance_families = ["t3", "m6i", "r6g", "c6i"]

compute_resources = filter tfplan.resource_changes as _, rc {
    rc.type in ["aws_instance", "aws_launch_template"]
}

for compute_resources as _, resource {
    instance_type = resource.applied.instance_type else resource.drifted.instance_type

    family = split(instance_type, ".")[0]

    if family not in allowed_instance_families {
        print(resource.address + " uses " + instance_type + " (not allowed)")
        main = false
    }
}

main = rule { main is true }

Run Tasks

# Configure Run Task in TFC UI:
# Settings > Run Tasks > Create

# Example: Infracost cost estimation run task
runTask:
  name: Infracost
  url: https://infracost-api.dodatech.com/tfc-task
  category: pre_plan
  hmac_key: your-hmac-secret

# Example: Checkov security scanning run task
runTask:
  name: Checkov
  url: https://checkov.dodatech.com/tfc-task
  category: pre_apply
  hmac_key: your-hmac-secret

Team and Access Management

# teams.tf — manage teams via Terraform
resource "tfe_team" "platform" {
  name         = "platform-engineers"
  organization = "dodatech"
}

resource "tfe_team" "security" {
  name         = "security-engineers"
  organization = "dodatech"
}

resource "tfe_team_access" "platform_prod" {
  access       = "write"
  team_id      = tfe_team.platform.id
  workspace_id = tfe_workspace.production.id
}

resource "tfe_team_access" "security_prod" {
  access       = "plan"
  team_id      = tfe_team.security.id
  workspace_id = tfe_workspace.production.id
}

Common Configuration Mistakes

  1. Not using speculative plans on PRs: Without speculative plans, pull requests don't show infrastructure changes. Enable VCS-driven speculative plans in workspace settings.

  2. Running <a href="/devops/terraform/">Terraform</a> apply from CLI without review: Remote execution bypasses Terraform Cloud's run review process. Use TFC UI or API for production applies with required approvals.

  3. Mixing local and remote state across workspaces: Once a workspace uses remote execution, all operations must go through Terraform Cloud. Running <a href="/devops/terraform/">Terraform</a> apply locally on a TFC-managed workspace causes state conflicts.

  4. Not configuring cost estimation tags: Without mandatory tags, the team cannot attribute infrastructure costs. Enforce tagging with Sentinel policies.

  5. Ignoring run task failures: Run tasks (security scanning, cost estimation) provide pre-apply validation. Treat their failures as blocking, not advisory.

Practice Questions

  1. What is the difference between Terraform Cloud and Terraform Enterprise? Answer: Terraform Cloud is HashiCorp's SaaS offering. Terraform Enterprise is self-hosted for private cloud/air-gapped environments. Both share the same feature set.

  2. How does remote execution differ from local execution? Answer: Remote execution runs <a href="/devops/terraform/">Terraform</a> plan and apply on Terraform Cloud's infrastructure. Local CLI streams output but does not execute. This enables run reviews, audit logs, and policy enforcement.

  3. What are Sentinel policies used for? Answer: Sentinel is a policy-as-code framework that enforces rules before Terraform creates resources — tagging requirements, allowed instance types, security group rules, cost limits.

  4. How do workspaces relate to environments? Answer: Each workspace has its own state, variables, and execution history. Teams typically create one workspace per environment per component (e.g., production-networking, staging-database).

Challenge

Set up a complete Terraform Cloud organization: configure VCS integration for a GitHub Repository, create workspaces for dev, staging, and production with separate variable sets and AWS credentials, write Sentinel policies enforcing mandatory tags and restricting instance families, configure a run task for Infracost cost estimation, set up team access (platform: write, security: plan, developers: read), enable speculative plans on PRs, and require at least one approval for production applies.

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro