HashiCorp's publicly available certification is centered on Associate, but this article assumes an advanced (Pro-equivalent) level and organizes study perspectives around the hard parts of real-world operations.
Beyond exam prep, we explain things in terms of standard production patterns such as Terraform Cloud/Enterprise and the S3 + DynamoDB backend.
At the advanced level, you are expected to do more than write HCL. You are tested on module publication quality, State operations (locking, isolation, migration), change safety (create_before_destroy, replace_triggered_by, moved), policy enforcement, and CI-driven automation and auditability. You should also understand the differences between Terraform Open Source and Terraform Cloud/Enterprise (TFC/E).
Questions tend to focus on decisions that assume scale and change — multi-environment, multi-workspace, remote State, team permissions, enforcement of tags and conventions, module versioning, provider upgrades — rather than simple single-workspace setups.
| Domain | Associate depth | Advanced-level depth | Production perspective |
|---|---|---|---|
| Module design | Basic variables/outputs | Publication quality, conditions, versioning, and breaking-change handling | Ship design changes while maintaining backward compatibility and docs |
| State/backend | Understanding of init/refresh | Locking, isolation, and migration strategy for S3+DynamoDB / TFC | Recovery procedures, drift response, and key design |
| Change management | Basics of plan/apply | Combining create_before_destroy, replace_triggered_by, and moved | Aim for zero downtime while balancing cost and speed |
| Governance | Basic understanding of workspaces | Sentinel/OPA, permission design, variable sets, audit logs | Enforcement of org standards with an exception approval process |
| Automation/audit | Running validate/plan | JSON plan retention, signing, approval gates, reproducibility | Evidence trail and ease of rollback |
Advanced-level Terraform responsibility map
Minimal root configuration skeleton (version / provider constraints)
terraform {
required_version = ">= 1.4, < 2.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = var.region
}
module "network" {
source = "appcorp/network/vpc"
version = "~> 2.4"
cidr_block = var.vpc_cidr
}
At the advanced level, modules need to be more than just usable — they must be safe to upgrade. The key points are variable validation, pre/post conditions, sensible defaults, backward compatibility of names and outputs, and clear versioning conventions. Breaking changes go in major releases, combined with moved blocks to migrate addresses and minimize impact.
Provide a README, examples, and a version compatibility matrix. If you publish to a registry, keep the usage examples runnable. Even for internal-only modules, always ship a CHANGELOG and an upgrade guide.
Module snippet with conditions and validation
variable "subnet_cidrs" {
type = list(string)
validation {
condition = length(var.subnet_cidrs) >= 2
error_message = "At least two subnet CIDRs are required."
}
}
locals {
default_tags = merge(var.default_tags, {
managed-by = "terraform"
module = "appcorp/network"
})
}
resource "aws_subnet" "this" {
for_each = toset(var.subnet_cidrs)
vpc_id = var.vpc_id
cidr_block = each.value
tags = local.default_tags
lifecycle {
precondition {
condition = can(cidrnetmask(each.value))
error_message = "Invalid CIDR format."
}
}
}
moved {
from = aws_subnet.old
to = aws_subnet.this
}
output "subnet_ids" {
description = "List of created subnet IDs"
value = values(aws_subnet.this)[*].id
}
State is the source of truth. At the advanced level, you design locking, permissions, and a key strategy (separation by environment, region, and system) on the remote backend, and you standardize recovery procedures for incidents. S3 + DynamoDB is the classic choice for on-prem and multi-account setups, while Terraform Cloud/Enterprise integrates locking, run management, policy, and audit.
For migration and maintenance, choose appropriately between terraform state mv/import and module-level moved. For drift, do not jump to -state rm or manual fixes — identify the root cause, and if needed adjust with ignore_changes or by understanding how the provider computes diffs.
Representative backend configuration and operational commands
# S3 + DynamoDB locking
terraform {
backend "s3" {
bucket = "tfstate-prod"
key = "network/prod/ap-northeast-1/terraform.tfstate"
region = "ap-northeast-1"
dynamodb_table = "tfstate-lock"
encrypt = true
}
}
# Terraform Cloud (remote) backend
terraform {
cloud {
organization = "appcorp"
workspaces {
name = "network-prod"
}
}
}
# Operational snippets
# Bind an existing resource to declaration (import)
terraform import aws_subnet.this["10.0.1.0/24"] subnet-abc123
# Address migration (state mv)
terraform state mv aws_subnet.old["10.0.1.0/24"] aws_subnet.this["10.0.1.0/24"]
# JSON-ify diffs (for audit)
terraform show -json plan.out > plan.json
Even when a change forces a replacement, you can reduce downtime and risk. Use lifecycle's create_before_destroy, suppress diffs on externally controlled values with ignore_changes, and induce replacement at the intended moment with replace_triggered_by. Provider-specific blue-green and rolling updates are safest when wrapped behind a module abstraction.
Keep -target reserved for debugging and staged rollouts — do not make it part of normal operations. Split risk across multi-step changes by versioning modules and leveraging moved blocks and output compatibility.
HCL example for replacement order and diff suppression
resource "aws_launch_template" "app" {
name_prefix = "app-"
image_id = var.ami
instance_type = var.instance_type
user_data = var.user_data
lifecycle {
create_before_destroy = true
ignore_changes = [
user_data, # Suppress drift when swapped externally each time
tags["temporary"]
]
replace_triggered_by = [
var.force_recreate_token # Force safer-side replacement with an arbitrary token
]
}
timeouts {
create = "20m"
delete = "20m"
}
}
In Terraform Cloud/Enterprise, Sentinel lets you enforce organization-wide policies on plans. Codify rules such as required tags, cost ceilings, and allow-listed regions or providers, and control scope via workspaces and policy sets. In Open Source environments, integrate OPA/Rego and Conftest into CI to run equivalent checks.
Apply least-privilege as a principle, and when integrating with VCS carefully separate trigger permissions from State-read permissions. Use variable sets and Sensitive variables to inject credentials outside of code, and ensure operational traceability through audit logs.
Simple Sentinel policy example (required tags)
import "tfplan/v2" as tfplan
main = rule {
all tfplan.resources as r {
r.mode is "managed" implies has_required_tags(r)
}
}
has_required_tags = func(r) {
all r.applied.resources as inst {
inst.change.after.tags is not null and
inst.change.after.tags["owner"] is not null and
inst.change.after.tags["env"] in ["dev", "stg", "prod"]
}
}
Separate init/validate/plan in CI, save the plan as a binary artifact, and use it only for apply after review. Run static analysis (tflint and friends) and policy checks (OPA/Checkov) early, and reserve heavy plans for the point where changes are finalized. Combine with VCS protection rules to ensure reproducibility and evidence.
For incident investigation, start with machine-readable diffs via plan/show -json, TF_LOG and provider debug flags, and adjustments to parallelism or API rate limits. For import, where the recent import block is available, declare it in code so it is built into the plan and the procedure becomes visible.
Basic GitHub Actions pipeline example
name: terraform-ci
on:
pull_request:
paths: ["infra/**"]
jobs:
plan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
with:
terraform_version: 1.6.6
- run: terraform -chdir=infra init -input=false
- run: terraform -chdir=infra validate
- run: terraform -chdir=infra plan -input=false -out=plan.out
- run: terraform -chdir=infra show -json plan.out > plan.json
- uses: actions/upload-artifact@v4
with:
name: tf-plan
path: infra/plan.out
apply:
if: github.ref == 'refs/heads/main' && github.event_name == 'workflow_dispatch'
needs: plan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- uses: actions/download-artifact@v4
with:
name: tf-plan
path: infra
- run: terraform -chdir=infra init -input=false
- run: terraform -chdir=infra apply -input=false "plan.out"
Pro
問題 1
You refactored an internal module used across multiple workspaces (dev/stg/prod) and the resource address changed from aws_subnet.old to aws_subnet.this. You want to migrate safely across all environments without re-creation or downtime. Which is the most appropriate action?
正解: A
The moved block declaratively migrates resource address changes and avoids re-creation. Distributed as a new module version, it automatically updates State during plan/apply in each workspace. state rm is destructive and hard to recover from, -target is not a permanent migration tool, and creating new workspaces is unnecessary and risky.
Should I use Sentinel or OPA?
If you use Terraform Cloud/Enterprise, Sentinel is the natural choice for centrally managing runtime policies. For Open Source-centric CI, adopt OPA/Rego (Conftest) and run it as a static check before plan. You can also combine both, splitting roles like OPA for development and Sentinel for production.
Can I get safe state locking without Terraform Cloud?
Yes. The standard pattern is to combine an S3 backend with DynamoDB locking. Enable versioning and encryption on S3, and configure appropriate throughput and alerts on the DynamoDB table. To avoid contention, serialize CI to a single job and set operational rules that prevent overlap with manual runs.
How tightly should I pin module and provider versions?
For modules, pin to a minor range with ~> for compatibility, and absorb breaking changes via major updates. For providers, a pragmatic approach is to use ~> range constraints to avoid incidents, or pin exactly in the short term, validate, then gradually loosen. Be diligent about reading CHANGELOGs and applying changes first in a validation environment.
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...