VCS Integration
Connect HCP Terraform กับ Git provider — auto plan ตอน PR, auto apply ตอน merge
Supported VCS
- GitHub (cloud + enterprise)
- GitLab (cloud + self-managed)
- Bitbucket (cloud + server)
- Azure DevOps (services + server)
Setup VCS Connection
GitHub
HCP → Organization Settings → VCS Providers → GitHub
└── Token: github_pat_xxx (from GitHub OAuth or Personal Access Token)
Connect
หรือใช้ GitHub App (recommended):
Add VCS Provider → GitHub.com (OAuth or App)
└── Install GitHub App on org/repo
GitHub App เด่นกว่า:
- Fine-grained permissions
- Per-repo access
- ไม่ต้องผูกกับ user account
GitLab
GitLab → User Settings → Applications → Add new application
└── Name: HCP Terraform
Redirect URI: https://app.terraform.io/auth/<provider-id>/callback
Scopes: api
Copy Application ID + Secret → HCP
Bitbucket Cloud
Bitbucket → Settings → OAuth consumers → Add consumer
└── Permissions: Repositories (read/admin), Webhooks (read/write)
Connect Workspace to VCS
Workspace → Settings → Version Control
└── VCS Provider: GitHub
Repository: myorg/infra
Branch: main
Working directory: ./prod/network
Trigger patterns: prod/network/**
Apply method: Auto / Manual
Triggers
Trigger on Push to Branch
ทุกครั้งที่ push ไป main (ที่มี file ใน working directory)
Trigger Patterns
trigger_patterns:
- prod/network/**
- shared/iam/**
- "!**.md" # exclude markdown
→ Push ที่แก้แค่ *.md → ไม่ trigger
Trigger on Pull Request
Workspace → Settings → Version Control
└── ☑ Automatic speculative plans
→ PR เปิด → speculative plan run → comment ใน PR
Speculative Plan
= "what if" plan โดยไม่ apply
PR opened → HCP runs `terraform plan` → comment:
"Plan: 3 to add, 0 to change, 0 to destroy"
"View run: https://app.terraform.io/..."
→ Reviewer เห็น diff ก่อน approve
Auto Apply Setup
Workspace → Settings → General
└── Apply method:
- Manual apply (default) ← prod
- Auto apply ← dev
Auto apply trigger:
- On successful plan
- On VCS push to main
Manual Apply Workflow
1. PR opened → speculative plan
2. Review plan in PR
3. Merge PR → main
4. HCP queues run with full plan
5. Reviewer clicks "Confirm & Apply"
6. Apply runs
Webhook Setup (Auto)
HCP จะ create webhook ใน VCS อัตโนมัติเมื่อ connect workspace
URL pattern:
https://app.terraform.io/webhooks/vcs/<workspace-id>
VCS push event → HCP receives webhook → triggers run
Multi-Workspace per Repo
infra/ # 1 repo
├── prod/
│ ├── network/ # workspace: prod-network
│ │ └── trigger_patterns: ["prod/network/**"]
│ ├── data/ # workspace: prod-data
│ │ └── trigger_patterns: ["prod/data/**"]
│ └── compute/ # workspace: prod-compute
│ └── trigger_patterns: ["prod/compute/**"]
└── staging/
└── ... (same)
→ แก้ prod/network/main.tf → trigger เฉพาะ prod-network workspace
Branch Strategy
Main-Only
Workspace 1: branch=main
→ Only main triggers
Feature Branch (Speculative)
Workspace 1: branch=main
└── Auto plan on PR (speculative)
→ PR creates speculative plan, merge triggers real run
Per-Branch Workspace
Workspace 1: branch=main → prod
Workspace 2: branch=develop → staging
Workspace 3: branch=feature/* → dev
→ Each branch deploys to different env
VCS-Driven Workflow
Working with Modules
Public Modules
ปกติใน workspace สามารถใช้ได้:
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.13.0"
}
Private Modules (HCP Registry)
module "vpc" {
source = "app.terraform.io/my-org/vpc/aws"
version = "1.0.0"
}
→ Module repo ก็ต้อง connect VCS เพื่อ publish
Publish Module
Module Registry → Publish → Connect VCS
└── Repository: myorg/terraform-aws-vpc
Tags become versions: v1.0.0 → 1.0.0
→ Push tag v1.1.0 → auto publish module version 1.1.0
Status Checks
GitHub PR shows:
✓ Terraform Cloud / prod-network — Plan finished
✗ Terraform Cloud / prod-data — Plan errored
→ Block merge if plan fails (require status checks ใน branch protection)
Branch Protection (GitHub)
Repo → Settings → Branches → Add Rule
└── Branch pattern: main
Require status checks to pass:
- Terraform Cloud / prod-network
- Terraform Cloud / prod-data
Require approvals: 1
Restrict who can push: platform-team
→ ป้องกัน merge ที่ plan fail
Conditional Run on Files Changed
Workspace → Settings → Version Control → Trigger Patterns:
- "prod/network/**"
- "modules/network/**" ← include shared module
- "!docs/**" ← exclude docs
→ Only run when relevant files change
VCS-Driven vs CLI-Driven
| Aspect | VCS-Driven | CLI-Driven |
|---|---|---|
| Trigger | Git push | terraform apply |
| Best for | Production | Dev / debugging |
| Audit trail | Git history + HCP logs | HCP logs only |
| Code review | Built-in (PR) | Manual |
| Speed | Slower (queue) | Faster (immediate) |
→ Production ใช้ VCS-driven, dev ใช้ CLI-driven
ตัวอย่าง: Setup with TFE Provider
provider "tfe" {
organization = "my-org"
}
data "tfe_oauth_client" "github" {
service_provider = "github"
}
resource "tfe_workspace" "prod_network" {
name = "prod-network"
organization = "my-org"
working_directory = "prod/network"
auto_apply = false # require manual approve
vcs_repo {
identifier = "myorg/infra"
branch = "main"
oauth_token_id = data.tfe_oauth_client.github.oauth_token_id
ingress_submodules = false
}
trigger_patterns = [
"prod/network/**",
"modules/network/**"
]
tag_names = ["prod", "network"]
}
Disconnect VCS
Workspace → Settings → Version Control → Disconnect
→ Workspace ใน CLI-driven mode
Best Practices
✅ DO:
- ใช้ VCS-driven สำหรับ production
- Use GitHub App แทน OAuth user (per-repo permissions)
- Branch protection + required status checks
- Trigger patterns specific (`prod/network/**`)
- Speculative plans on PR
- Manual approve for prod
❌ DON'T:
- ห้าม auto-apply ใน prod
- ห้าม connect VCS โดยใช้ user OAuth ของ admin
- ห้ามให้ workspace trigger ทุก path (run จะเยอะมาก)
- ห้าม skip status checks
ทางเลือก: GitOps Tools
ถ้าไม่ใช้ HCP:
- Atlantis — open-source, VCS-driven
- GitHub Actions — DIY
- GitLab CI — DIY
- Argo CD (สำหรับ K8s manifests)
สรุป
- VCS Integration = Git provider connect to HCP
- Triggers: push to branch, PR (speculative)
- Trigger patterns ระบุ files ที่จะ trigger
- Status checks + branch protection ใน VCS
- GitHub App > OAuth user (recommended)
- Production: VCS-driven + manual apply
ต่อไป → Run Tasks