0
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?

Terraformで構築する実務向けAWS 3層アーキテクチャ(SSM・Secrets Manager対応)

0
Last updated at Posted at 2026-05-05

はじめに

Terraformを学び始めた方が次にステップアップとして挑戦する、「VPC・EC2・RDS」を用いた3層アーキテクチャの構築方法を解説します。
単にリソースを作るだけでなく、実務で必須となる以下の要素を盛り込んだ「そのまま使える」構成を目指します。

  • モジュール化: 再利用性を高めるディレクトリ構造
  • 脱踏み台サーバー: AWS Systems Manager (SSM) によるセキュアなログイン
  • 秘匿情報の管理: AWS Secrets Manager を使ったRDSパスワードの注入

ディレクトリ構成

環境ごとに設定を分離し、共通の処理はmodulesに切り出す構成です。

terraform/
├── envs/
│   └── dev/                  # 開発環境用設定
│       ├── main.tf           # モジュールの呼び出し
│       ├── variables.tf
│       ├── terraform.tfvars  # 具体的なパラメータ
│       └── backend.tf        # S3バックエンド設定
└── modules/
    ├── vpc/                  # ネットワーク基盤(SG含む)
    ├── ec2/                  # SSM対応インスタンス
    └── rds/                  # PostgreSQLインスタンス

modules/vpc:セキュアなネットワーク基盤

システムの土台となるVPC、サブネット、ゲートウェイ、およびリソース間の通信を制御するセキュリティグループを定義します。

  • パブリック/プライベートサブネットの分離による多層防御
  • セキュリティグループによる「Web層からDB層への特定ポート許可」の定義
modules/vpc/main.tf
resource "aws_vpc" "this" {
  cidr_block           = var.vpc_cidr
  enable_dns_support   = true
  enable_dns_hostnames = true
  tags = { Name = "${var.project}-${var.env}-vpc" }
}

# EC2用セキュリティグループ
resource "aws_security_group" "web" {
  name   = "${var.project}-${var.env}-web-sg"
  vpc_id = aws_vpc.this.id

  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"]
  }
}

# RDS用セキュリティグループ (Web-SGからの接続のみ許可)
resource "aws_security_group" "db" {
  name   = "${var.project}-${var.env}-db-sg"
  vpc_id = aws_vpc.this.id

  ingress {
    from_port       = 5432
    to_port         = 5432
    protocol        = "tcp"
    security_groups = [aws_security_group.web.id]
  }
}

modules/ec2:SSM管理による「踏み台レス」サーバー

ec2にSSM権限を付与します

modules/ec2/main.tf
resource "aws_instance" "this" {
  ami                    = var.ami_id
  instance_type          = var.instance_type
  subnet_id              = var.subnet_id
  vpc_security_group_ids = var.security_group_ids
  iam_instance_profile   = aws_iam_instance_profile.ssm_profile.name

  metadata_options {
    http_endpoint = "enabled"
    http_tokens   = "required"
  }

  tags = { Name = "${var.project}-${var.env}-ec2" }
}

# SSM用のIAMロール定義
resource "aws_iam_role" "ssm_role" {
  name = "${var.project}-${var.env}-ssm-role"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{ Action = "sts:AssumeRole", Effect = "Allow", Principal = { Service = "ec2.amazonaws.com" } }]
  })
}

resource "aws_iam_role_policy_attachment" "ssm_managed" {
  role       = aws_iam_role.ssm_role.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}

modules/rds:データベース

PostgreSQLを使用したデータベースを構築します。

外部からの直接通信を遮断する非公開設定。
パスワードを変数化し、上位環境から動的に注入。

  • 外部からの直接通信を遮断する非公開設定
  • パスワードを変数化し、上位環境から動的に注入
modules/rds/main.tf
resource "aws_db_subnet_group" "this" {
  name       = "${var.project}-${var.env}-rds-subnet-group"
  subnet_ids = var.subnet_ids
}

resource "aws_db_instance" "this" {
  identifier             = var.identifier
  engine                 = var.engine
  engine_version         = var.engine_version
  instance_class         = var.instance_class
  allocated_storage      = 20
  db_name                = var.database_name
  username               = var.master_username
  password               = var.master_password # 変数から注入
  db_subnet_group_name   = aws_db_subnet_group.this.name
  vpc_security_group_ids = var.security_group_ids
  publicly_accessible    = false
  skip_final_snapshot    = true
}

envs/dev:環境固有の設定とシークレット管理

各モジュールを組み合わせて「開発環境」として統合し、パスワードなどの機密情報を安全に渡します。

envs/dev/main.tf
# Secrets Managerからパスワードを読み取る
data "aws_secretsmanager_secret" "rds_password" {
  name = "${var.project}/${var.env}/rds-password"
}

data "aws_secretsmanager_secret_version" "rds_password" {
  secret_id = data.aws_secretsmanager_secret.rds_password.id
}

module "vpc" {
  source   = "../../modules/vpc"
  vpc_cidr = var.vpc_cidr
  # ... subnetの設定など
}

module "rds" {
  source          = "../../modules/rds"
  master_password = data.aws_secretsmanager_secret_version.rds_password.secret_string
  vpc_id          = module.vpc.vpc_id
  subnet_ids      = module.vpc.private_subnet_ids
  security_group_ids = [module.vpc.db_sg_id]
}

module "ec2" {
  source             = "../../modules/ec2"
  subnet_id          = module.vpc.private_subnet_ids[0]
  security_group_ids = [module.vpc.web_sg_id]
}

まとめ:実務に耐えうるTerraform構成を目指して

今回の構成では、単にリソースをコード化するだけでなく、実務現場で求められる「保守性」「セキュリティ」「再利用性」に焦点を当てました。

今回の構成のメリット

  1. 環境のポータビリティ: envs/prod/ を新しく作るだけで、同じ構成の本番環境を数分で作成可能です

  2. 踏み台サーバーからの脱却: SSMを活用することで、SSHポートを公開するリスクを排除しました

  3. 機密情報の適切な管理: Secrets Manager を使い、Git管理からパスワードを完全に切り離しました

TerraformによるInfrastructure as Code(IaC)は、エンジニアの工数を大幅に削減し、ヒューマンエラーを防ぐ強力な武器になります。ぜひ、ご自身のプロジェクトに合わせてこのテンプレートをカスタマイズしてみてください。

0
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
0
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?