Skip to main content

CircleCI

ตัวอย่าง CircleCI config สำหรับ Terraform pipeline

Basic .circleci/config.yml

.circleci/config.yml
version: 2.1

orbs:
terraform: circleci/[email protected]
aws-cli: circleci/aws-[email protected]

jobs:
terraform-fmt:
docker:
- image: hashicorp/terraform:1.9.8
steps:
- checkout
- run:
name: Format Check
command: terraform fmt -check -recursive

terraform-validate:
docker:
- image: hashicorp/terraform:1.9.8
steps:
- checkout
- run:
name: Init
command: terraform init -backend=false
- run:
name: Validate
command: terraform validate

terraform-plan:
docker:
- image: hashicorp/terraform:1.9.8
steps:
- checkout
- aws-cli/setup:
role-arn: $AWS_ROLE_ARN
- run:
name: Init
command: terraform init
- run:
name: Plan
command: terraform plan -out=tfplan
- persist_to_workspace:
root: .
paths:
- tfplan
- .terraform/

terraform-apply:
docker:
- image: hashicorp/terraform:1.9.8
steps:
- checkout
- attach_workspace:
at: .
- aws-cli/setup:
role-arn: $AWS_ROLE_ARN
- run:
name: Apply
command: terraform apply -auto-approve tfplan

workflows:
terraform:
jobs:
- terraform-fmt
- terraform-validate

- terraform-plan:
requires:
- terraform-fmt
- terraform-validate

- hold-for-approval:
type: approval
requires:
- terraform-plan
filters:
branches:
only: main

- terraform-apply:
requires:
- hold-for-approval
filters:
branches:
only: main

ใช้ CircleCI Orb

CircleCI Terraform Orb มี jobs สำเร็จรูป:

version: 2.1

orbs:
terraform: circleci/[email protected]

workflows:
terraform:
jobs:
- terraform/fmt:
checkout: true
- terraform/validate:
checkout: true
path: .
- terraform/plan:
checkout: true
path: .
persist-workspace: true
- terraform/apply:
checkout: false
attach-workspace: true
path: .
filters:
branches:
only: main

OIDC Authentication

ใช้ CircleCI OIDC token แทน AWS access key:

1. ตั้งค่า IAM

data "circleci_oidc_token" "this" {}

resource "aws_iam_openid_connect_provider" "circleci" {
url = "https://oidc.circleci.com/org/${var.circleci_org_id}"
client_id_list = [var.circleci_org_id]
thumbprint_list = ["..."]
}

resource "aws_iam_role" "circleci" {
name = "CircleCITerraform"

assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = {
Federated = aws_iam_openid_connect_provider.circleci.arn
}
Action = "sts:AssumeRoleWithWebIdentity"
Condition = {
StringEquals = {
"oidc.circleci.com/org/${var.circleci_org_id}:aud" = var.circleci_org_id
}
}
}]
})
}

2. ใช้ใน Job

jobs:
terraform-apply:
docker:
- image: hashicorp/terraform:1.9.8
steps:
- checkout
- run:
name: Assume AWS Role
command: |
aws sts assume-role-with-web-identity \
--role-arn $AWS_ROLE_ARN \
--role-session-name circleci-${CIRCLE_BUILD_NUM} \
--web-identity-token $CIRCLE_OIDC_TOKEN

Multi-Environment

workflows:
deploy-dev:
jobs:
- terraform-apply:
name: deploy-dev
working-directory: envs/dev
context: aws-dev
filters:
branches:
only: develop

deploy-prod:
jobs:
- terraform-apply:
name: deploy-prod
working-directory: envs/prod
context: aws-prod
filters:
branches:
only: main

Caching

jobs:
terraform-init:
docker:
- image: hashicorp/terraform:1.9.8
steps:
- checkout

- restore_cache:
keys:
- tf-plugins-{{ checksum ".terraform.lock.hcl" }}

