Terraformとは?AWSでの使い方をインストールから実践まで実際の画面で解説

  • 2026.10.09
       
【Terraform】インフラをコードで構築・管理する

AWSなどのクラウドサービスを利用する際に、管理画面から手作業で設定を行うと、既存設定の管理や同じ環境の複製が難しくなるといった問題が発生します。
そこで利用されるのが、「IaC(Infrastructure as Code)」という考え方です。

この記事では、IaCを実現するための代表的なツールの一つである「Terraform」について、基本的な仕組みからAWSでの使い方までを解説します。
記事の後半では、実際にTerraformでAWSにS3バケットを作成し、変更・削除するまでの手順を、実行画面とあわせて紹介します。

目次

Terraformとは?インフラをコードで管理する「IaC」ツール

Terraformは、HashiCorpが開発しているIaC(Infrastructure as Code)ツールです。
IaCとは、サーバーやデータベース、ストレージなどのインフラ構成を、コードで定義することによって構築・管理する考え方のことを言います。

通常、クラウド上にリソースを作成する際は、AWSなどの管理画面から必要な項目を入力して設定します。
そのため、同じような構成を別の環境で再現しようとする場合に、管理画面で同じ作業を繰り返さなければいけません。

一方、Terraformを利用すると、設定を一から手作業で行うのではなく、コードを利用して環境を構築することができます。
また、コードをGitなどのバージョン管理システムで管理すれば、「いつ、どのような変更を行ったのか」を追跡することも可能です。

Terraformのもう一つの大きな特徴は、「宣言型」でインフラを定義することです。
シェルスクリプトなどの手続き型では、「ネットワークを作る→サブネットを作る→サーバーを作る」のように、作業の手順を順番に書く必要があります。
一方、Terraformでは「最終的にどのような状態にしたいか(あるべき姿)」だけを書けば、作成の順番やリソース同士の依存関係はTerraformが判断し、現在の状態との差分だけを実行してくれます。

手続き型と宣言型の違いを比較した図。手続き型はネットワーク・サブネット・サーバーを順番に作る手順を書き、宣言型のTerraformはあるべき姿を書くだけで差分を計算して必要な操作だけを実行する

TerraformはAWS専用のツールではなく、Microsoft AzureやGoogle Cloudなど、様々なサービスに対応しています。
そのため、複数のクラウドサービスを利用する環境でも、Terraformを使ってインフラをコードで管理できます。
Terraformの概要や最新情報は、Terraform公式サイトで確認できます。

Terraformの基本的な仕組み

Terraformがどのようにインフラを管理しているのかを理解する上で重要なのが、Provider、Resource、Stateの3つの要素です。

ProviderとResourceの役割

Providerは、Terraformと外部のサービスやクラウドプラットフォームを接続する役割を持ちます。
たとえばAWS Providerを設定することで、TerraformからAWSの各種リソースを操作できるようになります。

一方、Resourceは、EC2インスタンスやS3バケットなど、Terraformで管理する具体的なインフラリソースを表します。
Terraformのコードでは、「どのProviderを使い、どのResourceをどのような設定で作るか」を記述していきます。

State(状態ファイル)とは

Terraformを理解する上でもう一つ重要なのが、Stateです。
Terraformは、コードの記述内容だけを見てインフラを管理するわけではなく、管理しているリソースの状態を記録したStateファイルを利用し、コード上で定義された状態と実際のインフラの状態を比較します。

作業ディレクトリで初めてterraform applyを実行すると、「terraform.tfstate」というStateファイルが作成されます。
コードを変更して設定を更新すると、Terraformはこのファイルをもとにインフラの状態を比較し、必要な変更を判断します。

planやapplyの実行時には、Stateに記録された情報をもとにAWS上の実際の状態も確認したうえで、コードとの差分を計算します。
コード・State・実際のインフラの関係を図にすると、次のようになります。

Terraformがインフラを管理する仕組みの図。コード(main.tf)とState(terraform.tfstate)、実際のインフラ(AWS)をTerraformが比較し、planで差分を表示、applyで差分だけを反映してStateを更新する

この仕組みによって、Terraformでは現在の状態と目的の状態との差分を確認しながらインフラを管理できます。
なお、Stateファイルにはリソースの詳細情報や機密情報が平文で記録される場合があるため、取り扱いには注意が必要です(詳しくはTerraformのState公式ドキュメントを参照してください)。

コードの基本的な書き方(HCL)

Terraformでは、主にHCL(HashiCorp Configuration Language)という設定言語を使ってコードを記述します。
JSON形式で設定を書くことも可能ですが、一般的にはHCL形式が利用されています。

HCLは「ブロック」と呼ばれる単位の組み合わせで構成されます。
リソースを定義するresourceブロックの基本的な構文は、次のとおりです。

HCLの基本構文
resource "リソースタイプ" "リソース名" {
  引数名 = 値
}

ブロックタイプの後ろには「ラベル」を指定します。
resourceブロックの場合は、1つ目のラベルがリソースタイプ(作成するリソースの種類)、2つ目のラベルがリソース名(Terraformのコード内でそのリソースを識別するための名前)です。
たとえば、S3バケットを定義する場合は次のように記述します。

S3バケットの定義例
resource "aws_s3_bucket" "example" {
  bucket = "my-example-bucket"
}

resourceブロック1つが、管理対象のリソース1つに対応します。
ほかにも、Terraform自体の設定を行うterraformブロックや、Providerの設定を行うproviderブロックなどがあり、これらを組み合わせてコードを書いていきます。

