This article lays out the practical guidelines for embedding Terraform plan/apply into CI/CD so you get both clear change visibility and safe deployments.
We break down the key topics that the exam often tests — freezing the change plan, state locking, approval gates, and version pinning — in a form you can actually apply in the field.
The goal is to build a pipeline that freezes the Terraform plan output in a form a human can review, and then applies only that exact same plan to production. This guarantees that even if code or external state changes after review, the applied content cannot be swapped out.
The intended reader is an intermediate-to-advanced practitioner who already understands cloud privilege separation and the basics of running a remote backend. Terraform version management, the provider lock file, and remote backend locking are the foundations for everything that follows.
Always separate plan and apply into distinct phases, and have apply consume the stored plan file as-is. It is critical that the apply phase never re-runs plan.
Keep Terraform and provider versions identical between the CI and CD environments. Because a plan file depends on Terraform/provider versions and the OS, the entire workflow must assume version parity.
Baseline pipeline that separates plan from apply
The following is a minimal example that proceeds in order: 1) static checks, 2) initialization, 3) validation, 4) saving the plan, 5) manual approval, 6) applying the plan. We express it as shell steps so it stays independent of any specific CI/CD product.
Inject backend configuration and sensitive variables from the CI secret store or environment variables, and disable interactivity with -input=false.
CI/CD reference script (pseudo-example)
# CI: 計画の生成
set -euo pipefail
# 1) フォーマットと静的検査
terraform fmt -check -recursive
terraform init \
-input=false
# 2) バリデーション
terraform validate -no-color
# 3) ワークスペース/環境の選択
# export TF_WORKSPACE=staging
# terraform workspace select "$TF_WORKSPACE" || terraform workspace new "$TF_WORKSPACE"
# 4) 変更計画の作成(詳細終了コードで差分検出)
set +e
terraform plan \
-out=plan.bin \
-lock=true \
-input=false \
-no-color \
-detailed-exitcode
rc=$?
set -e
if [ "$rc" -eq 0 ]; then
echo "差分なし。apply は不要"; exit 0
elif [ "$rc" -eq 2 ]; then
echo "差分あり。plan.bin を保存して承認待ちへ";
sha256sum plan.bin > plan.bin.sha256
# ここで CI のアーティファクトに plan.bin とハッシュを保存
else
echo "plan 失敗"; exit $rc
fi
# --- 手動承認ゲート(人のレビュー)---
# CD: plan の適用(同一バージョンの Terraform/Provider 前提)
sha256sum -c plan.bin.sha256
terraform init -input=false
terraform apply -input=false -auto-approve plan.binSeparate environments via directory splits (state separated per env directory), workspaces (one configuration, multiple states), or repository splits. In every case, state must be physically separated, and locking must be in place so concurrent apply runs cannot interfere with one another.
Center review and approval on the plan's visibility. The review target is not just the HCL diff but also the plan's summary of resource adds, changes, and deletes. Post-approval apply must use the plan.bin generated at approval time — never re-run plan immediately before apply.
Remote backends give you centralized state management and locking. Major backends — S3 + DynamoDB locking, azurerm, gcs — all ship with a locking mechanism. -lock defaults to true, but in CI/CD it's worth setting it explicitly to make intent clear.
Apply concurrency control at two layers. First, the backend lock. Second, CI/CD queuing that serializes apply runs against the same environment. Together, they prevent state corruption from parallel apply runs. Parallelism across separate environments and separate states becomes much easier to allow.
Terraform automation broadly splits into DIY general-purpose CI/CD, Terraform Cloud/Enterprise VCS integration, and API-driven execution. Compare them on state management, policy, approval UX, and cost when choosing.
From an exam perspective, frequently tested topics include plan freezing and apply separation, remote state and locking, version pinning, least privilege, the meaning of -detailed-exitcode, and where policy enforcement (such as Sentinel) fits in.
| Aspect | General-purpose CI/CD (DIY) | Terraform Cloud: VCS-integrated runs | Terraform Cloud: API/CLI-driven |
|---|---|---|---|
| State management / locking | Self-configured S3+DynamoDB / azurerm / gcs, etc. | TFC manages it (locking built in) | TFC manages it (locking built in) |
| Plan storage / approval | CI artifact storage plus manual approval | Review and approve plans in the UI (policy checks integrate) | Fetch plans via API and externalize the approval flow |
| Policy | Integrate OPA/conftest, etc. (operated separately) | Sentinel (edition-dependent) | Sentinel (edition-dependent) |
| Execution environment setup | Maintain Terraform/provider version pinning yourself | TFC handles version management (per workspace setting) | TFC handles version management (per workspace setting) |
| Permissions and secrets | Connect to the cloud via OIDC/short-lived credentials (managed CI-side) | Managed safely via workspace variables | Managed safely via workspace variables |
| Learning / operational cost | Flexible but heavy initial build and maintenance burden | UI and guardrails make operations easy | Flexible integration, but you need to design the API surface |
Pro
問題 1
A team wants to embed Terraform changes into CI/CD. Which approach most strongly guarantees that, even if code or external state changes after review, no change other than what was approved will be applied to production?
正解: A
Applying the stored plan file as-is is the strongest way to guarantee that what was approved at review time and what gets applied are identical. If you re-run plan right before apply, code or external state changes can alter the plan.
Can a plan file be applied in any environment?
No. A plan file depends on the exact Terraform core version, provider versions, and OS/architecture. Apply it only against the same version set, the same configuration, and the same remote state. Do not treat a plan as something you can ship across environments generically.
Should production apply be fully automated (unattended)?
The recommended pattern is a human approval gate. Automated apply after manual approval is common, but combine -auto-approve with RBAC and audit logs so you have a record of who approved what.
How should sensitive variables be passed?
Use the CI/CD secret store or Terraform Cloud's sensitive variables. Avoid passing secrets in plain text via -var. Inject them as TF_VAR_name environment variables or encrypted tfvars files, and never commit secrets to the repository.
Practice with certification-focused question sets
無料で問題を解いてみるNicheeLab Editorial Team
NicheeLab editorial team focused on data engineering and cloud certification learning. Content is structured around practical study needs and official exam domains.
HCL Syntax: Terraform's Configuration Language (2026)
HCL2 fundamentals for Terraform — blocks, attributes, expres...
Terraform Authoring & Operations Pro: Complete Guide (2026)
Tactics for the Terraform Pro exam — module authoring, works...
Terraform Providers: Plugin Management Fundamentals (2026)
Provider mechanics — required_providers, versions, mirrors, ...
Terraform Resource Blocks: Declarative Infra Units (2026)
Resource block fundamentals — addresses, references, common ...
Terraform Data Sources: Read-Only External Data (2026)
Data source basics — declaration, refresh behavior, dependen...