Pipeline GitOps mengubah apply manual menjadi alur yang aman dan terdokumentasi. Episode ini membangun alur PR menuju produksi dengan action resmi setup-opentofu di GitHub Actions dan padanannya di GitLab CI: fmt, validate, security scan, plan dengan komentar di PR, hingga apply via OIDC dengan approval gate.

Di episode 12 sebelumnya kita menyusun arsitektur DRY bersama Terragrunt: backend dan provider terpusat di file root, sedangkan folder Dev, Staging, dan Prod hanya membawa nilai-nilai yang benar-benar berbeda. Struktur itu menghilangkan duplikasi, tapi masih menyisakan satu titik lemah yang paling fatal di IaC: siapa yang menekan tofu apply. Apply manual dari laptop berarti environment yang salah, kredensial yang bocor, dan perubahan tanpa jejak sama sekali di repositori. Di dunia nyata, inilah penyebab drift dan insiden produksi yang paling umum.
Di episode 13 ini kita akan membangun CI/CD pipeline automation: memakai action resmi opentofu/setup-opentofu di GitHub Actions, lalu menyusun alur GitOps lengkap — PR masuk, tofu fmt, tofu validate, security scan, tofu plan yang memposting komentar ke PR, merge, approval gate, hingga tofu apply melalui OIDC. Di bagian akhir kita padankan semuanya dengan GitLab CI lewat .gitlab-ci.yml. Mari mulai.
Bayangkan tim berempat, masing-masing dengan laptop dan akun AWS yang berbeda. Satu orang apply dari cabang lama, orang lain lupa menjalankan tofu init, dan yang ketiga mengubah sesuatu langsung di console. Semua itu menyisakan tanda tanya besar: apa yang sebenarnya terjadi, oleh siapa, dan kapan. Pipeline mengubah pertanyaan itu menjadi jawaban pasti, karena seluruh alur terekam sebagai log build dan hanya dua hal yang bisa memicu eksekusi: event dari repository dan persetujuan manusia yang terdokumentasi.
GitHub Actions resmi menyediakan action opentofu/setup-opentofu — dikelola oleh tim OpenTofu sendiri, bukan pihak ketiga. Action ini mengunduh binary tofu sesuai versi yang diminta, memverifikasi checksum, dan menyimpan hasil unduhan sebagai cache agar job berikutnya tidak mengunduh ulang. Memasangnya sesederhana satu langkah:
- name: Setup OpenTofu
uses: opentofu/setup-opentofu@v1
with:
tofu_version: 1.8.2
cache: true
github_token: ${{ secrets.GITHUB_TOKEN }}Tip
Pin versi tofu_version secara eksplisit di workflow. Versi minor OpenTofu berkembang cepat, dan determinisme adalah harga mati untuk pipeline — job yang berubah perilaku hanya karena rilis baru semalam tidak boleh terjadi di repositori IaC.
Berikut workflow yang merangkum seluruh alur: pull request memicu validate dan security-scan, lalu plan yang memposting komentar; push ke branch main memicu apply yang berjalan di environment dengan approval gate. Kredensial cloud tidak pernah disimpan sebagai secret jangka panjang — setiap job menerima token AWS sementara lewat OIDC:
name: OpenTofu GitOps
on:
pull_request:
types: [opened, synchronize, reopened]
push:
branches: [main]
permissions:
id-token: write
contents: read
pull-requests: write
env:
TF_IN_AUTOMATION: "1"
jobs:
validate:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup OpenTofu
uses: opentofu/setup-opentofu@v1
with:
tofu_version: 1.8.2
cache: true
- run: tofu fmt -check -recursive
- run: tofu init
- run: tofu validate
security-scan:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Checkov scan
uses: bridgecrewio/checkov-action@v1
with:
directory: .
framework: tofu
- name: Trivy config scan
uses: aquasecurity/trivy-action@master
with:
scan-type: config
severity: HIGH,CRITICAL
exit-code: 1
plan:
needs: [validate, security-scan]
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup OpenTofu
uses: opentofu/setup-opentofu@v1
with:
tofu_version: 1.8.2
cache: true
- name: Assume role via OIDC
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/opentofu-github-oidc
aws-region: ap-southeast-1
- name: Plan
run: |
tofu init
tofu plan -out=plan.tfplan
- name: Post plan comment ke PR
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
tofu show -no-color plan.tfplan > plan.txt
gh pr comment "$PR_NUMBER" --body-file plan.txt
apply:
needs: [plan]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- name: Setup OpenTofu
uses: opentofu/setup-opentofu@v1
with:
tofu_version: 1.8.2
cache: true
- name: Assume role via OIDC
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/opentofu-github-oidc
aws-region: ap-southeast-1
- run: tofu init
- run: tofu apply -auto-approvePerhatikan pemisahan peran yang ketat di workflow ini. Job validate dan security-scan tidak punya akses cloud sama sekali — mereka murni memeriksa kode. Job plan baru berhak memakai role OIDC, dan job apply digantung pada environment: production yang di pengaturan repositori dikonfigurasi mewajibkan required reviewers — gerbang persetujuan manusia yang tidak bisa dilewati oleh siapa pun yang punya hak push.
Warning
Jangan pernah meletakkan kredensial AWS jangka panjang sebagai secret workflow. Dengan OIDC, role di AWS hanya mempercayai token pendek dari GitHub, dan job apply hanya berjalan setelah approval. Secret panjang umur di CI adalah salah satu sumber kebocoran paling umum di repositori IaC.
GitLab CI menawarkan konsep yang sama dengan sintaks yang berbeda: stage berurutan, artefak untuk meneruskan file plan antar job, aturan rules untuk membatasi kapan job berjalan, dan id_tokens untuk OIDC. Job apply dibuat manual dan terikat ke environment production, sehingga memerlukan persetujuan:
stages:
- validate
- plan
- apply
image: ghcr.io/opentofu/opentofu:1.8.2
variables:
TF_IN_AUTOMATION: "true"
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == "main"
tofu:validate:
stage: validate
script:
- tofu fmt -check -recursive
- tofu init
- tofu validate
tofu:plan:
stage: plan
id_tokens:
AWS_ID_TOKEN:
aud: https://gitlab.com
script:
- tofu init
- tofu plan -out=plan.tfplan
artifacts:
paths:
- plan.tfplan
expire_in: 1 week
tofu:apply:
stage: apply
id_tokens:
AWS_ID_TOKEN:
aud: https://gitlab.com
script:
- tofu init
- tofu apply plan.tfplan
environment:
name: production
rules:
- if: $CI_COMMIT_BRANCH == "main"
when: manualBlok id_tokens memberi setiap job sebuah token OIDC yang bisa dipertukarkan dengan role AWS, mirip peran aws-actions/configure-aws-credentials di GitHub. Artefak plan.tfplan diteruskan dari job plan ke job apply sehingga yang dieksekusi persis sama dengan yang direview — tanpa window kosong antara review dan eksekusi.
Pada episode 13 ini kita telah membangun fondasi otomatisasi:
opentofu/setup-opentofu dengan versi ter-pin dan caching.tofu fmt, tofu validate, security scan, dan tofu plan dengan komentar di PR; merge ke main memicu apply.id_tokens dan when: manual.Membangun pipeline sendiri memberikan kontrol penuh, tapi bukan tanpa biaya perawatan. Di episode 14 selanjutnya kita akan meninjau ekosistem managed platforms — Spacelift, env0, Scalr — dan mengenal Digger, tool GitOps open-source yang mengeksekusi OpenTofu langsung di dalam GitHub Actions atau GitLab CI tanpa SaaS eksternal. Sampai jumpa!