AWSの無料枠で出来る範囲のチュートリアルがあったので試してみた経過を簡単にまとめてみました。
AWS等の実際の画面や操作はどんな感じか知りたい方を読者対象としているつもりです。
著者はAWS クラウドプラクティショナー、ソリューションアーキテクト アソシエイト という資格を取得済みで「AWSってなんぞや?」という概要を知識としてある程度理解しているが、実際にAWSの画面を触ったことが無いという状態でAWSのチュートリアルをこなしていくという状況です。
今回の内容としては、今まで実装してきた Terraform のコードが各所で何をしているのかを見ていこうと思います。
terraform の main.tf の解説
今の main.tf はこのような構成です。
VPC(ネットワーク)
├─ サブネット×2(AZ分散)
├─ IGW(インターネット接続)
├─ ルートテーブル
├─ セキュリティグループ
│
├─ EC2(nginx)
│
└─ ALB(ロードバランサー)
└─ ターゲットグループ → EC2
🧩 ① provider(AWS接続設定)
provider "aws" {
region = "ap-northeast-1"
}
💡 役割
TerraformがどのAWSに接続するか決める
🧩 ② VPC(ネットワークの土台)
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
}
💡 役割
AWS上の「自分専用ネットワーク」
🧩 ③ サブネット(配置場所)
resource "aws_subnet" "public" {
cidr_block = "10.0.1.0/24"
}
resource "aws_subnet" "public2" {
cidr_block = "10.0.2.0/24"
}
💡 役割
EC2やALBを置く場所
❗ なぜ2つ?
ALBは別アベイラビリティゾーン(AZ)に2つ必要
👉 高可用性
🧩 ④ IGW(インターネット接続)
resource "aws_internet_gateway" "igw" {
vpc_id = aws_vpc.main.id
}
💡 役割
インターネットへの出口
🧩 ⑤ ルートテーブル(通信ルール)
resource "aws_route_table" "public_rt" {
# インターネットへのルート
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.igw.id
}
}
💡 意味
全部の通信 → インターネットへ
🧩 ⑥ セキュリティグループ
🎯 まず前提(超重要)
セキュリティグループ = インスタンス単位のファイアウォール
特徴
✔ ステートフル(戻り通信は自動許可)
✔ インバウンド(入ってくる通信)
✔ アウトバウンド(出ていく通信)
🖥 EC2用
resource "aws_security_group" "web_sg" {
name = "web-sg"
vpc_id = aws_vpc.main.id
# HTTP(Webアクセス)
# HTTP許可(80番)
# 💡 意味
# 全世界 → EC2の80番ポートを許可
# 🔥 これでできること
# http://IP → アクセス可能
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
# SSH(接続用)※本番では制限推奨
# 💡 意味
# どこからでもSSH接続可能
# ❗ 注意
# 本番では危険
# → 理想 👇
# cidr_blocks = ["あなたのIP/32"]
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
# アウトバウンド
# 💡 意味
# EC2 → 外部への通信は全部OK
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "terraform-web-sg"
}
}
ALB → EC2 のみ許可
「あなたのIP」は 自分のグローバルIPアドレス です
🔍 一番簡単な確認方法
🥇 方法①(おすすめ)
ブラウザで👇を開く
または👇
💡 /32 の意味
/32 = そのIP「1台だけ」許可
❗ これは変わる可能性あり
自宅Wi-Fi → OK
カフェWi-Fi → 別IP
スマホ回線 → 別IP
👉 つまり
接続できなくなったらIP更新が必要
🌐 ALB用
resource "aws_security_group" "alb_sg" {
name = "alb-sg"
vpc_id = aws_vpc.main.id
# ALBはインターネットからアクセスを受ける入口
# なので、全世界からのアクセスを許可
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
インターネット → ALB を許可
🔥 ここが重要
EC2に直接アクセス不可
👉 セキュリティ強化
💡 全体イメージ
インターネット
↓
ALB(誰でもOK)
↓
EC2(ALBだけOK)
❌ 間違い
ALBで制限しようとする
✅ 正解
EC2で「入口制限」する
まとめ
| リソース | 許可対象 |
|---|---|
| ALB セキュリティグループ | 0.0.0.0/0 |
| EC2 セキュリティグループ | ALB SGのみ |
🧩 ⑦ EC2(nginxサーバー)
resource "aws_instance" "web" {
ami = "ami-0c3fd0f5d33134a76"
instance_type = "t3.micro"
subnet_id = aws_subnet.public1.id
# SG設定
# ALBからの通信しか受けない
vpc_security_group_ids = [aws_security_group.web_sg.id]
user_data = <<-EOF
#!/bin/bash
amazon-linux-extras install -y nginx1
systemctl start nginx
systemctl enable nginx
EOF
}
💡 user_data: 起動時に自動でnginxインストール&起動
amazon-linux-extras install -y nginx1
systemctl start nginx
🎯 結果
EC2起動 → nginx自動起動
🧩 ⑧ ALB(ロードバランサー)
# AWSのロードバランサーを作る
# 名前は「alb」
# → Terraform内での参照名👇
# aws_lb.alb
resource "aws_lb" "alb" {
# AWS上での名前 (コンソールに表示される名前)
name = "terraform-alb"
# 値 内容
# false インターネット公開
# true VPC内部専用
internal = false
# タイプ 用途
# application HTTP/HTTPS
# network TCP/UDP
# 今回
# HTTP通信(nginx)なので application
load_balancer_type = "application"
# ALBに適用するファイアウォール
# インターネット → ALB を許可
# ALBも「サーバー」なので👇
# セキュリティグループが必要
security_groups = [aws_security_group.alb_sg.id]
# ALBを配置する場所(複数)
# なぜ2つ必要?
# → 異なるアベイラビリティゾーンに配置するため
# 💡 メリット
# 片方落ちてもサービス継続
subnets = [
aws_subnet.public.id,
aws_subnet.public2.id
]
# AWSの管理用ラベル
tags = {
Name = "terraform-alb"
}
}
🧩 ⑨ ターゲットグループ
resource "aws_lb_target_group" "tg" {
name = "secure-tg"
port = 80
protocol = "HTTP"
vpc_id = aws_vpc.main.id
}
💡 役割
「どこにリクエストを送るか」を定義
🔥 重要な概念
ALBは👇
直接EC2を知らない
👉 代わりに👇を見る
ターゲットグループ
イメージ
ALB → TG → EC2
🧩 ⑩ EC2をターゲットに登録
resource "aws_lb_target_group_attachment" "attach" {
target_group_arn = aws_lb_target_group.tg.arn
target_id = aws_instance.web.id
port = 80
}
💡 役割
EC2をターゲットグループに登録する
🔥 これがないと
ALB → どこに送るか不明
👉 エラー or 503
イメージ
ターゲットグループ
↓
EC2を追加(ここ)
🧩 ⑪ リスナー(ALB入口)
resource "aws_lb_listener" "listener" {
load_balancer_arn = aws_lb.alb.arn
port = 80
protocol = "HTTP"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.tg.arn
}
}
💡 役割
ALBに来たリクエストをどう処理するか
🔹 ポイント
✔ port = 80
HTTPリクエストを受ける
✔ default_action
受けたら → ターゲットグループへ転送
🔥 重要
リスナーがないと👇
ALBは受けても何もしない
💡 全体イメージ
[ユーザー]
↓
[ALB]
↓(listener)
[ターゲットグループ]
↓
[EC2(nginx)]
↓
レスポンス
🔥 重要なこと
① ALBは直接EC2を知らない
必ずターゲットグループ経由
② リスナーが交通整理
どこに送るか決める
③ セキュリティはEC2側で制御
ALB以外は拒否
まとめ: セキュリティ強化版 main.tf
############################################
# AWSプロバイダ
############################################
provider "aws" {
region = "ap-northeast-1"
}
############################################
# VPC(ネットワーク)
############################################
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
tags = {
Name = "secure-vpc"
}
}
############################################
# インターネットゲートウェイ
############################################
resource "aws_internet_gateway" "igw" {
vpc_id = aws_vpc.main.id
}
############################################
# パブリックサブネット(2AZ)
############################################
resource "aws_subnet" "public1" {
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_subnet" "public2" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.2.0/24"
availability_zone = "ap-northeast-1c"
map_public_ip_on_launch = true
}
############################################
# ルートテーブル(インターネット接続)
############################################
resource "aws_route_table" "public_rt" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.igw.id
}
}
resource "aws_route_table_association" "assoc1" {
subnet_id = aws_subnet.public1.id
route_table_id = aws_route_table.public_rt.id
}
resource "aws_route_table_association" "assoc2" {
subnet_id = aws_subnet.public2.id
route_table_id = aws_route_table.public_rt.id
}
############################################
# ALB用セキュリティグループ
# → インターネットからのHTTPのみ許可
############################################
resource "aws_security_group" "alb_sg" {
name = "alb-sg"
vpc_id = aws_vpc.main.id
# インターネット → ALB
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
# ALB → 外部(全許可)
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
############################################
# EC2用セキュリティグループ(重要)
# → ALBからの通信のみ許可
############################################
resource "aws_security_group" "web_sg" {
name = "web-sg"
vpc_id = aws_vpc.main.id
# ALB → EC2(HTTPのみ許可)
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
security_groups = [aws_security_group.alb_sg.id]
}
# SSH(自分のIPだけ許可にする)
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["あなたのIP/32"] # ←必ず自分のIPに変更
}
# EC2 → 外部(全許可)
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
############################################
# EC2(nginx)
############################################
resource "aws_instance" "web" {
ami = "ami-0c3fd0f5d33134a76"
instance_type = "t3.micro"
subnet_id = aws_subnet.public1.id
vpc_security_group_ids = [aws_security_group.web_sg.id]
associate_public_ip_address = true
user_data = <<-EOF
#!/bin/bash
amazon-linux-extras install -y nginx1
systemctl start nginx
systemctl enable nginx
EOF
tags = {
Name = "secure-nginx"
}
}
############################################
# ALB(ロードバランサー)
############################################
resource "aws_lb" "alb" {
name = "secure-alb"
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.alb_sg.id]
# 2つのAZに配置(必須)
subnets = [
aws_subnet.public1.id,
aws_subnet.public2.id
]
}
############################################
# ターゲットグループ(EC2に流す)
############################################
resource "aws_lb_target_group" "tg" {
name = "secure-tg"
port = 80
protocol = "HTTP"
vpc_id = aws_vpc.main.id
}
############################################
# EC2をターゲットに登録
############################################
resource "aws_lb_target_group_attachment" "attach" {
target_group_arn = aws_lb_target_group.tg.arn
target_id = aws_instance.web.id
port = 80
}
############################################
# リスナー(ALB入口)
############################################
resource "aws_lb_listener" "listener" {
load_balancer_arn = aws_lb.alb.arn
port = 80
protocol = "HTTP"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.tg.arn
}
}
############################################
# 出力
############################################
output "alb_dns" {
value = aws_lb.alb.dns_name
}