Skip to main content

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

TierRun 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
StageWhenUse Case
pre-planBefore planValidate config
post-planAfter planSecurity scan
pre-applyBefore applyFinal check
post-applyAfter applyNotification

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

  1. ลงมือทำจริง — สร้าง project + apply S3 bucket แรก
  2. Build a Module — เริ่มจาก simple module (security group)
  3. Setup Remote Backend — S3 + DynamoDB
  4. Add CI/CD — GitHub Actions plan in PR
  5. Add Security Scan — Checkov ใน pre-commit
  6. Try HCP Free Tier — สำหรับ project ขนาดกลาง

แหล่งเรียนรู้ต่อ

ขอให้สนุกกับ Terraform! 🚀