Temporal Terraform Orchestrator
A Temporal-based workflow orchestration system for managing multi-workspace Terraform deployments with dependency resolution, variable passing between workspaces, and MCP server integration for AI-driven automation.
Table of Contents
- Overview
- Architecture
- Prerequisites
- Quick Start
- CLI Starter
- MCP Server
- Configuration Reference (
infra.yaml) - Testing
- Repository Layout
- Troubleshooting
Overview
This project provides a robust infrastructure-as-code orchestration layer using Temporal workflows to manage Terraform operations across multiple workspaces with:
- Dependency management: Define workspace dependencies and the system executes them in the correct order
- Output propagation: Pass Terraform outputs from one workspace as inputs to dependent workspaces
- Parallel execution: Independent workspaces run concurrently for faster deployments
- Durability: Temporal provides automatic retries, state persistence, and failure recovery
- AI integration: MCP server enables AI agents to trigger and monitor infrastructure deployments
ParentWorkflow (Orchestrator)
│
├─> TerraformWorkflow (vpc) ← runs first (no dependencies)
│
├─> TerraformWorkflow (vpc-2) ← runs in parallel with vpc
│
├─> TerraformWorkflow (subnets) ← waits for vpc, receives vpc_id output
│
└─> TerraformWorkflow (eks) ← waits for vpc + subnets, receives both outputs
Architecture
Workflow Components
ParentWorkflow: The orchestrator that:
- Validates and normalizes the configuration
- Builds a dependency DAG (Directed Acyclic Graph)
- Starts root workspaces (those with no dependencies) immediately
- Listens for completion signals and starts dependent workspaces when ready
- Propagates outputs between workspaces based on input mappings
TerraformWorkflow: Executes Terraform operations for a single workspace:
terraform init- Initialize the workspaceterraform plan- Create execution plan (with-detailed-exitcodeto detect changes)terraform show -json- Validate the plan outputterraform apply- Apply changes (skipped if no changes detected)terraform output -json- Capture outputs for downstream workspaces- Signals completion back to ParentWorkflow
- Enters "hosting mode" to spawn child workflows for nested dependencies
Hosting Architecture
Child workflows are spawned as nested children of their "host" workflow (the deepest dependency). This creates a natural hierarchy where:
- Root workspaces are direct children of ParentWorkflow
- Dependent workspaces become children of their host workflow
- All workflows signal completion back to the ParentWorkflow orchestrator
Prerequisites
- Go 1.23+
- Terraform CLI >= 1.5 - Available on PATH
- Temporal Server - Running at default address
localhost:7233(or setTEMPORAL_ADDRESS) - AWS Credentials - If using real AWS resources (the examples use mock outputs)
Quick Start
-
Install dependencies:
go mod tidy -
Start Temporal (if not already running):
temporal server start-dev -
Start the worker:
go run ./cmd/worker -
Execute the workflow:
go run ./cmd/starter -config infra.yaml -
Monitor execution in the Temporal Web UI at
http://localhost:8233
CLI Starter
The CLI starter (cmd/starter) initiates workflow execution from a YAML configuration file.
Usage
go run ./cmd/starter [flags]
Flags
| Flag | Default | Description |
|---|---|---|
-config | infra.yaml | Path to the infrastructure configuration file |
-task-queue | terraform-task-queue | Temporal task queue name |
-workflow-id | terraform-parent-workflow | Custom workflow ID for tracking |
Examples
# Run with default settings
go run ./cmd/starter
# Specify a custom config file
go run ./cmd/starter -config ./environments/production.yaml
# Use a custom workflow ID for tracking
go run ./cmd/starter -config infra.yaml -workflow-id "deploy-prod-2024-01-15"
Behavior
- Reads and parses the YAML configuration file
- Validates the configuration (checks for cycles, missing dependencies, etc.)
- Normalizes paths relative to
workspace_root - Starts the ParentWorkflow via Temporal
- Waits for workflow completion and reports success/failure
MCP Server
The MCP (Model Context Protocol) server enables AI agents and automation tools to interact with the orchestration system.
Starting the Server
go run ./cmd/mcp-server
The server runs on stdio and communicates via JSON-RPC, following the MCP specification.
Available Tools
list_workflows
Lists available workflows and configured workspaces from the configuration file.
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
config_path | string | No | infra.yaml | Path to YAML config file |
Response example:
{
"config_path": "infra.yaml",
"workspace_root": ".",
"workflows": [
{
"name": "ParentWorkflow",
"description": "Orchestrates terraform operations across multiple workspaces with dependencies",
"configured_workspaces": [
{
"name": "vpc",
"kind": "terraform",
"dir": "/abs/path/vpc",
"dependsOn": []
},
{
"name": "subnets",
"kind": "terraform",
"dir": "/abs/path/subnets",
"dependsOn": ["vpc"]
}
],
"workspace_count": 2
}
]
}
execute_workflow
Starts a Terraform orchestration workflow.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
workflow_name | string | Yes | Must be ParentWorkflow |
config_path | string | No* | Path to YAML config file |
config | object | No* | Inline configuration payload (JSON) |
*Either config_path or config must be provided.
Response example:
Workflow started successfully.
WorkflowID: terraform-parent-workflow-12345
RunID: abc123-def456-ghi789
get_workflow_status
Gets the status of a running or completed workflow.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
workflow_id | string | Yes | The workflow ID to check |
Response example:
Workflow: terraform-parent-workflow-12345
Status: WORKFLOW_EXECUTION_STATUS_COMPLETED
Started At: 2024-01-15 10:30:00
Finished At: 2024-01-15 10:35:42
Integration with AI Agents
The MCP server is designed for integration with AI coding assistants (like Cursor, Claude, etc.). Add it to your MCP configuration:
{
"mcpServers": {
"temporal-terraform": {
"command": "/path/to/mcp-server",
"args": []
}
}
}
Configuration Reference (infra.yaml)
The configuration file defines your infrastructure workspaces and their relationships.
Complete Schema
# Base path for resolving relative directories (optional)
workspace_root: '.'
# List of workspaces to orchestrate
workspaces:
- name: string # Required: Unique workspace identifier
kind: string # Optional: "terraform" (default and only supported value)
dir: string # Required: Path to Terraform directory
tfvars: string # Optional: Path to .tfvars file
dependsOn: [string] # Optional: List of workspace names this depends on
inputs: [InputMapping] # Optional: Variable mappings from dependencies
operations: [string] # Optional: Operations to run (default: [init, validate, plan, apply])
taskQueue: string # Optional: Override the Temporal task queue
Input Mapping Schema
inputs:
- sourceWorkspace: string # Name of the dependency workspace
sourceOutput: string # Name of the Terraform output to read
targetVar: string # Name of the Terraform variable to set
Complete Example
workspace_root: .
workspaces:
# VPC workspace - no dependencies, runs first
- name: vpc
kind: terraform
dir: terraform/examples/vpc
tfvars: terraform/examples/vpc/vpc.tfvars
dependsOn: []
taskQueue: terraform-task-queue
# Second VPC - independent, runs in parallel with first
- name: vpc-2
kind: terraform
dir: terraform/examples/vpc-2
tfvars: terraform/examples/vpc-2/vpc.tfvars
dependsOn: []
taskQueue: terraform-task-queue
# Subnets - depends on VPC, receives vpc_id output
- name: subnets
kind: terraform
dir: terraform/examples/subnets
tfvars: terraform/examples/subnets/subnets.tfvars
dependsOn:
- vpc
inputs:
- sourceWorkspace: vpc
sourceOutput: vpc_id
targetVar: vpc_id
taskQueue: terraform-task-queue
# EKS - depends on both VPC and subnets, receives outputs from both
- name: eks
kind: terraform
dir: terraform/examples/eks
tfvars: terraform/examples/eks/eks.tfvars
dependsOn:
- vpc
- subnets
inputs:
- sourceWorkspace: vpc
sourceOutput: vpc_id
targetVar: vpc_id
- sourceWorkspace: subnets
sourceOutput: subnet_ids
targetVar: subnet_ids
Key Concepts
Workspace Dependencies (dependsOn)
- Define execution order constraints
- Multiple dependencies create AND conditions (all must complete)
- Independent workspaces (empty or no
dependsOn) run in parallel - Cycles are detected and rejected during validation
Output to Input Propagation (inputs)
The inputs array maps Terraform outputs from dependency workspaces to variables in the current workspace:
# In the subnets workspace config
inputs:
- sourceWorkspace: vpc # Get output from 'vpc' workspace
sourceOutput: vpc_id # Read the 'vpc_id' output
targetVar: vpc_id # Pass as -var vpc_id=<value>
This allows you to:
- Chain infrastructure components together
- Pass resource IDs between workspaces
- Build complex dependency graphs
Transitive Dependencies
Input mappings support transitive dependencies. For example, if C depends on B, and B depends on A, then C can map outputs from both B AND A:
workspaces:
- name: a
dir: ./a
- name: b
dir: ./b
dependsOn: [a]
- name: c
dir: ./c
dependsOn: [b]
inputs:
- sourceWorkspace: a # Valid: 'a' is a transitive dependency
sourceOutput: some_output
targetVar: from_a
- sourceWorkspace: b # Valid: 'b' is a direct dependency
sourceOutput: other_output
targetVar: from_b
Operations Control
The operations field allows fine-grained control over which Terraform operations to run for each workspace:
operations: [init, validate, plan, apply] # Full apply mode (default)
operations: [init, validate, plan] # Plan-only mode (no apply)
Valid operations:
init- Initialize the Terraform workspace (required)validate- Validate Terraform configuration (required)plan- Generate execution planapply- Apply changes to infrastructure
Requirements:
initandvalidateare always required- Operations must be specified in order:
init→validate→plan→apply applyrequiresplanto be present
Use cases:
- Plan-only mode: Set
operations: [init, validate, plan]for review/approval workflows - Full apply mode: Set
operations: [init, validate, plan, apply]for automatic deployments (default)
Path Resolution
workspace_root: Base path for resolving relative paths- Relative paths in
dirandtfvarsare joined withworkspace_root - Absolute paths are used as-is
- The current working directory is used if
workspace_rootis empty
Testing
Run all tests:
go test ./...
Test Coverage
- Config validation: Cycle detection, duplicate names, missing dependencies, input mapping validation
- Parent workflow: Execution order, dependency waiting, signal handling
- Activities: Uses a shim Terraform binary that simulates CLI behavior
The tests use a fake Terraform binary that:
- Returns exit code 2 for
plan(simulating changes) - Creates plan files on disk
- Returns mock JSON for
outputandshowcommands
Repository Layout
.
├── activities/ # Terraform CLI wrapper activities
│ ├── terraform_activities.go # Init, Plan, Validate, Apply, Output
│ └── terraform_activities_test.go
├── cmd/
│ ├── mcp-server/ # MCP server for AI integration
│ ├── starter/ # CLI to start workflows
│ └── worker/ # Temporal worker process
├── terraform/examples/ # Sample Terraform workspaces
│ ├── vpc/
│ ├── vpc-2/
│ ├── subnets/
│ └── eks/
├── utils/ # Shared constants
├── workflow/ # Temporal workflow definitions
│ ├── config.go # Configuration types and validation
│ ├── parent_workflow.go # Orchestrator workflow
│ └── terraform_workflow.go # Per-workspace workflow
├── go.mod
├── go.sum
├── infra.yaml # Example configuration
└── README.md
Troubleshooting
Worker Connection Issues
Unable to create client: ...
Solution: Ensure Temporal server is running and accessible. Check TEMPORAL_ADDRESS if using a non-default location.
Workflow Fails Immediately
Invalid config: ...
Solution: Validate your infra.yaml:
- Check for duplicate workspace names
- Ensure all
dependsOnreferences exist - Verify there are no circular dependencies
- Confirm
inputsreference valid dependencies
Terraform Errors
terraform init failed: ...
Solutions:
- Ensure
terraformis on PATH - Verify the workspace
dirpath exists - Check for valid Terraform configuration in the directory
- For AWS resources, ensure credentials are configured
Plan File Not Found
plan file not found for apply: ...
Solution: This typically indicates terraform plan failed silently. Check:
- Directory permissions
- Terraform initialization state
- Provider configurations
MCP Server Not Responding
Solution: The MCP server runs on stdio. Ensure your client is configured to communicate via stdin/stdout, not HTTP.