各サービスで指定できるリソースタイプや引数は、Terraform RegistryからProviderごとのドキュメントを開くことで確認できます。
AWSの場合は、AWS Providerの公式ドキュメントの左側のメニューから、サービスごとのリソースを探せます。

Terraform RegistryのAWS Providerドキュメントページ。左側のメニューからサービスごとのリソースを探せる

Terraformでは、設定ファイルの拡張子として「.tf」を使用します。
同じディレクトリにある.tfファイルは、Terraformの実行時にまとめて読み込まれます。

ディレクトリ構成の例
terraform/
├── main.tf
└── variables.tf

規模の大きさにもよりますが、上記のように、リソースや変数などを役割ごとにファイルへ分けて管理するのが一般的です。
本記事の実践では、シンプルにmain.tfの1ファイルだけを使用します。

【実践】Terraformを使ってAWSにS3バケットを作ってみる

ここからは、実際にTerraformを使ってAWS上にS3バケットを作成し、変更・削除するまでの流れを体験してみましょう。
全体の流れは次のとおりです。

手順作業内容主に使うコマンド
事前準備AWSアカウントとIAMユーザーを用意する-
手順1Terraformをインストールし、AWSの認証情報を設定するterraform -version
aws configure
手順2S3バケットを定義するコード(main.tf)を書く-
手順3初期化・実行計画の確認・適用を行うterraform init
terraform plan
terraform apply
手順4AWSコンソールで確認し、変更・削除を行うterraform state list
terraform plan
terraform apply
terraform destroy
応用変数と出力を使ってコードを使い回しやすくするterraform output

本記事では、macOS(Apple シリコン)のターミナルで動作を確認しています。
Terraform 1.16.4、AWS Provider 6.67.0を使用しています。

事前準備:AWSアカウントとIAMユーザーを用意する

TerraformからAWSのリソースを操作するためには、AWSのアカウントが必要です。
まだAWSアカウントを持っていない場合は、AWSの公式サイトからアカウントを作成しておきましょう。

▼こちらもチェック▼
AWSとは?わかりやすくAWSの基本を解説 AWSとは【入門】基礎からわかりやすく解説 ▶

また、TerraformからAWSを操作する際には、AWS上で適切な権限を持った認証情報が必要になります。
AWSアカウント作成時に使用する「ルートユーザー」はすべての操作ができる強い権限を持つため、日常の作業にはルートユーザーを使わず、IAMユーザーを作成して利用します。

AWSマネジメントコンソールで「IAM」→「ユーザー」→「ユーザーの作成」と進み、作業用のIAMユーザーを作成しましょう。
許可の設定では「ポリシーを直接アタッチする」を選択し、今回は学習・検証目的として、S3の全操作を許可するAWS管理ポリシー「AmazonS3FullAccess」を付与して進めていきます。

ただし、AmazonS3FullAccessはアカウント内のすべてのS3バケットを操作できる広い権限です。
実際の運用では、必要な操作・必要なリソースだけを許可する「最小権限の原則」に従ってポリシーを設計することが重要です。
IAMの考え方については、IAMのセキュリティのベストプラクティス(AWS公式ドキュメント)も参考にしてください。

なお、Terraform自体は無料で利用できますが、Terraformで作成したAWSリソースにはAWSの利用料金が発生する可能性があります。
S3は保存したデータ量やリクエスト数などに応じた従量課金のため、今回のように空のバケットを作るだけであれば料金はほとんどかかりませんが、詳しくはAmazon S3の料金ページを確認してください。
新規アカウント向けの無料利用枠(クレジット)の内容は時期によって変わるため、AWS無料利用枠の公式ページで最新情報を確認しておきましょう。
いずれの場合も、作業が終わったら不要なリソースは必ず削除することが大切です。

手順1:Terraformのインストールと認証情報の設定

まず、Terraformを利用する環境へTerraformをインストールします。
macOSの場合は、Homebrewを使って次のコマンドでインストールできます。

Terraformのインストール(macOS・Homebrew)
brew tap hashicorp/tap
brew install hashicorp/tap/terraform

WindowsやLinuxでのインストール方法については、Terraform公式のインストールページを参考にしてください。

▼こちらもチェック▼
Homebrewとは?Macへのインストール方法・使い方をエンジニア目線で解説 Homebrewとは?Macへのインストール方法・使い方をエンジニア目線で解説 ▶

インストール後、ターミナルで次のコマンドを実行し、正常にインストールされているかを確認しましょう。

Terraformのバージョン確認
terraform -version

問題がなければ、以下のようにTerraformのバージョンが表示されます。
表示されるバージョン番号は、インストールした時期によって異なります。

ターミナルでterraform -versionを実行し、Terraform v1.16.4 on darwin_arm64と表示された画面

Terraformのインストールが完了したら、続けてTerraformからAWSへアクセスするための認証情報を設定します。
今回は、AWS CLI(AWSをコマンドで操作するための公式ツール)を使って認証情報を設定します。
AWS CLIをインストールしていない場合は、AWS CLIのインストール手順(AWS公式ドキュメント)に沿ってインストールし、次のコマンドでバージョンが表示されることを確認してください。

AWS CLIのバージョン確認
aws --version

認証情報には、IAMユーザーのアクセスキーを使用します。
アクセスキーは、作成したIAMユーザーの詳細画面にある「アクセスキーを作成」から作成できます。
ユースケースの選択画面では「コマンドラインインターフェイス (CLI)」を選択してください。

