Terraform で AWS リソース作成
Terraform で最小コストの実習インフラを作る
⚠️ 事前案内
ㅁ
運用環境では
GSLB + 複数センサー(複数 AZ / 複数インスタンス)構成を推奨する。
Terraform に不慣れな場合は、
AWS Console でリソースを手動作成し、
本編(第1編)はスキップして、
次の編の Suricata / ELK インストールおよびシグネチャテストガイド から
直接参照しても問題ない。
インスタンス仕様に関する補足
本実習では
Suricata(NAT Instance) と ターゲットサーバー の両方をt3.medium で構成した。
これは
初期構成および性能検証を単純化するための選択である。
ただしコストを考慮すると、両インスタンスを同一仕様で維持する必要はない。
- Suricata NAT Instance
パケット処理、NFQUEUE、ELK(Logstash / Elasticsearch)まで同時に行うため、
最低でも t3.medium 以上を推奨する。 - Web サーバー / PBX ターゲットインスタンス
単純なトラフィック生成および攻撃テスト用途なので、t3.microまたはt3.smallに下げても問題ない。
ただし、その場合ターゲットインスタンスの仕様変更は Terraform コードで直接修正する必要がある。
(本実習では単純化のため同一仕様を維持する)
1. 目的
- NAT Instance 上に Suricata + ELK を構築
(コストの問題で OpenSearch は使用しない) - Target サーバー(Private Subnet)を作成し、
すべてのトラフィックが NAT を必ず経由するようにルーティングを構成 - EIP を付与して NAT の Public IP を固定
- Terraform で 一括作成 / 一括削除
📌 Terraform コード適用範囲に関する案内(重要)
本シリーズで提供する Terraform コードは、
**Suricata Inline IPS 構成を説明するための 핵심例(コア例)**のみを含む。
実際の運用環境では以下のリソースが
すでに別構成・別コードで管理されている可能性が高い。
- VPC
- Subnet(Public / Private)
- Route Table
- Internet Gateway
- 既存 EC2 / Security Group
- その他ネットワークモジュール
環境差異により混乱を招く恐れがあるため、
本シリーズでは 運用中の Terraform 全コードは公開しない。
代わりに以下の原則で説明する。
本シリーズの Terraform ガイド原則
- Suricata に直接関連するリソースのみをコードとして提示
- 既存インフラは
dataリソースで参照するか- 上位モジュールから変数として受け取る前提
- 読者は自分の Terraform 構成に合わせて応用すること
つまり本シリーズのコードは、
コピー&ペースト用ではなく、構造理解と応用のための基準例である。
2. アーキテクチャ

