5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【AWS/Terraform】Terraformを初めて触ってみた

5
Last updated at Posted at 2026-01-30

はじめに

今回は遂にTerraformを触ってみました!
業務でCloudFormationを使用していたので、よく比較されるTerraformは前からやってみたいと思っていました
Terraformを使うとAWSだけでなく、他SaaS等もIaC管理出来て、実PJでもかなり需要がありそうと感じていました
私の学習の備忘録のような形で実施したことをまとめたので、同じようにこれからTerraformを初めて触る方や、TerraformでAWSを構築する方の参考になれば幸いです

ハンズオンの流れ

1. Terraformインストール

以下からTerraformをインストールする
https://developer.hashicorp.com/terraform

「Install」を押下
image.png

「AMD64」の方の「Download」を押下
image.png

ダウンロードしたZipファイルを解凍して、任意のフォルダに保存
例: C:\Windows\terraform\ に「すべて展開」で保存等
image.png

「Windows+R」>「cmd」でターミナルを開き、以下を実行

Terminal
C:\Windows\terraform\terraform -v

TerraformのVerが表示されることを確認
image.png

2. tflintインストール

次にtflintをインストールする

以下のサイトにアクセス
https://github.com/terraform-linters/tflint/releases

「Assets」>「tflint_windows_amd64.zip」を押下してダウンロード
image.png

ダウンロードしたZipファイルを解凍して、先ほどと同じフォルダに保存
例: C:\Windows\terraform\ に「すべて展開」で保存等

先ほどと同様にターミナルで以下を実行

Terminal
C:\Windows\terraform\tflint -v

tflintのverが確認できること
image.png

3. 環境変数設定

次に環境変数を設定する

管理者権限でPowerShellを開き、以下を実行

パスの部分はご自身の保存したフォルダに応じて変えてください

PowerShell
$env:Path += ";C:\Windows\terraform"
[Environment]::SetEnvironmentVariable('PATH', $Env:Path, 'Machine')

image.png

以下を実行して、設定できたことを確認

PowerShell
terraform -v
tflint -v

以下のようにVerが表示されることを確認
image.png

4. VS Code拡張機能設定

次にVS Codeに拡張機能を設定する

VS Codeの拡張機能(Extensions)より「terraform」で検索し、
「HashiCorp Terraform」をインストール
image.png

「発行元を信頼して、インストール」を押下
image.png

サイドバーにアイコンが追加されることを確認
image.png

5. AWSと連携するためのSSOプロファイル設定

以下を参考にAWSとTerraformを連携する為に、SSOプロファイルを設定した

AWSへログイン
IAM Identy Centerを開き、「有効にする」を押下

初めてIAM Identy Centerを使用する場合のみ実行

image.png

「有効にする」を押下
image.png

組織インスタンスが作成完了(アカウントインスタンスでは許可セット/アカウントへのアクセスできないため組織インスタンスを作成した)
image.png

ユーザを作成する

作成した組織インスタンス>ユーザーを開き、「ユーザーを追加」を押下
image.png

ユーザー名やPWを入力
image.png

「次へ」を押下
image.png

今回はグループには追加せずに、「次へ」を押下
image.png

「ユーザーを追加」を押下
image.png

ユーザーが作成されていることを確認
image.png

登録したメールアドレスにメールが来ているので、「Accept Invitation」を押下
PWを設定した後MFAを設定

その後Your AWS access portal URLよりSSOユーザーでサインできるかを確認
image.png

サインイン完了画面
image.png

組織インスタンス>許可セットを開き、「許可セットを作成」を押下
image.png

「カスタム許可セット」を選択し、「次へ」を押下
image.png

マネージドポリシーで、必要なポリシーを選択
今回はVPC+EC2+ALB+S3を作成しようと思うので、以下を追加

  • AmazonEC2FullAccess
  • AmazonS3FullAccess
  • ElasticLoadBalancingFullAccess

EC2FullAccessの例
image.png

インラインポリシーに以下を追加

AWSアカウントIDはご自身のAWSアカウントIDに置き換える