AWSマネジメントコンソールのIAMユーザー詳細画面。概要欄の右側に「アクセスキーを作成」のリンクがある

アクセスキーを作成すると、以下のようにシークレットアクセスキーとセットで生成されます。
シークレットアクセスキーはこの画面でしか表示・ダウンロードできないため、忘れずに控えておくようにしましょう。
アクセスキーはパスワードと同じように扱い、他人に共有したり、GitHubなどに公開したりしないよう注意してください。

アクセスキーの作成完了画面。アクセスキーとシークレットアクセスキーが表示され、シークレットアクセスキーは後で復元できない旨のメッセージが表示されている

アクセスキーを用意できたら、次のコマンドを実行します。

AWS CLIの初期設定
aws configure

実行すると、AWSのアクセスキーやシークレットアクセスキー、デフォルトリージョンなどの入力を求められます。
今回は東京リージョン(ap-northeast-1)を使用するため、次のように入力します。

aws configureの入力例
AWS Access Key ID [None]: 作成したアクセスキー
AWS Secret Access Key [None]: 作成したシークレットアクセスキー
Default region name [None]: ap-northeast-1
Default output format [None]: json

入力した認証情報は、ホームディレクトリ配下の「.aws/credentials」などのファイルに保存されます(AWS CLIの設定ファイルについての公式ドキュメント)。
TerraformのAWS Providerはこの設定ファイルの認証情報を自動で読み込むため、Terraformのコードにアクセスキーを直接書く必要はありません。

認証情報の設定が完了したら、以下のコマンドでAWSへアクセスできることを確認します。

AWSの認証確認
aws sts get-caller-identity

正常に認証できていれば、次のようにAWSアカウントIDや認証に使用しているIAMユーザーなどの情報が表示されます。

実行結果の例
{
    "UserId": "AIDAXXXXXXXXXXXXXXXXX",
    "Account": "123456789012",
    "Arn": "arn:aws:iam::123456789012:user/SampleUser"
}

なお、今回使用したアクセスキーは有効期限のない「長期的な認証情報」のため、AWSでは推奨度の低い方法と位置づけられています。
実務では、IAM Identity Centerを利用した一時的な認証情報(aws configure sso)などの、より安全な方法を検討しましょう。
各認証方法の推奨順は、AWS CLIの認証とアクセス認証情報(AWS公式ドキュメント)で確認できます。
学習が終わったら、作成したアクセスキーは無効化・削除しておくと安心です。

手順2:S3バケットを定義するコードを書く

次に、TerraformでS3バケットを作成するためのコードを記述します。
まず、Terraform用の作業ディレクトリを作成し、そのディレクトリへ移動します。

作業ディレクトリの作成
mkdir terraform-s3
cd terraform-s3

作業ディレクトリの中に「main.tf」という設定ファイルを作成し、次の内容を記述します。

main.tf
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 6.67.0"
    }
  }
}

provider "aws" {
  region = "ap-northeast-1"
}

resource "aws_s3_bucket" "example" {
  # バケット名は全世界で一意にする必要があるため、独自の名前に変更する
  bucket = "terraform-example-bucket-20261005"
}

S3バケットの名前は、全世界のAWSアカウントで一意(重複不可)である必要があります。
上記のバケット名をそのまま使うと、すでに使われている名前としてエラーになる可能性があるため、自分の名前や日付、ランダムな文字列などを組み合わせた独自の名前に変更してください。
バケット名に使えるのは小文字の英字・数字・ハイフン・ピリオドで、長さは3~63文字です(詳しくはS3バケットの命名規則(AWS公式ドキュメント)を参照)。

ここからは、コードの内容を上から順に確認していきましょう。

terraformブロック内のrequired_providersは、使用するProviderを指定するブロックです。
sourceではAWS Providerの取得元(Terraform Registry上の「hashicorp/aws」)を、versionでは利用するProviderのバージョンを指定しています。

「~> 6.67.0」は、6.67.0以上かつ6.68.0未満のバージョンを使うという意味です。
このようにバージョンを固定しておくことで、Providerの更新によって意図せず挙動が変わることを防げます。
マイナーバージョンの更新も許可したい場合は「~> 6.0」(6.0以上7.0未満)のように指定します。
指定方法の詳細はバージョン制約の公式ドキュメントで確認できます。

その下のproviderブロックでは、AWSのリージョン設定を行っています。
ap-northeast-1は、AWSにおける東京リージョンのリージョンコードです。

最後に、resourceブロックで作成するS3バケットを定義します。
aws_s3_bucketは、AWSのS3バケットを表すリソースタイプです。
bucketでは、作成するS3バケットの名前を指定しています。
指定できる引数の一覧は、aws_s3_bucketのドキュメントで確認できます。

▼こちらもチェック▼
Amazon S3とは【AWS入門】基礎からわかりやすく解説 Amazon S3とは【AWS入門】基礎からわかりやすく解説 ▶

手順3:初期化・実行計画の確認・適用を行う

Terraformでは、コードを書いただけではAWS上にリソースは作成されません。
基本的には、「初期化(init)→ 実行計画の確認(plan)→ 適用(apply)」の順でコマンドを実行して反映させます。

Terraformの基本的な作業の流れの図。terraform initで初期化、terraform planで実行計画を確認、terraform applyで適用し、不要になったらterraform destroyで削除する