(要点)は 2 つだけ。
- NAT Instance は source/dest check を OFF
- Private Subnet のルーティングは
0.0.0.0/0 → NAT Instance ENI に強制
3. フォルダ構成
画像のようにモジュールは 3 ファイルで分割する。
my-site/
├─ envs/
│ └─ prod/
│ ├─ main.tf
│ ├─ variables.tf
│ └─ terraform.tfvars
└─ modules/
└─ suricata_lab/
├─ main.tf
├─ variables.tf
└─ outputs.tf
modules/suricata_lab/main.tfにリソースを全て集約variables.tf/outputs.tfは定義のみ最小限envs/prodはモジュール呼び出し + 変数注入のみ
4. envs/prod 側で追加する内容
4.1 envs/prod/variables.tf
variable "key_name" {
type = string
description = "EC2 key pair name"
}
4.2 envs/prod/main.tf
(既存モジュールがあっても問題ない。以下のモジュールだけ追加すればよい)
module "suricata_lab" {
source = "../../modules/suricata_lab"
name = "sec-lab"
key_name = var.key_name
my_ip = "162.120.XXX.XXX/32" # 実際に接続する自分の IP を適用
instance_type = "t3.medium"
}
5. modules/suricata_lab コード
✅ modules/suricata_lab/main.tf
############################################################
# modules/suricata_lab/main.tf
# - Ubuntu 24.04
# - NAT Instance (Suricata IPS + ELK) in Public Subnet
# - Target EC2 in Private Subnet
# - Private RT: 0.0.0.0/0 -> NAT Instance
# - NAT Instance: source_dest_check = false (必須)
############################################################
############################
# VPC / Subnet / IGW
############################
resource "aws_vpc" "lab" {
cidr_block = "10.20.0.0/16"
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = "${var.name}-vpc"
}
}
resource "aws_internet_gateway" "lab" {
vpc_id = aws_vpc.lab.id
tags = {
Name = "${var.name}-igw"
}
}
resource "aws_subnet" "public" {
vpc_id = aws_vpc.lab.id
cidr_block = "10.20.0.0/24"
map_public_ip_on_launch = true
tags = {
Name = "${var.name}-public"
}
}
resource "aws_subnet" "private" {
vpc_id = aws_vpc.lab.id
cidr_block = "10.20.1.0/24"
tags = {
Name = "${var.name}-private"
}
}
############################
# Route Table - Public
############################
resource "aws_route_table" "public" {
vpc_id = aws_vpc.lab.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.lab.id
}
tags = {
Name = "${var.name}-rt-public"
}
}
resource "aws_route_table_association" "public" {
subnet_id = aws_subnet.public.id
route_table_id = aws_route_table.public.id
}
############################
# Security Group - NAT/Suricata/ELK
############################
resource "aws_security_group" "nat" {
name = "${var.name}-sg-nat"
description = "NAT Instance (Suricata+ELK) SG"
vpc_id = aws_vpc.lab.id
# SSH (管理)
ingress {
description = "SSH from my IP"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = [var.my_ip]
}
# HTTP 接続許可 (only my ip)
ingress {
description = "HTTP from my IP"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = [var.my_ip]
}
# Kibana
ingress {
description = "Kibana from my IP"
from_port = 5601
to_port = 5601
protocol = "tcp"
cidr_blocks = [var.my_ip]
}
# private target 許可
ingress {
description = "All from target ip"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["10.20.1.0/24"]
}
# Outbound all
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "${var.name}-sg-nat"
}
}
############################
# Security Group - Target (Private)
############################
resource "aws_security_group" "target" {
name = "${var.name}-sg-target"
description = "Target EC2 (private) SG"
vpc_id = aws_vpc.lab.id
# SSH (管理)
ingress {
description = "SSH from NAT Instance only"
from_port = 22
to_port = 22
protocol = "tcp"
security_groups = [aws_security_group.nat.id]
}
# HTTP: NAT SG のみ許可(必要なら)
ingress {
description = "HTTP 80 from NAT SG"
from_port = 80
to_port = 80
protocol = "tcp"
security_groups = [aws_security_group.nat.id]
}
# Outbound all
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "${var.name}-sg-target"
}
}
############################
# EC2 - NAT/Suricata/ELK (Public)
############################
resource "aws_instance" "nat" {
ami = "ami-0a71e3eb8b23101ed"
instance_type = var.instance_type
subnet_id = aws_subnet.public.id
vpc_security_group_ids = [aws_security_group.nat.id]
key_name = var.key_name
associate_public_ip_address = true
root_block_device {
volume_size = 20
volume_type = "gp3"
delete_on_termination = true
}
# NAT Instance 必須
source_dest_check = false
tags = {
Name = "${var.name}-nat-suricata-elk"
}
}
############################
# EC2 - Target (Private)
############################
resource "aws_instance" "target" {
ami = "ami-0a71e3eb8b23101ed"
instance_type = var.instance_type
subnet_id = aws_subnet.private.id
vpc_security_group_ids = [aws_security_group.target.id]
key_name = var.key_name
tags = {
Name = "${var.name}-target"
}
}
############################
# Route Table - Private
# - 0.0.0.0/0 -> NAT Instance
############################
resource "aws_route_table" "private" {
vpc_id = aws_vpc.lab.id
route {
cidr_block = "0.0.0.0/0"
network_interface_id = aws_instance.nat.primary_network_interface_id
}
tags = {
Name = "${var.name}-rt-private"
}
}
resource "aws_route_table_association" "private" {
subnet_id = aws_subnet.private.id
route_table_id = aws_route_table.private.id
}
# NAT Instance 用 EIP
resource "aws_eip" "nat" {
domain = "vpc"
tags = {
Name = "${var.name}-eip-nat"
}
}
# NAT Instance に EIP を関連付け
resource "aws_eip_association" "nat" {
allocation_id = aws_eip.nat.id
instance_id = aws_instance.nat.id
}
6. modules/suricata_lab/variables.tf
リソースは main.tf に全て入り、ここは変数定義のみ置く。
✅ modules/suricata_lab/variables.tf
variable "name" {
type = string
description = "Lab name prefix"
}
variable "region" {
type = string
default = "ap-northeast-2"
}
variable "key_name" {
type = string
}
variable "my_ip" {
type = string
description = "162.120.xxx.xxx/32" # 実際に接続する IP を適用
}
variable "instance_type" {
type = string
default = "t3.medium"
}
7. modules/suricata_lab/outputs.tf
outputs は最小限にする。
実習で NAT 接続 / ターゲット確認のためだけ出力する。
✅ modules/suricata_lab/outputs.tf
output "nat_public_ip" {
value = aws_eip.nat.public_ip
}
output "target_private_ip" {
value = aws_instance.target.private_ip
}
8. Terraform 実行時の変数注入(Windows 環境)
Key Pair は Terraform で作る必要はない。
AWS Console で作成済みのものを名前だけ指定する。
cd C:\projects\my-site\envs\prod
PS C:\projects\my-site\envs\prod> terraform init
key pair 確認
PS C:\projects\my-site\envs\prod> aws ec2 describe-key-pairs --region ap-northeast-2 --query "KeyPairs[].KeyName" --output table
key pair 変数注入 + terraform 実行
PS C:\projects\my-site\envs\prod>terraform apply -var="key_name=blog"
Step-by-Step: 実際の terraform 実行とインフラ作成プロセス





9. 本編(第1編)の到達点
ここまでで以下が完了する。
- NAT Instance(Suricata + ELK 用)作成
- EIP 関連付け完了(固定 Public IP)
- Private Subnet のトラフィックを NAT 強制経由にするルーティング完了
- Target サーバー作成完了
次の編でやることは明確。
- NAT インスタンスに Suricata + ELK をインストール
ip_forward+iptables (NFQUEUE)構成- ルール更新 + SIP シグネチャ検証
〆(最後に)
Terraform に不慣れな場合は、
- Console で VPC / Subnet / IGW / RT / EC2 / EIP を手動作成して
- 本編(第1編)はスキップして
- 第2編から進めればよい。
🛠 마지막 수정일: 2025.12.22
💡 お困りですか?
Zabbix、Kubernetes、各種オープンソースインフラの構築・運用・最適化・障害解析が必要であれば、いつでもご連絡ください。
📧 メール: jikimy75@gmail.com
💼 サービス: 導入支援 | 性能チューニング | 障害解析コンサルティング
답글 남기기
댓글을 달기 위해서는 로그인해야합니다.