インラインポリシー
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "CreateAndManageEc2SsmRoleOnly",
            "Effect": "Allow",
            "Action": [
                "iam:CreateRole",
                "iam:GetRole",
                "iam:UpdateAssumeRolePolicy",
                "iam:DeleteRole",
                "iam:TagRole",
                "iam:UntagRole",
                "iam:ListRolePolicies",
                "iam:ListAttachedRolePolicies",
                "iam:ListInstanceProfilesForRole"
            ],
            "Resource": "arn:aws:iam::<AWSアカウントID>:role/ec2-ssm-*"
        },
        {
            "Sid": "AttachOnlyAmazonSSMManagedInstanceCore",
            "Effect": "Allow",
            "Action": [
                "iam:AttachRolePolicy",
                "iam:DetachRolePolicy",
                "iam:ListAttachedRolePolicies"
            ],
            "Resource": "arn:aws:iam::<AWSアカウントID>:role/ec2-ssm-*",
            "Condition": {
                "ArnEquals": {
                    "iam:PolicyARN": "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
                }
            }
        },
        {
            "Sid": "CreateAndManageInstanceProfileOnly",
            "Effect": "Allow",
            "Action": [
                "iam:CreateInstanceProfile",
                "iam:GetInstanceProfile",
                "iam:AddRoleToInstanceProfile",
                "iam:RemoveRoleFromInstanceProfile",
                "iam:DeleteInstanceProfile"
            ],
            "Resource": "arn:aws:iam::<AWSアカウントID>:instance-profile/ec2-ssm-*"
        },
        {
            "Sid": "PassOnlyEc2SsmRoleToEC2",
            "Effect": "Allow",
            "Action": "iam:PassRole",
            "Resource": "arn:aws:iam::<AWSアカウントID>:role/ec2-ssm-*",
            "Condition": {
                "StringEquals": {
                    "iam:PassedToService": "ec2.amazonaws.com"
                }
            }
        }
    ]
}

「次へ」を押下

image.png

許可セットに任意の名前を命名
またセッション時間は作業時間を考慮し、今回は8時間とした
「次へ」を押下
image.png

追加したマネージドポリシーを確認
image.png

インラインポリシーを確認
image.png

確認が完了したら、「作成」を押下
image.png

次にアカウントとユーザーの紐づけ、および先ほど作成した許可セットの紐づけを行う

AWSアカウントを開き、表示されているツリー内の該当AWSアカウントを選択し、「ユーザーまたはグループを割り当て」を押下
image.png

先ほど作成したユーザーを選択し、「次へ」を押下
image.png

先ほど作成した許可セットを選択し、「次へ」を押下
image.png

「送信」を押下
image.png

AWSアカウント>表示されているツリー内の該当AWSアカウントを押下し、ユーザーと許可セットが紐づいたことを確認
image.png

SSOユーザーでAWS access portalに再度ログインすると、以下のようにアカウントが表示されていることを確認
image.png

PowerShellで以下を実行
以下を参考にCLIと対話式で回答していくことで、AWS Configを作成可能

PowerShell
aws configure sso
SSO session name (Recommended): tf-user
SSO start URL [None]: https://XXXXXXX.awsapps.com/start/ # SSOユーザーのAWS access portalのURL(メールから確認可能)
SSO region [None]: ap-northeast-1
SSO registration scopes [sso:account:access]: # そのままEnter
Attempting to automatically open the SSO authorization page in your default browser.
If the browser does not open or you wish to use a different device to authorize this request, open the following URL:

https://d-XXXXXXXX.awsapps.com/start/#/device

Then enter the code:

XXXX-ZZZZ # 認証コード

自動でブラウザが起動
「確認して実行」を押下
image.png

「アクセスを許可」を押下
image.png

承認画面
image.png

再度PowerShellに戻り、以下を回答

PowerShell
The only AWS account available to you is: XXXXXXXX
Using the account ID XXXXXXX
The only role available to you is: tf-permission-set-ec2-s3-elb
Using the role name "tf-permission-set-ec2-s3-elb"
CLI default client Region [ap-northeast-1]: ap-northeast-1
CLI default output format [None]: json
CLI profile name [tf-permission-set-ec2-s3-elb-740625119642]: dev-tf-profile

Powershellで以下を実行し、~/.aws/configを確認

PowerShell
 type ~/.aws/config

入力通りの設定になっていることを確認
image.png

以下コマンドでログインを実行

PowerShell
 aws sso login --profile dev-tf-profile

先ほどと同様に認証画面へ遷移するので、同様の手順で進める

ログイン成功画面
image.png

6. tfファイル作成

まずはVPCを作ってみる

以下main.tfを作成

main.tf
provider "aws" {
  region  = "ap-northeast-1"
  profile = "dev-tf-profile"
}

resource "aws_vpc" "tf-test-vpc" {
  cidr_block           = "192.168.16.0/20"
  enable_dns_support   = true
  enable_dns_hostnames = true

  tags = {
    Name = "tf-test-vpc"
  }
}