まずは、main.tfを保存した作業ディレクトリで次のコマンドを実行します。

Terraformの初期化
terraform init

terraform initは、Terraformの作業ディレクトリを初期化するためのコマンドです。
required_providersで指定したAWS ProviderをTerraform Registryからダウンロードし、Terraformから利用できる状態にします。
「Terraform has been successfully initialized!」と表示されれば、初期化は完了です。

terraform initの実行結果。hashicorp/aws v6.67.0がインストールされ、Terraform has been successfully initialized!と表示されている

初期化時には、Providerのバージョンを記録する「.terraform.lock.hcl」というロックファイルも作成されます。
このファイルは、チームで同じProviderのバージョンを使うためにGitで管理するのが推奨されています。

また、初期化後は次のコマンドで、コードの書式を整えたり、構文に誤りがないかを確認したりできます。
必須の手順ではありませんが、planの前に実行しておくとミスに気づきやすくなります。

コードの整形と構文チェック
terraform fmt
terraform validate

続いて、次のコマンドで実行計画を確認します。

Terraformの実行計画
terraform plan

terraform planは、Terraformのコードをもとに、どのような変更が行われるのかを事前に確認するためのコマンドです。
planの段階では、AWS上のリソースは変更されません。
意図したリソースが作成されるかや、不要な変更が含まれていないかなどを確認できます。

terraform planの実行結果。aws_s3_bucket.exampleが作成(+ create)される予定として表示されている

実行計画では、各リソースの先頭に付く記号で変更の種類が表されます。
今回は新しくS3バケットを作成するため、「+ create」と表示されています。

記号表示意味
+createリソースを新しく作成する
~update in-place既存のリソースをそのまま変更する
–destroyリソースを削除する
-/+destroy and then create replacementリソースを削除してから作り直す(置き換え)

Terraformを利用して運用する際は、planの結果を確認してから変更を反映することが重要です。
特に「-/+」(置き換え)が表示された場合は、既存のリソースが一度削除されるため、内容をよく確認しましょう。

変更内容に問題がないことを確認したら、次のコマンドでコードの内容をAWSへ適用しましょう。

Terraformの適用
terraform apply

実行すると、もう一度実行計画が表示され、最後に「Enter a value:」と確認を求められます。
「yes」と入力してEnterキーを押すと、AWS上にリソースが作成されます(yes以外を入力すると中止されます)。
「Apply complete!」と表示されれば、適用は完了です。

terraform applyの実行結果。確認でyesを入力し、Apply complete! Resources: 1 added, 0 changed, 0 destroyed.と表示されている

terraform applyを実行すると、Stateファイル(terraform.tfstate)も合わせて作成・更新されます。
この時点で、作業ディレクトリは次のような構成になっています。

apply後のディレクトリ構成
terraform-s3/
├── .terraform/           # initでダウンロードしたProviderなど
├── .terraform.lock.hcl   # Providerのバージョンを記録するロックファイル
├── main.tf               # 作成した設定ファイル
└── terraform.tfstate     # applyで作成されたStateファイル

手順4:AWSコンソールで確認し、変更・削除まで行う

S3バケットが作成されたら、AWSマネジメントコンソールから確認してみましょう。
S3の画面を開き、バケット一覧にTerraformで指定したバケット名が表示されていれば、無事にS3バケットを作成できています。

AWSマネジメントコンソールのS3汎用バケット一覧に、Terraformで作成したterraform-example-bucket-20261005がアジアパシフィック(東京)リージョンで表示されている画面

Terraform側からも、管理しているリソースを確認できます。
作業ディレクトリで次のコマンドを実行してみましょう。

Terraformで管理しているリソースの確認
terraform state list
terraform show

terraform state listは、Stateに記録されている(Terraformで管理している)リソースの一覧を表示するコマンドです。
今回の例では、次のように表示されます。

実行結果の例
aws_s3_bucket.example

「aws_s3_bucket.example」は、「リソースタイプ.リソース名」の形式で表したリソースの識別名(アドレス)です。
また、terraform showを実行すると、バケットのARNやリージョンなど、Stateに記録されている各リソースの詳しい属性を確認できます。

ここまでがTerraformによる基本的なリソース作成方法です。
しかしながら、Terraformはリソースを作成することだけではなく、作成済みリソースの変更・削除も実行できます。

たとえば、S3バケットにタグを追加してみます。
main.tfのresourceブロックを次のように書き換えます(terraformブロックとproviderブロックはそのままです)。

main.tf(タグ追加後)
resource "aws_s3_bucket" "example" {
  bucket = "terraform-example-bucket-20261005"

  tags = {
    Name        = "Terraform Example"
    Environment = "Test"
  }
}

変更後は、terraform planを再度実行し、変更内容を確認してからterraform applyで反映しましょう。

変更内容の確認と適用
terraform plan
terraform apply

今回はバケットを作り直さずにタグだけを追加するため、実行計画には「~ update in-place」と表示され、「Plan: 0 to add, 1 to change, 0 to destroy.」となります。
このように、TerraformはStateファイルと比較して、差分だけを変更してくれます。

タグ追加後のterraform planの実行結果。aws_s3_bucket.exampleがupdate in-placeとなり、Plan: 0 to add, 1 to change, 0 to destroy.と表示されている

また、Terraformで管理しているリソースを削除したい場合は、主に2通りのやり方があります。

  • 設定ファイルから、対象のリソースに関する記述を消す
  • terraform destroyを実行する

