Run Tasks
Run Tasks = integrate third-party services (security, cost, compliance) ระหว่าง plan-apply ของ HCP Terraform
Run Tasks คืออะไร?
ทุกครั้งที่ HCP run plan/apply — เรียก external HTTP service:
ทำไมใช้ Run Tasks?
- 🔍 Security scan ก่อน apply (Snyk, Bridgecrew, Wiz, Aqua)
- 💰 Cost estimation (Infracost Cloud)
- 📊 Drift analysis (Lightlytics)
- 🛡️ Compliance check (custom internal tools)
- 🔐 Secrets scan (custom)
→ Pluggable extension points
Tier Availability
| Tier | Run Tasks |
|---|---|
| Free | ❌ |
| Standard | ✅ |
| Plus | ✅ |
| Enterprise | ✅ |
Add Run Task
Organization Settings → Run Tasks → Create Run Task
└── Name: snyk-security
Description: Snyk vulnerability scan
Endpoint URL: https://api.snyk.io/v1/...
HMAC Key: ***
Category: pre-apply / post-plan
Apply to Workspace
Workspace → Settings → Run Tasks → Add
└── Run Task: snyk-security
Enforcement: Mandatory / Advisory
Stage: After Plan / Before Apply
Enforcement Levels
Advisory
- Run task runs
- Result shown in UI
- Apply NOT blocked
- ใช้ตอน: ทดลองใช้ tool ใหม่
Mandatory
- Run task runs
- ถ้า fail → block apply
- ใช้ตอน: critical security/compliance
Run Task Lifecycle
1. Plan complete in HCP
2. HCP POST plan.json to run task endpoint (signed with HMAC)
3. Run task processes (sync or async)
4. Run task POST result back to HCP callback URL
5. HCP shows result in UI
6. If failed + mandatory → block apply
Pre-Built Integrations
Snyk (Security)
Settings → Run Tasks → Add Snyk
└── (Pre-configured template)
→ Snyk scans Terraform code + IaC misconfig
Bridgecrew (Compliance)
Add Run Task → Bridgecrew/Prisma Cloud
→ 750+ Checkov policies + cloud account context
Infracost Cloud
Add Run Task → Infracost
→ Cost estimation + cost policies
Wiz (CSPM)
Add Run Task → Wiz
→ Cloud Security Posture Management
Aqua / Bridgecrew / Snyk = built-in templates
Custom Run Task
ถ้า third-party service ไม่ available — สร้างเอง:
custom-run-task/app.py (Flask example)
from flask import Flask, request, jsonify
import hmac
import hashlib
import os
import requests
app = Flask(__name__)
HMAC_KEY = os.environ["HMAC_KEY"]
def verify_hmac(request):
signature = request.headers.get('X-TFC-Task-Signature')
body = request.get_data()
expected = hmac.new(
HMAC_KEY.encode(),
body,
hashlib.sha512
).hexdigest()
return hmac.compare_digest(signature, expected)
@app.route('/run-task', methods=['POST'])
def run_task():
if not verify_hmac(request):
return jsonify({"error": "Invalid signature"}), 401
data = request.get_json()
plan_url = data["plan_json_api_url"]
callback_url = data["task_result_callback_url"]
access_token = data["access_token"]
# Fetch plan
plan_resp = requests.get(
plan_url,
headers={"Authorization": f"Bearer {access_token}"}
)
plan = plan_resp.json()
# Custom logic — check plan
issues = check_plan(plan)
status = "failed" if issues else "passed"
# Callback to HCP
requests.patch(callback_url, json={
"data": {
"type": "task-results",
"attributes": {
"status": status,
"message": f"Found {len(issues)} issues",
"url": "https://my-internal-tool.example.com/results/..."
}
}
}, headers={
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/vnd.api+json"
})
return jsonify({"status": "received"}), 200
def check_plan(plan):
issues = []
for change in plan.get("resource_changes", []):
if change["type"] == "aws_s3_bucket":
after = change.get("change", {}).get("after", {})
if after.get("acl") in ["public-read", "public-read-write"]:
issues.append(f"Public S3 bucket: {change['address']}")
return issues
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8080)
Run Task UI Output
Run Tasks:
✓ Infracost - Monthly cost: +$45.81
✓ Bridgecrew - 0 critical issues found
✗ Snyk - 2 high severity vulnerabilities (BLOCKED)
Apply: BLOCKED (Snyk failed)
Run Task Stages
Workspace → Settings → Run Tasks
└── Snyk: pre-plan / post-plan / pre-apply / post-apply
| Stage | When | Use Case |
|---|---|---|
| pre-plan | Before plan | Validate config |
| post-plan | After plan | Security scan |
| pre-apply | Before apply | Final check |
| post-apply | After apply | Notification |
Tag-Based Run Tasks
Run Task → Apply to:
- All workspaces
- Specific workspaces
- By tag: prod
→ Mandatory ใน prod, advisory ใน dev
ตัวอย่าง: Production Setup
Organization: my-bank
Run Tasks:
├── snyk-security (pre-apply, mandatory, all workspaces)
├── infracost (post-plan, advisory, all workspaces)
├── internal-compliance (pre-apply, mandatory, prod workspaces)
└── pagerduty-notify (post-apply, advisory, prod workspaces)
→ Apply prod requires Snyk + internal compliance pass
API: Manage Run Tasks
# List run tasks
curl https://app.terraform.io/api/v2/organizations/my-org/tasks \
-H "Authorization: Bearer $TOKEN"
# Create
curl -X POST https://app.terraform.io/api/v2/organizations/my-org/tasks \
-H "Authorization: Bearer $TOKEN" \
-d '{
"data": {
"type": "tasks",
"attributes": {
"name": "my-task",
"url": "https://my-task-server.com/webhook",
"hmac_key": "xxx",
"category": "task"
}
}
}'
Manage Run Tasks via Terraform
resource "tfe_organization_run_task" "snyk" {
organization = "my-org"
name = "snyk-security"
url = "https://api.snyk.io/v1/run-task/..."
hmac_key = var.snyk_hmac_key
category = "task"
enabled = true
}
resource "tfe_workspace_run_task" "snyk_prod" {
workspace_id = tfe_workspace.prod_app.id
task_id = tfe_organization_run_task.snyk.id
enforcement_level = "mandatory"
stage = "post_plan"
}
Best Practices
✅ DO:
- Start with advisory → graduate to mandatory
- Verify HMAC signature in custom run tasks
- Set timeout (run task ต้อง response ภายใน 10 min default)
- Document what each run task does
- Use tags for selective application
❌ DON'T:
- ห้าม block apply ทั้งหมดถ้า run task service ล่ม
- ห้าม skip HMAC verification
- ห้ามใช้ many mandatory tasks (ทำให้ apply ช้า)
Limitations
- Free tier — ❌ no run tasks
- Async only (sync: ส่ง response ภายใน 30s)
- Max 10 run tasks per workspace
- HMAC signature required
ตัวอย่าง: Common Stack
Workspace prod-app:
├── Pre-plan: TFLint check
├── Post-plan: Infracost cost diff
├── Pre-apply: Snyk security scan + Bridgecrew compliance
└── Post-apply: Slack notification + Datadog deployment marker
สรุป
- Run Tasks = third-party integration ใน HCP run lifecycle
- 4 stages: pre-plan, post-plan, pre-apply, post-apply
- 2 enforcement levels: advisory, mandatory
- Pre-built: Snyk, Bridgecrew, Infracost, Wiz, ฯลฯ
- Custom run task ผ่าน HTTP webhook + HMAC
- Standard tier+ feature (not free)
🎉 จบ Roadmap แล้ว!
ตอนนี้คุณรู้:
- ✅ IaC + Terraform fundamentals
- ✅ HCL syntax + resources + variables + outputs
- ✅ Workflow: init → plan → apply → destroy
- ✅ State management (most important!)
- ✅ Modules + reusable patterns
- ✅ Provisioners + data sources
- ✅ CI/CD + testing
- ✅ Scaling: split state, Terragrunt, Infracost
- ✅ Security: Vault, Sentinel, Checkov, Trivy
- ✅ HCP Terraform Cloud features
Next Steps
- ลงมือทำจริง — สร้าง project + apply S3 bucket แรก
- Build a Module — เริ่มจาก simple module (security group)
- Setup Remote Backend — S3 + DynamoDB
- Add CI/CD — GitHub Actions plan in PR
- Add Security Scan — Checkov ใน pre-commit
- Try HCP Free Tier — สำหรับ project ขนาดกลาง
แหล่งเรียนรู้ต่อ
- Terraform Official Docs
- HashiCorp Learn
- Terraform Registry
- Awesome Terraform
- r/Terraform on Reddit
- HashiCorp Discuss
ขอให้สนุกกับ Terraform! 🚀