resource "aws_subnet" "tf-private-subnet-1a" {
  vpc_id            = aws_vpc.tf-test-vpc.id
  cidr_block        = "192.168.16.0/24"
  availability_zone = "ap-northeast-1a"

  tags = {
    Name = "tf-private-subnet-1a"
  }
}

resource "aws_subnet" "tf-public-subnet-1a" {
  vpc_id                  = aws_vpc.tf-test-vpc.id
  cidr_block              = "192.168.17.0/24"
  availability_zone       = "ap-northeast-1a"
  map_public_ip_on_launch = true

  tags = {
    Name = "tf-public-subnet-1a"
  }
}

7. terraform実行準備(VS Code)

今回はVS Codeのターミナルで実行するため、環境変数を設定

VS Code>Terminalを開き、以下を実行

パスは自身の環境に応じて変更

VS Code Terminal
 $env:Path += ";C:\Windows\terraform"  
 [Environment]::SetEnvironmentVariable('PATH', $Env:Path)

VS Codeのターミナルで以下を実行し、正常にVerが表示されることを確認

VS Code Terminal
terraform -v
tflint -v

まずは再度SSOユーザーでログイン

VS Code Terminal
aws sso login --profile dev-tf-profile

AWSのプロファイルとリージョンは環境変数として設定

VS Code Terminal
$env:AWS_PROFILE="dev-tf-profile"
$env:AWS_REGION="ap-northeast-1"

次にmain.tfを作成した階層へ移動
以下を実行して、main.tfが表示されることを確認

VS Code Terminal
ls

8. Terraform実行

以下を実行して、整形

VS Code Terminal
terraform fmt -recursive

以下を実行して、初期化(初回/Provider更新時に実行要)

initはTerraformがこのコードを実行できる環境を作るイメージ

VS Code Terminal
terraform init

実際の画面
image.png

以下を実行して、文法チェック

VS Code Terminal
terraform validate

以下のように表示されればOK
image.png

以下を実行して、設計、ベストプラクティスのチェック

VS Code Terminal
tflint

すると、以下が表示された

VS Code Terminal
Warning: terraform "required_version" attribute is required (terraform_required_version)

  on main.tf line 1:

Reference: https://github.com/terraform-linters/tflint-ruleset-terraform/blob/v0.13.0/docs/rules/terraform_required_version.md

Warning: Missing version constraint for provider "aws" in `required_providers` (terraform_required_providers)

  on main.tf line 26:
  26: resource "aws_subnet" "tf-public-subnet-1a" {

Reference: https://github.com/terraform-linters/tflint-ruleset-terraform/blob/v0.13.0/docs/rules/terraform_required_providers.md

調査した結果、TerraformのVerとProviderのVerを固定化していないという内容だった
この必要なVerを定義しておかないと、実行環境(PC等)によってVerがバラバラになり、意図しないエラーが発生する恐れがあるとのこと

versions.tfを作成し、以下を定義

私の環境に合わせて、Verを定義しているのでご自身の環境に合わせて適宜Verは変更してください

versions.tf
terraform {
  required_version = ">= 1.14.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 6.0"
    }
  }
}

変更したので再度以下を実行

VS Code Terminal
terraform fmt -recursive
terraform init -upgrade
tflint

今度はtflintを実行しても何も表示されなくなった

以下を実行して、差分確認(実際に作成されるリソースの情報を確認)

VS Code Terminal
 terraform plan -out tfplan

実際の画面
image.png

特にエラー等なければ、最後以下を実行して、リソースを作成

VS Code Terminal
terraform apply tfplan

tfplanを使用してApplyすることでtfplanで確認した内容が環境に反映されるため、再現性がある

作成成功画面
image.png

AWSに作成したVPCを見に行く

無事出来ていました!
image.png

出来たのもつかの間、さっそく削除してみます

以下を実行して、削除

VS Code Terminal
terraform destroy

削除確認があるので、「yes」と入力し、Enterを押下
image.png

以下のように表示されたら削除完了
image.png

AWSの方からも削除されていることを確認
image.png

9. より実践的なファイル構成に変更

ここからはChat GPTにより実践的なファイル構成、コードにリファクタリングしてもらい、色々と試してみました
これから学習していくので、まだおかしなところ多々あると思いますが、ご了承ください

構成は以下

project/
├─ versions.tf
├─ provider.tf
├─ main.tf
├─ variables.tf
├─ outputs.tf