設定ファイルを用いる方法の場合は、これまでと同様に記述内容を変更し、terraform plan→terraform applyの順にコマンドを実行します。
コードから消したリソースは、実行計画で「- destroy」として表示されます。

一方、terraform destroyは、その作業ディレクトリのTerraformで管理しているリソースをすべて削除するコマンドです。

Terraformのリソース削除
terraform destroy

applyと同様に、削除対象のリソースが表示された後に確認を求められるので、内容を確認して「yes」と入力します。
本番環境のように長期間使うリソースに対して実行することは通常ありませんが、練習環境などでリソースをまとめて片付けたい場合に便利なコマンドです(terraform destroyの公式ドキュメント)。

terraform destroyの実行結果。aws_s3_bucket.exampleが削除(destroyed)される予定として表示されている

なお、S3バケットの中にファイル(オブジェクト)が残っていると、バケットを削除できずエラーになります。
その場合は、バケットを空にしてから再度実行してください。
作業が終わったら、AWSコンソールでバケットが削除されていることを確認し、不要な料金が発生しないようにしておきましょう。

応用:変数と出力でコードを使い回しやすくする

ここまでのmain.tfでは、バケット名をコードに直接書いていました。
Terraformでは、変数(variable)を使うと値をコードの外から渡せるようになり、出力(output)を使うと作成したリソースの情報をapply後に表示できます。
冒頭のディレクトリ構成で紹介したように、変数や出力は役割ごとにファイルを分けて書くのが一般的です。

まず、作業ディレクトリに「variables.tf」を作成し、バケット名を受け取る変数を定義します。

variables.tf
variable "bucket_name" {
  description = "作成するS3バケットの名前"
  type        = string
}

次に、main.tfのresourceブロックを書き換え、バケット名の代わりにvar.変数名の形式で変数を参照します(terraformブロックとproviderブロックはそのままです)。

main.tf(変数を使用)
resource "aws_s3_bucket" "example" {
  bucket = var.bucket_name
}

変数に渡す値は、「terraform.tfvars」というファイルに書いておくと、plan・apply時に自動で読み込まれます。

terraform.tfvars
bucket_name = "terraform-example-bucket-20261005"

最後に、「outputs.tf」を作成し、apply後に表示したい値を定義します。
ここでは、作成したバケットのARN(AWS上でリソースを一意に識別する名前)を出力します。

outputs.tf
output "bucket_arn" {
  description = "作成したS3バケットのARN"
  value       = aws_s3_bucket.example.arn
}

この状態でterraform plan→terraform applyを実行すると、apply完了後に「Outputs:」として出力の値が表示されます(手順4でバケットを削除した場合は、もう一度バケットが作成されます)。

実行結果の例
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Outputs:

bucket_arn = "arn:aws:s3:::terraform-example-bucket-20261005"

出力の値は、あとから次のコマンドでも確認できます。

出力の確認
terraform output

このように変数を使えば、main.tfを書き換えずにterraform.tfvarsの値を変えるだけで、別の名前のバケットを作成できるようになります。
変数と出力の書き方の詳細は、変数(Input Variables)の公式ドキュメントと出力(Output Values)の公式ドキュメントで確認できます。
確認が終わったら、terraform destroyでバケットを削除しておきましょう。

Terraformでよくあるエラーと対処法

ここでは、本記事の手順を試す中で初心者がつまずきやすいエラーと、その対処法を紹介します。
エラーメッセージの細かな表記は、TerraformやAWS Providerのバージョンによって異なる場合があります。

AWSの認証情報が見つからない

planやapplyの実行時に次のようなエラーが表示される場合は、TerraformがAWSの認証情報を読み込めていません。

エラーメッセージの例
Error: No valid credential sources found

主な原因は、aws configureを実行していない、設定したプロファイル名と使用中のプロファイルが異なる、アクセスキーを無効化・削除した、などです。
まずは次のコマンドでAWSにアクセスできるかを確認し、エラーになる場合は認証情報を設定し直してください。

認証情報の確認と再設定
aws sts get-caller-identity
aws configure

名前付きプロファイルを使っている場合は、環境変数AWS_PROFILEで使用するプロファイルを指定してからTerraformを実行します。

バケット名が重複している(BucketAlreadyExists)

applyの実行時に次のようなエラーが表示される場合は、指定したバケット名がほかのAWSアカウントですでに使われています。

エラーメッセージの例
Error: creating S3 Bucket (terraform-example-bucket-20261005): operation error S3: CreateBucket, https response error StatusCode: 409, ..., BucketAlreadyExists: The requested bucket name is not available.

S3のバケット名は全世界で一意である必要があるため、main.tf(変数を使っている場合はterraform.tfvars)のバケット名を別の名前に変更してから、再度planとapplyを実行してください。
なお、「BucketAlreadyOwnedByYou」と表示される場合は、自分のアカウントにすでに同じ名前のバケットが存在しています。
Terraformの外で作成したバケットであれば、削除するか、インポート機能でTerraformの管理下に取り込みます。

バケットが空でないため削除できない(BucketNotEmpty)

destroyの実行時に次のようなエラーが表示される場合は、バケットの中にファイル(オブジェクト)が残っているため削除できません。

エラーメッセージの例
Error: deleting S3 Bucket (terraform-example-bucket-20261005): operation error S3: DeleteBucket, https response error StatusCode: 409, ..., BucketNotEmpty: The bucket you tried to delete is not empty

