TerraformでAWSを構築する手順は、2024年までの入門記事から前提が3つ変わりました。awsプロバイダ6系でリソース単位のregion引数が入ったこと、tfstateのロックがDynamoDBテーブルからS3のネイティブロックへ移ったこと、ローカルの認証が長期アクセスキーからIAM Identity Centerのプロファイルへ寄ったことです。本記事はTerraform 1.16.5とaws 6.68.0(いずれも2026年10月12日時点の最新)を前提に、版の固定、認証、tfstateの置き場、VPCからEC2までの最小構成、terraform planで止まるエラーの対処、AWS純正ツールとの使い分けを実装順に並べます。掲載したHCLは同じ版の組み合わせでterraform validateを通しています。
まとめ:AWS構築前に決める3点と最初の実行順
- 版の固定:CLIは
required_version、プロバイダはversion = "~> 6.68"で固定し、.terraform.lock.hclをリポジトリに入れる - 認証:ローカルはIAM Identity Centerのプロファイル、CIはOIDCなどの一時認証情報。長期アクセスキーはコードにもCIの変数にも置かない
- tfstate:S3バックエンド+
use_lockfile = true。新規構築でDynamoDBテーブルは作らない
実行順はAWS_PROFILEの設定とaws sso login→terraform init→terraform plan→terraform applyで、検証環境は使い終わったらterraform destroyで消します。Terraformを使うメリットは構成を差分でレビューでき、同じ定義から同じ環境を作り直せる点ですが、対象がAWSだけならCloudFormationでも同じ利点は得られます。Terraformを選ぶ理由が立つのは、AWSの外側まで1つの記法で管理したいときです。設計からAWS環境の構築・移行までをまとめて任せたい場合は、一創のインフラ構築(AWS・Google Cloud・Azure)でTerraformによるコード化を含めて対応しています。
Terraform 1.16系とaws 6系のバージョン固定
versions.tfとS3バックエンドを書く入口ファイル
Terraform CLIの安定版は1.16.5(2026年10月2日UTC公開)です。1.16系は1.16.0のリリースノートのとおり2026年8月26日に出ており、1.17.0は10月7日にrc1が出た段階なので、本番構成の既定は1.16系にします。awsプロバイダは6.68.0(2026年10月7日UTC公開)が最新で、6.64.0から6.68.0までの5本が9月9日から10月7日の約4週間に出ています。入口のファイルは次の形です。
terraform {
required_version = "~> 1.16.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 6.68"
}
}
backend "s3" {
bucket = "example-tfstate-prod"
key = "network/terraform.tfstate"
region = "ap-northeast-1"
use_lockfile = true
}
}
provider "aws" {
region = "ap-northeast-1"
default_tags {
tags = {
Project = "sample"
ManagedBy = "terraform"
}
}
}
required_version = "~> 1.16.0"は1.16系のパッチ更新だけを許す指定です。S3ネイティブロックだけなら1.11以上で動きますが、後述のlifecycleのdestroy = falseとモジュール内のimportブロックは1.16.0からの機能なので、本記事の構成は1.16系に揃えます。プロバイダ側の~> 6.68は右端の要素だけ増加を許す指定で、6.69は入り7.0.0は入りません。パッチ更新だけに絞るなら~> 6.68.0と書きます。実際に使う版は.terraform.lock.hclに記録され、terraform init -upgradeを実行するまで動きません。default_tagsを置くと、タグに対応するリソースへ共通のタグが付き、リソース側では値の上書きだけを書けば済みます。制約演算子の選び分けはterraform providerのバージョン制約とalias設計|lockファイルの運用判断、CLIの入れ方はTerraformのインストール手順をOS別に整理|tfenv・CIでの版固定まで、版ごとの新機能はTerraformの最新バージョンは1.16|terraform versionでの確認とアップグレード手順・新機能で扱っています。
aws 6.0のregion引数を使う場面
6.0.0で、大半のリソースとデータソースにトップレベルのregion引数が入りました。プロバイダを東京に設定したまま、特定のリソースだけ大阪に置けます。
resource "aws_vpc" "dr" {
region = "ap-northeast-3"
cidr_block = "10.1.0.0/16"
}
regionの値を変えるとリソースは置換されます。記述を消した場合はstateに残った値が使われるため置換は起きません。インポートIDは<id>@ap-northeast-3の形でリージョンを付けます。IAMのようなグローバルリソースは対象外です。この引数が効くのは「基本は単一リージョン、DR用など一部だけ別リージョン」の構成で、環境全体のリージョンを切り替える用途には向きません。従来のプロバイダalias構成は6系でも有効で、非推奨にもなっていません。5系から上げる場合は、公式の6系移行ガイドのとおり、まず5系の最新版でterraform planの警告を消してから制約を6系へ広げます。
AWSへの認証をローカル実行とCI実行で分ける方式
認証情報が読まれる順序と別アカウントへの誤適用
awsプロバイダは、プロバイダ設定のパラメータ、環境変数、共有credentialsファイル、共有configファイル、コンテナの認証情報、インスタンスプロファイルの順に認証情報を探します。AWS CLIおよびAWS SDK for Go v2と同じ順序です。プロファイルを何も指定しないと、シェルに残ったAWS_ACCESS_KEY_IDがdefaultプロファイルより先に使われ、意図しないアカウントへ適用される原因になります。一方、1.16.5とaws 6.68.0で試すと、profile引数かAWS_PROFILEでプロファイルを指定した場合は、環境変数にアクセスキーを置いてもプロファイル側が読まれ、存在しない名前を指定すると環境変数のキーで代替されずにプロファイルのエラーで止まりました。ローカルではプロファイルを必ず明示し、アクセスキーをプロバイダブロックへ直書きする書き方は採りません。
IAM Identity Centerのプロファイルでローカルから実行する手順
手元のPCから実行するときは、長期のアクセスキーを発行せず、IAM Identity Centerのプロファイルで一時認証情報を使います。AWS CLIのIAM Identity Center設定手順が推奨する形式は、sso-sessionセクションを定義してプロファイルに関連付けるものです。aws configure ssoを実行すると、次のような設定が~/.aws/configに書き込まれます。
[profile example-dev]
sso_session = example
sso_account_id = 123456789012
sso_role_name = TerraformDeveloper
region = ap-northeast-1
[sso-session example]
sso_start_url = https://example.awsapps.com/start
sso_region = ap-northeast-1
sso_registration_scopes = sso:account:access
export AWS_PROFILE=example-dev
aws sso login
terraform init
terraform plan
プロファイルは環境変数AWS_PROFILEで渡します。provider "aws"のprofile引数はS3バックエンドに引き継がれないため、引数で指定するとバックエンド側にも別途profileを書く必要があります。AWS_PROFILEならプロバイダとバックエンドの両方が同じプロファイルを読みます。セッションが切れたらaws sso loginをやり直します。CLIはこのログインのためだけに必要で、Terraform本体はCLIを呼び出しません。
assume_roleで実行専用ロールへ委譲する構成
複数アカウント構成では、開発者自身の権限ではapplyせず、Terraform実行用のロールへ委譲します。
provider "aws" {
region = "ap-northeast-1"
assume_role {
role_arn = "arn:aws:iam::123456789012:role/TerraformExecution"
session_name = "terraform-cli"
}
}
session_nameはCloudTrailで実行者を追う単位になるため、命名規則を決めておきます。第三者のアカウントへ委譲するならexternal_idを併用します。踏み台ロールを経由して本命のロールへ渡すロールチェーンは、assume_roleブロックを実行順に2つ並べればプロバイダ側だけで完結します。
実行環境ごとの認証方式
| 実行環境 | 使う認証 | プロバイダが読む経路 |
|---|---|---|
| 開発者のPC | IAM Identity Center | AWS_PROFILEで選ぶ共有configのプロファイル |
| GitHub ActionsなどAWS外のCI | OIDC+IAMロール | 環境変数の一時認証情報 |
| EC2 | インスタンスプロファイル | インスタンスメタデータ |
| ECS | タスクロール | AWS_CONTAINER_CREDENTIALS_* |
| CodeBuild | サービスロール | AWS_CONTAINER_CREDENTIALS_* |
| EKS | IRSA | AWS_ROLE_ARN・AWS_WEB_IDENTITY_TOKEN_FILE |
どの環境でも長期キーを配らずに済みます。GitHub Actionsのワークフローとロールの信頼ポリシーはGitHub ActionsとTerraformでAWSのCI/CDを構築する手順(OIDC・S3ネイティブロック対応)、fmt・validate・planをCIで回す設計はTerraformのCI導入ガイド|fmt・validate・planを自動化するパイプライン設計とツールの選び方で扱っています。
tfstateをS3に置くbackendの設定とロック方式
use_lockfileへの移行とDynamoDBテーブルを外す順序
S3ネイティブロックはTerraform 1.10.0で入り、このときはDynamoDBと併用すると双方からロックを取る挙動でした。1.11.0でuse_lockfileが正式提供になり、DynamoDB関連の引数は非推奨になっています。S3バックエンドのドキュメントではdynamodb_tableが「Optional, Deprecated」で、use_lockfileの既定値はfalseです。書き忘れるとロック無しで動きます。
既存構成から移すときは、まずuse_lockfile = trueを足してterraform init -reconfigureで再初期化し、両方が有効な状態で運用します。backendブロックを書き換えたままplanを打つと、「Backend initialization required」「Backend configuration block has changed」で止まります。同じstateを触る全員とCIが1.11以降になったことを確かめてからdynamodb_tableを外して再びterraform init -reconfigureを実行し、最後にテーブルを消します。テーブルを先に消すと、旧版のCLIが残っている環境でロックが取れずに失敗します。
backend用のIAM権限とバケット側の設定
必須引数はbucket、key、regionの3つです。ネイティブロックを有効にすると、state本体に加えて拡張子.tflockのオブジェクトにs3:GetObject、s3:PutObject、s3:DeleteObjectが要ります。state本体へのs3:DeleteObjectは不要です。DynamoDB時代の権限セットのままだとロック取得だけが失敗するので、移行時はIAMポリシーの更新を同じ変更に含めます。defaultワークスペースだけを使う場合の最小ポリシーは次のとおりです。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::example-tfstate-prod",
"Condition": {
"StringEquals": { "s3:prefix": "network/terraform.tfstate" }
}
},
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject"],
"Resource": "arn:aws:s3:::example-tfstate-prod/network/terraform.tfstate"
},
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
"Resource": "arn:aws:s3:::example-tfstate-prod/network/terraform.tfstate.tflock"
}
]
}
バケットはバージョニングを有効にして、tfstateの世代を戻せるようにします。tfstateには属性値が平文で入るため、読める主体はTerraformの実行ロールに絞ります。stateの構造や別stateへの移動はTerraform stateとは?tfstateの構造とS3バックエンド・移動削除の安全手順で扱っています。
本番と非本番のstateと実行権限の分離
本番と非本番は、できればバケットとAWSアカウントごと分けます。誤ったworkspaceのままterraform applyを打つ事故は、本番と非本番で実行ロールが分かれていれば権限エラーで止まります。同じバケットのプレフィックスで分けてもIAMでキー単位に絞れますが、1つの実行ロールで両方を触れる状態にしている限り止まりません。S3バックエンドでは、default以外のstateはenv:/<workspace名>/<key>(workspace_key_prefixの既定値)に置かれるため、上のdefault専用ポリシーのままworkspaceを使うと権限不足になります。分割方式の比較はterraform workspaceの使い方と環境分離の判断基準|分割方式の比較にあります。
tfstateバケットを守るprevent_destroyと1.16のdestroy = false
tfstate用のバケットをTerraformで作る構成では、terraform destroyの巻き添えで消える事故を防ぐ設定が要ります。従来のprevent_destroy = trueに加え、1.16.0でlifecycleにdestroy = falseが入りました(追加したプルリクエストは「破棄の代わりにstateから外す」と説明しています)。
resource "aws_s3_bucket" "tfstate" {
bucket = "example-tfstate-prod"
lifecycle {
prevent_destroy = true
}
}
resource "aws_s3_bucket_versioning" "tfstate" {
bucket = aws_s3_bucket.tfstate.id
versioning_configuration {
status = "Enabled"
}
}
2つの違いを1.16.5で確かめると、terraform destroyに対する反応が分かれます。prevent_destroyはError: Instance cannot be destroyedでplanごと止まり、destroy = falseは「will no longer be managed by Terraform, but will not be destroyed」と表示して実物を残したまま管理から外します。環境をまるごと畳むときにバケットだけ残したいならdestroy = false、誤操作を止めたいならprevent_destroyです。
共通の弱点もあります。リソースブロックごとコードから消すと、どちらを付けていても次のplanは通常の破棄(because … is not in configuration)になりました。保護はコードの中にしか無いので、ブロック削除のレビューは代替できません。tfstate用バケットはアプリとは別のstateで管理し、日常のapplyから切り離します。lifecycle全体の使い分けはterraform lifecycleの使い分け|ignore_changes・depends_on・movedの判断で整理しています。
VPCからEC2までの最小構成をapplyする手順
インターネットゲートウェイとSSM接続まで含めた最小構成
VPC、サブネット、EC2の3つだけでは、インスタンスは外へ出られず接続もできません。インターネットゲートウェイ、ルートテーブル、セキュリティグループ、Session Manager用のインスタンスプロファイルまで足したのが次の構成です。SSHのポートは開けず、キーペアも作りません。AMI IDはリージョンごとに異なり更新もされるため、SSMパブリックパラメータから引きます。
data "aws_ssm_parameter" "al2023" {
name = "/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64"
}
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
}
resource "aws_subnet" "public_a" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
availability_zone = "ap-northeast-1a"
map_public_ip_on_launch = true
}
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
}
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main.id
}
}
resource "aws_route_table_association" "public_a" {
subnet_id = aws_subnet.public_a.id
route_table_id = aws_route_table.public.id
}
resource "aws_security_group" "app" {
name = "sample-app"
vpc_id = aws_vpc.main.id
}
resource "aws_vpc_security_group_egress_rule" "all" {
security_group_id = aws_security_group.app.id
ip_protocol = "-1"
cidr_ipv4 = "0.0.0.0/0"
}
resource "aws_iam_role" "ssm" {
name = "sample-ec2-ssm"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = "sts:AssumeRole"
Principal = { Service = "ec2.amazonaws.com" }
}]
})
}
resource "aws_iam_role_policy_attachment" "ssm" {
role = aws_iam_role.ssm.name
policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}
resource "aws_iam_instance_profile" "ssm" {
name = "sample-ec2-ssm"
role = aws_iam_role.ssm.name
}
resource "aws_instance" "app" {
ami = data.aws_ssm_parameter.al2023.value
instance_type = "t3.micro"
subnet_id = aws_subnet.public_a.id
vpc_security_group_ids = [aws_security_group.app.id]
iam_instance_profile = aws_iam_instance_profile.ssm.name
metadata_options {
http_tokens = "required"
}
}
output "instance_id" {
value = aws_instance.app.id
}
セキュリティグループは外向きのルールだけを持ち、受信は1本も許可していません。それでも接続できるのは、AL2023のAMIにSSM Agentが入っていること(SSM Agentのプリインストール一覧に記載)と、インスタンス側から外へ出る経路があるためです。apply後はaws ssm start-session --target <instance_id>でシェルに入れます(手元にSession Manager pluginが必要です)。http_tokens = "required"はIMDSv2の強制です。aws_ssm_parameterのvalueはplan出力で常にsensitive扱いになり、AMI IDは伏字で表示されます。
init・plan・apply・destroyの順序と検証環境の費用
実行はterraform init、terraform plan、terraform applyの順です。バックエンド用のバケットがまだ無い段階では、terraform init -backend=falseでプロバイダの取得とterraform validateだけ先に済ませられます。バケットを用意したらフラグ無しで初期化し直します。planの記号の読み方や、applyを止めるべき差分の見分け方はterraform planの差分の読み方|init・apply・destroyの安全手順にまとめています。
この構成で時間単位の課金が続くのは、EC2インスタンスとパブリックIPv4アドレスです。AWSの価格データでは東京リージョンのt3.micro(Linux)がオンデマンド1時間0.0136USD、使用中のパブリックIPv4アドレスが1時間0.005USDで、つけっぱなしにすると2つだけで1か月(730時間)約13.6USDになり、ルートボリュームのEBS料金はこれとは別にかかります(EC2オンデマンド料金・VPC料金)。2025年7月15日以降に初めてAWSに登録した場合は、サインアップ時に100USD、対象のアクティビティで最大100USDのクレジットが付き、登録時に無料プランか有料プランを選びます(AWSの告知)。無料プランは6か月経過かクレジット消化の早いほうで終わり、そのままにするとアカウントが自動で閉じられ、AWS Organizationsへの参加などで有料プランへ自動で切り替わります。無料利用枠の対象として表示されるのは、t3.microやt4g.microを含む6種類のインスタンスタイプです(EC2のドキュメント)。検証が終わったらterraform destroyで消すところまでを1回の作業にしてください。実AWSへapplyせずに試したい場合は、LocalStackとは?AWSをローカルで動かす手順と有料化後の料金・判断基準のtflocalでエンドポイントをローカルへ向ける方法があります。
applyで作ったEC2の中身をAnsibleで構成する手順はTerraformとAnsibleの連携手順:インベントリの受け渡しとactionsでの自動実行で解説しています。
terraform planで止まるエラーと対処
認証エラー3種の文言と原因の切り分け
最初のplanが認証エラーで止まったら、プロファイルの選択、認証情報の有無、認証情報の有効性の順に切り分けます。Terraform 1.16.5とaws 6.68.0で、それぞれの条件を作って実行したときの文言は次の3種でした。
# 1. AWS_PROFILE(またはprofile)の名前が ~/.aws/config に無い
Error: failed to get shared config profile, example-dev
# 2. profile指定も環境変数も無い
Error: No valid credential sources found
# 3. アクセスキーが無効
Error: Retrieving AWS account details: validating provider credentials:
retrieving caller identity from STS: operation error STS: GetCallerIdentity,
https response error StatusCode: 403, ... api error InvalidClientTokenId:
The security token included in the request is invalid.
1はAWS_PROFILEやprofileに書いた名前の綴りかAWS_CONFIG_FILEの向き先、2はaws sso loginの実行忘れかCIでロールを引き受けるステップの欠落を疑います。3はSTSがアクセスキーを有効と認めなかったという意味で、失効・削除済みのキーや、想定と違う場所から読まれたキーが候補です。aws configure listを実行すると、キーをマスクした状態で取得元(環境変数か設定ファイルか)が表示されます。環境変数が原因ならunset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKENで外します。
認証は通ったのにapplyの途中でUnauthorizedOperationが出た場合、EC2系のAPIはエラーにエンコードされた認可メッセージを付けて返します。そのままでは読めないので、STSで復号します。
aws sts decode-authorization-message \
--encoded-message "<エラーに含まれる文字列>" \
--query DecodedMessage --output text
復号結果には、明示的なDenyによる拒否か許可が無いことによる拒否か、リクエストしたプリンシパル、アクション、リソース、条件キーの値が入ります(DecodeAuthorizationMessageのAPIリファレンス)。復号を実行するプリンシパルにはsts:DecodeAuthorizationMessageの権限が必要なので、調査を担当するロールに付けておきます。
ロックが残ったときのforce-unlock
applyの途中でPCがスリープした、CIのジョブが強制終了された、といった場合はロックが残り、次の実行がError: Error acquiring the state lockで止まります。エラーにはLock InfoとしてID、Path、Operation、Who、Version、Createdが並ぶので、まずWhoとCreatedで「本当に誰も実行していないか」を確かめます。誰も動かしていないと確認できたら、表示されたIDを渡して解除します。
terraform force-unlock 7f6394d0-ce97-b9d4-c337-c1737062e1b2
force-unlockのドキュメントのとおり、このコマンドは現在の構成のロックだけを外し、インフラには触りません。IDは誤って別のロックを外さないためのnonceとして働きます。実行中の相手がいる状態で外すとstateが壊れるので、-lock=falseで回避する運用は採りません。
terraform-aws-modulesのVPCモジュールと自作モジュールの分岐
公開VPCモジュールで複数AZのネットワークを組む設定例
実運用のVPCは、サブネットを複数のアベイラビリティゾーンへ並べ、NATゲートウェイとルートテーブルまで揃えるとリソースブロックが数十本になります。この定型部分はterraform-aws-modules/terraform-aws-vpcに任せる方法があり、最新は6.7.3(2026年9月18日UTC公開)です。次の例はaws 6.68.0と組み合わせてterraform validateが通っています。.terraform.lock.hclが記録するのはプロバイダの版だけでモジュールの版は記録しないため、モジュールはversion = "6.7.3"と完全に固定し、上げるときは値の変更をレビューに通します。
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "6.7.3"
name = "sample-vpc"
cidr = "10.0.0.0/16"
azs = ["ap-northeast-1a", "ap-northeast-1c"]
public_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
private_subnets = ["10.0.11.0/24", "10.0.12.0/24"]
enable_nat_gateway = true
single_nat_gateway = true
}
single_nat_gateway = trueはNATゲートウェイを1台に絞る指定です。NATゲートウェイは稼働時間と処理データ量の両方で課金されるため検証環境では台数を減らしますが、そのAZが落ちると全プライベートサブネットの外向き通信が止まります。AZ障害時も他のAZの外向き通信を保ちたい本番では、single_nat_gateway = falseとone_nat_gateway_per_az = trueでAZごとに1台置きます。READMEには、ルートモジュールでのVPCフローログ作成が6系では非推奨で7.0.0で削除予定とあるため、フローログは同じリポジトリのmodules/flow-logを使います。
自作モジュールへ寄せる条件と1.16のモジュール内import
公開モジュールが向くのは、VPCのように構成の型がほぼ決まっていて自社固有の要件が少ないリソースです。社内の命名規則・タグ規約・セキュリティ基準をモジュールの境界で強制したい場合や、入力変数の多さがレビューの負担になっている場合は、必要な引数だけを出す自作モジュールで包みます。分割の粒度はTerraform moduleの分割粒度とoutput設計|自作とRegistryの判断で扱っています。
手作りの既存VPCをモジュール管理へ移すときは、1.16.0からimportブロックをモジュールの内側に書けます。1.15系まではルートモジュールに置く必要があったため、取り込み用の記述をモジュールごとにまとめられるようになりました。手順はterraform importで既存リソースをコード化する手順|importブロックとCLIの使い分けにあります。
CloudFormation・AWS CDK・CDKTFと比べたTerraformの選び方
AWS単独ならCloudFormationとCDKを選ぶ条件
管理対象がAWSだけで、stateファイルの保管と排他制御を自分たちで運用したくないなら、CloudFormationかAWS CDKが有利です。状態はAWS側が持つため、tfstateの置き場もロックも検討から外れます。AWS Organizations配下へStackSetsで一括展開する要件も純正の土俵です。ただしCDKは、cdk bootstrapでS3バケット・ECRリポジトリ・IAMロールを含むCDKToolkitスタックを先に作ります。
Terraformを選ぶ管理対象と、見送るべき体制
Terraformを選ぶ理由が立つのは、管理対象がAWSの外へ広がるときです。AzureやGCP、Datadog、GitHub、CloudflareのようなSaaSまで同じ記法とplan・applyの流れで管理できます。他クラウドの手順はTerraformでAzureを構築する手順|azurerm 5系の認証とbackend設計とTerraformでGCPを構築する手順|google 7系の認証とGCSバックエンド設計で扱っています。AWS自身もBest practices for using the Terraform AWS Providerを公開しており、Security・Backends・AWS Provider version managementなどの章立ては設計レビューの観点に使えます。
逆に、対象がAWS単独で、tfstateの保管・ロック・版の更新を担える人が1人しかいない体制では、Terraformは見送るのが妥当です。stateが壊れたときに直せる人がいない構成は、手作業より復旧が難しくなります。プロバイダの変更履歴やセキュリティ修正を確認し、必要な更新を検証して適用する担当を決められない体制も同じです。
CDKTFを新規採用しない理由と既存構成の移行経路
TypeScriptやPythonでTerraformを書くCDK for Terraform(CDKTF)は、新規採用の候補から外します。HashiCorpは2025年12月10日にサンセットとアーカイブを実施し、GitHubのリポジトリは読み取り専用です。最終リリースはv0.21.0(2025年6月4日)で、既存プロジェクトはcdktf synth --hclでHCLを書き出して離脱します。判断材料はCDK for Terraform(CDKTF)とは?提供終了後の移行判断を解説にまとめています。
よくある質問
AWSでTerraformを使うメリットは何ですか?
構成をコードの差分としてレビューでき、同じ定義からステージングと本番を同じ形で作れる点です。この利点はCloudFormationでも得られるため、本記事ではAWSとその外側のサービスを1つの記法とワークフローで管理できる点を、Terraformを選ぶ判断で最も重く見ています。既存のモジュールやチームの習熟を理由にAWS単独で選ぶ判断もあります。
TerraformとTera Termの違いは何ですか?
名前が似ているだけで別物です。TerraformはAWSなどのリソースをコードから作るIaCツール、Tera TermはWindowsでSSH接続などに使う端末エミュレータです。本記事の最小構成はSession Managerで接続するため、SSHクライアントは使いません。
Terraformの実行にAWS CLIのインストールは必要ですか?
Terraformの実行そのものにAWS CLIは不要です。awsプロバイダは共有config・credentialsファイルや環境変数から直接読みます。ただしIAM Identity Centerのプロファイルを使う場合、aws configure ssoとaws sso loginにCLIが要るため、実務ではCLIも入れる構成になります。
tfstateのロックにDynamoDBはもう不要ですか?
新規構築では不要です。1.11未満のCLIが1台でも残っている間はテーブルを残し、全員の版が上がってから外します。手順はbackendの章にまとめています。
IaC(インフラのコード化)とTerraformの関係は?
IaC(Infrastructure as Code)は、サーバーやネットワークの構成を手作業でなく定義ファイルで管理する考え方です。TerraformはそのためのツールでHCLという記法で書いた定義を読み、プロバイダと呼ばれるプラグインを介してAWSなどのAPIを呼びます。AWSを扱うときに読み込まれるのがawsプロバイダです。