各コードの詳細は以下

versions.tf
terraform {
  required_version = ">= 1.6.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 6.0"
    }
  }
}
provider.tf
provider "aws" {
  region  = var.aws_region
  profile = var.aws_profile
}
main.tf
locals {
  common_tags = {
    Project = var.project_name
    Managed = "terraform"
  }
}

resource "aws_vpc" "this" {
  cidr_block           = var.vpc_cidr
  enable_dns_support   = true
  enable_dns_hostnames = true

  tags = merge(
    local.common_tags,
    { Name = "${var.project_name}-vpc" }
  )
}

resource "aws_subnet" "private_1a" {
  vpc_id            = aws_vpc.this.id
  cidr_block        = var.private_subnet_cidr_1a
  availability_zone = var.az_1a

  tags = merge(
    local.common_tags,
    { Name = "${var.project_name}-private-subnet-1a" }
  )
}

resource "aws_subnet" "public_1a" {
  vpc_id                  = aws_vpc.this.id
  cidr_block              = var.public_subnet_cidr_1a
  availability_zone       = var.az_1a
  map_public_ip_on_launch = true

  tags = merge(
    local.common_tags,
    { Name = "${var.project_name}-public-subnet-1a" }
  )
}
variables.tf
variable "aws_region" {
  description = "AWS region"
  type        = string
  default     = "ap-northeast-1"
}

variable "aws_profile" {
  description = "AWS CLI profile name (SSO profile)"
  type        = string
  default     = "dev-tf-profile"
}

variable "project_name" {
  description = "Name prefix for resources"
  type        = string
  default     = "tf-test"
}

variable "vpc_cidr" {
  description = "VPC CIDR block"
  type        = string
  default     = "192.168.16.0/20"
}

variable "az_1a" {
  description = "Availability Zone for subnets"
  type        = string
  default     = "ap-northeast-1a"
}

variable "private_subnet_cidr_1a" {
  description = "Private subnet CIDR in az_1a"
  type        = string
  default     = "192.168.16.0/24"
}

variable "public_subnet_cidr_1a" {
  description = "Public subnet CIDR in az_1a"
  type        = string
  default     = "192.168.17.0/24"
}
outputs.tf
output "vpc_id" {
  value       = aws_vpc.this.id
  description = "Created VPC ID"
}

output "private_subnet_id_1a" {
  value       = aws_subnet.private_1a.id
  description = "Created private subnet ID (1a)"
}

output "public_subnet_id_1a" {
  value       = aws_subnet.public_1a.id
  description = "Created public subnet ID (1a)"
}

各ファイルの役割となぜ分けるのかは以下(Chat GPTの解説をもとに自分なりにまとめました)

versions.tf

実行するTerraformとProviderのバージョンを固定化
変更頻度が低いため、ファイルを分ける

provider.tf

接続設定として、TerraformがどのAWSアカウント/リージョンに接続するかを定義
開発環境や本番環境等、環境ごとにここだけ変えることが多いので、ファイルを分ける

variables.tf

各コードのパラメータの設定値を定義(変更可能な設定値が可視化)
main.tfのハードコーディングを避ける
またコードの再利用性を高めるために、ファイルを分ける
環境分離(dev/prod)が可能となる

main.tf

AWSリソースを定義

outputs.tf

作成したリソースのIDやARN等の情報を表示し、他モジュールや環境から参照可能とする

将来的にモジュール化、環境分離をするためにも上記の構成が必要らしい

上記に変更し、再度以下を実行してリソースを作成(上記ファイルを作成した階層まで移動していることが前提)

VS Code Terminal
terraform fmt -recursive
terraform init
tflint
terraform validate
terraform plan -out tfplan
terraform apply tfplan

作成成功画面
先ほどと異なり、Outputとして作成されたVPCのID等が表示されている
image.png

再度AWS上でVPCが作成されていることを確認
image.png

最後に再度作成したリソースを削除

VS Code Terminal
terraform destroy

image.png

まとめ

念願のTerraformを触ってみた第一印象は、思ったより簡単にAWSのリソースができる!でした
勝手なイメージで最初のハードルが高いのかなと思っていましたが、自分はCloudFormationを使ってきて、IaCについて業務経験が2年ほどあるので、Terraformの考え方もすっと理解することができました

とはいえ、実運用を想定するとまだまだ学習していかないといけない要素がたくさんあることも見えてきたので、次回はそちらに取り組みたいです

参考にさせていただいたサイト

5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?