AWSコンソールのS3画面でバケットを選択して「空にする」を実行し、中身を削除してから再度terraform destroyを実行してください。
学習用のバケットであれば、次のようにforce_destroy = trueを設定してapplyしておくと、destroy時に中のファイルごとバケットを削除できます。

main.tf(学習用:中身ごと削除する設定)
resource "aws_s3_bucket" "example" {
  bucket        = "terraform-example-bucket-20261005"
  force_destroy = true
}

ただし、force_destroyを有効にすると、バケット内のファイルも確認なしで完全に削除されます。
大切なデータを保存するバケットでは使用しないでください。

Providerのバージョンが合わない

required_providersのversionを変更した後にinitやplanを実行すると、次のようなエラーが表示されることがあります。

エラーメッセージの例
Error: Failed to query available provider packages

Could not retrieve the list of available versions for provider hashicorp/aws: locked provider registry.terraform.io/hashicorp/aws 6.67.0 does not match configured version constraint ~> 6.68.0; must use terraform init -upgrade to allow selection of new versions

これは、ロックファイル(.terraform.lock.hcl)に記録されたProviderのバージョンが、新しいバージョン指定と一致しないために発生するエラーです。
次のコマンドを実行すると、バージョン指定に合うProviderが改めて選ばれ、ロックファイルも更新されます。

Providerのバージョンを更新して初期化
terraform init -upgrade

Stateがロックされている

Terraformは、複数の操作が同時にStateを書き換えないよう、実行中はStateをロック(施錠)します。
次のようなエラーが表示される場合は、ほかのTerraformの操作が実行中か、以前の操作が中断されてロックが残っています。

エラーメッセージの例
Error: Error acquiring the state lock

まずは、別のターミナルなどで同じ作業ディレクトリのTerraformを実行していないか確認し、実行中であれば終了を待ってから再度実行してください。
ほかに実行中の操作がないことを確認できた場合に限り、エラーメッセージに表示されるロックID(Lock Info内のID)を指定して、次のコマンドでロックを解除できます。

Stateのロック解除
terraform force-unlock ロックID

実行中の操作があるのにロックを解除すると、Stateが壊れる原因になるため注意してください(terraform force-unlockの公式ドキュメント)。

Terraformのメリット・デメリット

Terraformを使うメリット

【インフラ構成をコードとして管理できる】

Terraformの大きなメリットは、冒頭でも述べたように、インフラの構成をコードとして管理できることです。
作成内容の見返しやすさや再現のしやすさ、変更履歴の追跡のしやすさなど、コードで記述することで管理にかかる手間を大きく減らせます。
コードをGitHubなどで管理すれば、変更内容をチームでレビューしてから反映する運用も可能です。

Terraform自体はAWS専用のツールではないため、複数のクラウドサービスを利用する環境でも同じようにコードで管理できるのも特徴の1つです。

▼こちらもチェック▼
GitHubとは?初心者向けにメリットや知識、機能を解説 GitHubとは?初心者向けにメリットや知識、機能を解説 ▶

【変更内容を事前に確認できる】

実践でも解説したように、Terraformでは、terraform planコマンドを使用することで変更前に実行計画(プレビュー)を確認できます。
変更内容を一目で把握しやすく、意図しない変更を防ぐための方法として非常に便利なコマンドです。

管理画面から手作業で修正する場合、修正箇所のみを抜き出して比較するのは手間がかかるため、Terraformを利用する上でのメリットの1つと言えます。

Terraformを使う前に知っておきたい注意点

【Stateファイルの管理が必要】

Terraformは、Stateファイルを利用してインフラの状態を把握するため、ファイルが失われたり、複数人が同時に同じファイルを操作したりすると、意図しない問題が発生する可能性があります。
チームで利用する場合は、StateファイルをS3やHCP Terraformなどのリモート環境(バックエンド)で共有し、同時操作を防ぐロック機能を有効にするのが一般的です(S3バックエンドの公式ドキュメント)。

また、Stateファイルにはリソースの属性値がそのまま記録され、パスワードなどの機密情報が平文で含まれる場合があります(Stateに含まれる機密データについての公式ドキュメント)。
コードをGitで管理する場合は、次のような.gitignoreを用意して、Stateファイルなどをリポジトリに含めないようにしましょう。

.gitignore
# Providerなどがダウンロードされるディレクトリ
.terraform/

# Stateファイル(機密情報を含む可能性がある)
*.tfstate
*.tfstate.*

# 変数ファイル(機密情報を含む場合)
*.tfvars

【Terraformだけで全てを管理できるわけではない】

Terraformは、インフラの構築・変更・削除をコードで管理するためのツールです。
しかし、アプリケーションそのもののデプロイやサーバー内部の細かな設定など、Terraformが必ずしも得意とは限らない領域もあります。

そのため、Terraformですべての作業を行おうとするのではなく、目的に応じて他のツールと組み合わせることも重要です。

【コードを書けば安全というわけではない】

コードの記述内容を間違えた場合、実際のインフラにも当然ながら誤った変更が適用されてしまいます。
そのため、terraform planで変更内容を確認することや、コードをバージョン管理すること、必要に応じてレビューを行うことが重要です。

また、AWSの認証情報などの機密情報をTerraformのコードへ直接記述しないことも、運用する上で大事なポイントとなります。

CloudFormation・Ansibleなど他ツールとの違い