- run:
name: Setup plugin cache
command: |
mkdir -p ~/.terraform.d/plugin-cache
echo 'plugin_cache_dir = "$HOME/.terraform.d/plugin-cache"' > ~/.terraformrc

- run: terraform init

- save_cache:
key: tf-plugins-{{ checksum ".terraform.lock.hcl" }}
paths:
- ~/.terraform.d/plugin-cache

Approval Gate

workflows:
deploy-prod:
jobs:
- terraform-plan
- approve-prod-deploy:
type: approval
requires:
- terraform-plan
filters:
branches:
only: main
- terraform-apply:
requires:
- approve-prod-deploy

→ Workflow pause ที่ approval — manual click ใน UI ก่อน apply

Notification

jobs:
terraform-apply:
docker:
- image: hashicorp/terraform:1.9.8
steps:
- run: terraform apply -auto-approve

- run:
name: Notify Slack
when: always
command: |
if [ "$CIRCLE_JOB_STATUS" == "success" ]; then
MESSAGE="✅ Terraform applied successfully"
else
MESSAGE="❌ Terraform apply failed"
fi

curl -X POST $SLACK_WEBHOOK \
-H 'Content-Type: application/json' \
-d "{\"text\":\"$MESSAGE\"}"

Run Linting + Security Scan

jobs:
lint:
docker:
- image: ghcr.io/terraform-linters/tflint:v0.53.0
steps:
- checkout
- run: tflint --init
- run: tflint --recursive

security:
docker:
- image: bridgecrew/checkov:latest
steps:
- checkout
- run: checkov -d . --framework terraform

Best Practices

✅ DO:
- ใช้ OIDC แทน access keys
- Cache provider plugins
- Approval gate สำหรับ prod
- Notify on success/failure
- Run lint + security scan parallel กับ plan

❌ DON'T:
- ห้าม hardcode secrets ใน config.yml
- ห้าม skip approval gate ใน prod
- ห้ามรัน apply โดยไม่มี plan ก่อน

ตัวอย่าง Complete Pipeline

version: 2.1

orbs:
terraform: circleci/[email protected]
aws-cli: circleci/aws-[email protected]

executors:
terraform:
docker:
- image: hashicorp/terraform:1.9.8

jobs:
fmt-check:
executor: terraform
steps:
- checkout
- run: terraform fmt -check -recursive

validate:
executor: terraform
steps:
- checkout
- run: terraform init -backend=false
- run: terraform validate

lint:
docker:
- image: ghcr.io/terraform-linters/tflint:v0.53.0
steps:
- checkout
- run: tflint --init
- run: tflint --recursive

security-scan:
docker:
- image: bridgecrew/checkov:latest
steps:
- checkout
- run: checkov -d . --framework terraform

plan:
executor: terraform
steps:
- checkout
- aws-cli/setup
- run: terraform init
- run: terraform plan -out=tfplan
- persist_to_workspace:
root: .
paths: [tfplan, .terraform]

apply:
executor: terraform
steps:
- checkout
- attach_workspace:
at: .
- aws-cli/setup
- run: terraform apply -auto-approve tfplan

workflows:
pr:
jobs:
- fmt-check
- validate
- lint
- security-scan
- plan:
requires: [fmt-check, validate, lint, security-scan]

deploy:
when:
equal: [main, << pipeline.git.branch >>]
jobs:
- fmt-check
- validate
- lint
- security-scan
- plan:
requires: [fmt-check, validate, lint, security-scan]
- approve:
type: approval
requires: [plan]
- apply:
requires: [approve]

สรุป

  • CircleCI ใช้ .circleci/config.yml
  • Workflow: fmt → validate → lint → security → plan → approve → apply
  • Use CircleCI Terraform Orb ลดงานเขียน config
  • OIDC กับ AWS — temp credentials, no secrets
  • Approval gate สำหรับ prod
  • Cache plugins + persist_to_workspace ระหว่าง jobs

ต่อไป → GitLab CI