Terraformとよく比較されるツールに、CloudFormationとAnsibleがあります。
それぞれの主な違いは次のとおりです。

比較項目TerraformCloudFormationAnsible
提供元HashiCorpAWSRed Hat(オープンソースのコミュニティ版あり)
主な用途インフラリソースの作成・変更・削除AWSリソースの作成・変更・削除サーバーの設定やソフトウェアの導入などの構成管理
対応範囲AWS・Azure・Google Cloudなど多数(Provider経由)主にAWSサーバーやネットワーク機器、クラウドなど
記述形式HCLJSON/YAMLYAML(Playbook)
状態の管理Stateファイルを利用者が管理するAWS側(スタック)で管理されるStateファイルのような状態ファイルは持たない

CloudFormationとの違い

CloudFormationは、AWSが提供しているIaCサービスです。
Terraformと同じように、テンプレート(JSONまたはYAML形式のファイル)でAWSのリソースを定義し、その内容をもとにインフラを構築・管理できます。

Terraformが複数のクラウドサービスに対応しているのに対し、CloudFormationは基本的にAWSのサービスを対象としています。
そのため、複数のクラウドサービスを利用する場合は、Terraformのようなマルチクラウドに対応したツールが適しています。

記述方法も異なります。
同じS3バケットを作成するコードを比べると、次のようになります。

Terraform(HCL)の場合
provider "aws" {
  region = "ap-northeast-1"
}

resource "aws_s3_bucket" "example" {
  bucket = "my-example-bucket"
}
CloudFormation(YAML)の場合
AWSTemplateFormatVersion: "2010-09-09"
Resources:
  ExampleBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: my-example-bucket

CloudFormationはYAMLまたはJSONでテンプレートを書き、リージョンはテンプレートをデプロイする際に指定します。
Terraformは、HCLの「resource “リソースタイプ” “リソース名”」という共通の書き方で、AWS以外のサービスも同じように定義できるのが特徴です。

一方で、CloudFormationはAWSのサービスとして提供されているため、AWSの各種サービスとの連携を行いやすい点が特徴です。
また、リソースの状態はAWS側で管理されるため、Terraformのように利用者がStateファイルを管理する必要はありません。

▼こちらもチェック▼
【AWS入門】CloudFormationとは|基礎からわかりやすく解説 【AWS入門】CloudFormationとは|基礎からわかりやすく解説 ▶

Ansibleとの違い

Ansibleは、サーバーなどの構成管理や作業の自動化を行うためのツールです。
TerraformとAnsibleはどちらもインフラ管理に利用されますが、得意とする処理が異なります。

Terraformは、AWSのS3やEC2、VPCなど、インフラリソースそのものを作成・変更・削除することを得意としています。
一方、Ansibleは、既存のサーバーに対してソフトウェアのインストールや設定ファイルの変更、サービスの起動などを行うことを得意としています。

どちらか片方のみしか利用できないというわけではなく、たとえば「TerraformでEC2インスタンスを作成し、Ansibleでその中のソフトウェアを設定する」といったように、それぞれの得意分野を活かして役割分担することも可能です。

AWS CDK・Pulumi・OpenTofuとの違い

CloudFormationやAnsible以外にも、IaCを実現するツールはいくつかあります。
Terraformと比較されることが多い代表的なツールは、次のとおりです。

ツール記述方法特徴
AWS CDKTypeScript・Pythonなどのプログラミング言語AWSが提供。コードからCloudFormationのテンプレートを生成してデプロイする。対象は主にAWS
PulumiTypeScript・Python・Goなどのプログラミング言語Terraformと同様に複数のクラウドに対応。条件分岐や繰り返しをプログラミング言語の機能で書ける
OpenTofuHCL(Terraformとほぼ同じ)2023年のTerraformのライセンス変更をきっかけに、変更前のTerraformをもとに作られたオープンソースのツール。Linux Foundation傘下で開発されている

Terraformは、2023年にライセンスがオープンソースライセンス(MPL 2.0)からBSL(Business Source License)に変更されました。
ただし、学習や自社のインフラ管理に使う範囲であれば、これまでどおり無料で利用できます。
使い慣れたプログラミング言語でインフラを書きたい場合はAWS CDKやPulumi、HCLの情報量や対応サービスの多さを重視する場合はTerraformというように、目的やチームのスキルに合わせて選ぶと良いでしょう。

次のステップ:実務でTerraformを使うために

本記事のハンズオンでは、1つのディレクトリで1つのS3バケットを管理しました。
実務では、管理するリソースや環境が増えていくため、次のような仕組みを組み合わせて運用するのが一般的です。

モジュールで構成を部品化する

モジュール(module)は、複数のリソース定義をひとまとめにして、部品のように再利用できる仕組みです。
たとえば、S3バケットの定義を「modules/s3-bucket」ディレクトリにまとめておくと、次のように呼び出すだけで同じ構成のバケットを何度でも作成できます。

モジュールの呼び出し例
module "log_bucket" {
  source      = "./modules/s3-bucket"
  bucket_name = "my-log-bucket-20261005"
}

sourceにはモジュールの場所を指定し、それ以外の引数でモジュール側に定義した変数へ値を渡します。
Terraform Registryでは、多くの人が利用している公開モジュールも探せます(モジュールの公式ドキュメント)。

開発環境・本番環境ごとに管理を分ける

実際のシステムでは、開発環境・検証環境・本番環境のように、同じ構成の環境を複数用意することがよくあります。
このとき重要なのが、環境ごとにStateを分けて管理することです。
同じStateのまま設定値だけを切り替えると、開発用の変更が本番のリソースに適用されるおそれがあります。

代表的な方法は、次のように環境ごとにディレクトリを分け、共通部分はモジュールとして呼び出す構成です。

環境ごとに分けたディレクトリ構成の例
terraform/
├── modules/
│   └── s3-bucket/        # 共通のモジュール
│       ├── main.tf
│       ├── variables.tf
│       └── outputs.tf
└── environments/
    ├── dev/              # 開発環境(Stateも別)
    │   ├── main.tf
    │   └── terraform.tfvars
    └── prod/             # 本番環境(Stateも別)
        ├── main.tf
        └── terraform.tfvars

各環境のディレクトリでinit・plan・applyを実行すれば、Stateも環境ごとに別々に作成されます。
環境ごとの違い(バケット名など)は、それぞれのterraform.tfvarsで指定します。

Stateをリモートで管理する

チームでTerraformを使う場合は、Stateファイルを各自のPCではなく、S3などのリモートの保存先(バックエンド)で共有します。
S3をバックエンドにする場合は、terraformブロックに次のようなbackendブロックを追加します。

main.tf(S3バックエンドの設定例)
terraform {
  backend "s3" {
    bucket       = "my-terraform-state-bucket"
    key          = "terraform-s3/terraform.tfstate"
    region       = "ap-northeast-1"
    use_lockfile = true
  }
}

bucketにはStateを保存する既存のS3バケットを、keyにはバケット内での保存先のパスを指定します。
use_lockfile = trueを指定すると、S3上のロックファイルによって複数人の同時操作を防げます(Terraform 1.10以降で利用可能)。
backendブロックを追加・変更した後は、terraform initを再実行してください。
Stateを保存するバケットは、誤って削除・上書きしても復元できるよう、バージョニングを有効にしておくのがおすすめです。

CI/CDでplanとapplyを自動化する

チーム開発では、TerraformのコードをGitHub ActionsなどのCI/CDツールと連携させる運用も一般的です。
たとえば、プルリクエストを作成したタイミングでplanを自動実行して結果をレビューし、mainブランチにマージされたらapplyを実行する、といった流れを自動化できます。

このとき、AWSの認証にはアクセスキーを使わず、OIDC(OpenID Connect)でIAMロールを引き受ける方法が推奨されています。
具体的な手順は、HashiCorp公式のGitHub ActionsチュートリアルやGitHub Actionsの公式ドキュメントを参考にしてください。

▼こちらもチェック▼
DevOpsとは?【入門】アジャイル開発との違い、メリットを解説 DevOpsとは?【入門】アジャイル開発との違い、メリットを解説 ▶

Terraformに関するよくある質問

Q. Terraformは無料で使えますか?

A. 本記事で使用したTerraformのCLI(コマンドラインツール)は、学習や自社のインフラ管理に使う範囲であれば無料で利用できます。
チームでの運用を支援するクラウドサービス「HCP Terraform」には、無料プランと有料プランがあります。
なお、Terraformで作成したAWSなどのリソースには、各クラウドサービスの利用料金が別途かかる点に注意してください。

Q. Terraformを学ぶのにプログラミングの経験は必要ですか?

A. HCLは「どのようなリソースを、どのような設定で作るか」を宣言的に書く言語のため、本格的なプログラミング経験がなくても基本的な使い方は習得できます。
ただし、何をコードで定義するのかを理解するために、AWSなどのクラウドサービスやネットワークの基礎知識はあったほうがスムーズです。

Q. Stateファイルを削除してしまった場合はどうなりますか?

A. Stateファイルを削除しても、AWS上のリソースは削除されずに残ります。
ただし、Terraformはそのリソースを管理していないと判断するため、そのままapplyすると同じリソースを新しく作成しようとして、エラーや重複の原因になります。
既存のリソースをTerraformの管理下に戻すには、インポート機能を使います。
Stateファイルを失わないためにも、実務ではリモートのバックエンドでStateファイルを管理するのがおすすめです。

Q. AWS用に書いたコードは、ほかのクラウドでもそのまま使えますか?

A. そのままでは使えません。
HCLの書き方やinit・plan・applyといった操作の流れは共通ですが、リソースタイプや引数はProviderごとに異なります。
たとえば、AWSのS3バケットは「aws_s3_bucket」、Google CloudのCloud Storageバケットは「google_storage_bucket」のように別のリソースとして定義するため、利用するクラウドに合わせてコードを書く必要があります。

まとめ

Terraformは、インフラの構成をコードとして定義し、そのコードをもとにインフラを構築・管理できるIaCツールです。
S3やEC2、VPC、データベースなど、様々なインフラリソースを管理できます。

基本的な使い方は、コードを書いたら「terraform init → terraform plan → terraform apply」の順に実行し、不要になったら削除するという流れです。
まずは本記事の手順のように小さなリソースから試し、planの結果を確認する習慣を身につけましょう。
慣れてきたら、変数・出力やモジュール、Stateのリモート管理などを取り入れ、実務に近い構成に挑戦してみてください。

導入を検討する際は、CloudFormationやAnsibleなどのツールと特徴を比較しながら、環境や使用目的に適したものを選択すると良いでしょう。
さらに詳しく学びたい場合は、Terraform公式のAWS入門チュートリアルも参考にしてください。

     

AWSカテゴリの最新記事