Terraform個人メモ：VPC、6つのサブネット、IGW、ルートテーブル、NAT、ALB、ECS、execute-command、マイグレーションをコード化

## はじめに
AWS環境をTerraformで構築することで、**インフラの管理をコード化** し、**再現性や運用の効率を向上** させることができます。  

本記事では、**VPCやECS、RDSなどの主要リソースをTerraformで構築する方法** について詳しく解説します。  

Terraformを活用してAWS環境を効率的に管理したい方の参考になれば幸いです。

## 書こうと思ったきっかけ
AWS環境を手動で構築する際、**設定ミスや作業の手間が発生しやすい** と感じました。  

Terraformを使うことで、**インフラの構築・管理がシンプル** になり、**スケールや変更管理も容易** になります。  

**実際のAWS構成図**

![Screenshot 2025-02-21 at 7.29.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/14c68cef-7863-4742-97de-dc012a8dfd49.png)

自身の学習や備忘録として、Terraformを使ったAWS環境構築の手順を整理し、**共有するために本記事を書くことにしました**。

## AWS環境構築のTerraformコード解説

本記事では、Terraformを用いたAWS環境の構築について解説します。

東京リージョン（ap-northeast-1）を対象とし、VPC、サブネット、インターネットゲートウェイ、ルートテーブル、NATゲートウェイ、ECSクラスタ、RDSなどを設定しています。

### AWSプロバイダーの設定
まず、AWSプロバイダーを東京リージョン（ap-northeast-1）に設定します。

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

### ACM証明書の設定
外部入力用のACM証明書のARNを変数として設定します。

```hcl
variable "acm_certificate_arn" {
  default     = "arn:aws:acm:ap-northeast-1:xxx"
  description = "ARN of the ACM Certificate"
}
```

### VPCの定義
VPCを作成し、DNSサポートを有効にします。

```hcl
resource "aws_vpc" "main" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_support   = true
  enable_dns_hostnames = true

  tags = {
    Name = "Terraform-vpc"
  }
}
```

### サブネットの設定
パブリックおよびプライベートサブネットを各アベイラビリティゾーン（AZ）に作成します。

```hcl
resource "aws_subnet" "public1" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.0.0/20"
  availability_zone = "ap-northeast-1a"
  tags = { Name = "Terraform-subnet-public1-ap-northeast-1a" }
}

resource "aws_subnet" "public2" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.16.0/20"
  availability_zone = "ap-northeast-1c"
  tags = { Name = "Terraform-subnet-public2-ap-northeast-1c" }
}
```

プライベートサブネットも作成します。

```hcl
resource "aws_subnet" "private1" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.128.0/20"
  availability_zone = "ap-northeast-1a"
  tags = { Name = "Terraform-subnet-private1-ap-northeast-1a" }
}
```

### インターネットゲートウェイの設定
VPCにインターネットゲートウェイ（IGW）をアタッチします。

```hcl
resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id
  tags = { Name = "Terraform-igw" }
}
```

### ルートテーブルの設定
パブリックサブネット用のルートテーブルを作成し、デフォルトルートをIGWに向けます。

```hcl
resource "aws_route_table" "public" {
  vpc_id = aws_vpc.main.id
  tags = { Name = "Terraform-rtb-public" }
}

resource "aws_route" "public_internet_access" {
  route_table_id         = aws_route_table.public.id
  destination_cidr_block = "0.0.0.0/0"
  gateway_id             = aws_internet_gateway.main.id
}
```

### NATゲートウェイの設定
プライベートサブネットからインターネットにアクセスできるように、NATゲートウェイを設定します。

```hcl
resource "aws_eip" "nat" {}

resource "aws_nat_gateway" "public1" {
  subnet_id     = aws_subnet.public1.id
  allocation_id = aws_eip.nat.id
  tags = { Name = "Terraform-nat-public1-ap-northeast-1a" }
}
```

### ECSクラスターの作成

```hcl
resource "aws_ecs_cluster" "main" {
  name = "my-ecs-cluster"
}
```

### ECS タスク実行ロールの設定
ECSタスクがAWSのリソースにアクセスできるようにIAMロールを定義します。

```hcl
resource "aws_iam_role" "ecs_task_execution_role" {
  name = "ecs-task-execution-role"
  assume_role_policy = jsonencode({
    Version = "2012-10-17",
    Statement = [{
      Effect = "Allow",
      Principal = { Service = "ecs-tasks.amazonaws.com" },
      Action = "sts:AssumeRole"
    }]
  })
}
```

### RDSの設定
データベースのセキュリティグループとサブネットグループを設定します。

```hcl
resource "aws_security_group" "rds_sg" {
  vpc_id = aws_vpc.main.id
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
  tags = { Name = "Terraform-rds-sg" }
}
```

RDSインスタンスを作成します。

```hcl
resource "aws_db_instance" "rds_instance" {
  allocated_storage    = 20
  storage_type         = "gp2"
  engine               = "mysql"
  engine_version       = "8.0.39"
  instance_class       = "db.t4g.micro"
  username             = "myuser"
  password             = "mypassword"
  db_subnet_group_name = aws_db_subnet_group.rds_subnet_group.name
  vpc_security_group_ids = [aws_security_group.rds_sg.id]
  publicly_accessible = false
  multi_az            = false
  skip_final_snapshot = true
}
```

## まとめ
本記事では、Terraformを使用してAWSのインフラをコードで管理する方法について解説しました。

:::note warn
***東京リージョンにVPC、サブネット、NATゲートウェイ、ECSクラスター、RDSなどを構築し、ネットワークやIAMの設定も行いました。***
:::

Terraformを活用することで、インフラの管理を効率化し、再現性のある構築が可能になります。

## おまけ：実際に完成したコード（マイグレーション込み）

```main.tf
# AWSプロバイダーの設定（東京リージョン）
provider "aws" {
  region = "ap-northeast-1"
}

# ACM 証明書の ARN（外部入力用）
variable "acm_certificate_arn" {
  default     = "arn:aws:acm:ap-northeast-1:xxx"
  description = "ARN of the ACM Certificate"
}

# VPC の定義
resource "aws_vpc" "main" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_support   = true
  enable_dns_hostnames = true

  tags = {
    Name = "Terraform-vpc"
  }
}

# パブリックサブネット（AZ: ap-northeast-1a）
resource "aws_subnet" "public1" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.0.0/20"
  availability_zone = "ap-northeast-1a"

  tags = {
    Name = "Terraform-subnet-public1-ap-northeast-1a"
  }
}

# パブリックサブネット（AZ: ap-northeast-1c）
resource "aws_subnet" "public2" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.16.0/20"
  availability_zone = "ap-northeast-1c"

  tags = {
    Name = "Terraform-subnet-public2-ap-northeast-1c"
  }
}

# プライベートサブネット（AZ: ap-northeast-1a）
resource "aws_subnet" "private1" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.128.0/20"
  availability_zone = "ap-northeast-1a"

  tags = {
    Name = "Terraform-subnet-private1-ap-northeast-1a"
  }
}

# プライベートサブネット（AZ: ap-northeast-1c）
resource "aws_subnet" "private2" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.144.0/20"
  availability_zone = "ap-northeast-1c"

  tags = {
    Name = "Terraform-subnet-private2-ap-northeast-1c"
  }
}

# プライベートサブネット（AZ: ap-northeast-1a, 別のCIDRブロック）
resource "aws_subnet" "private3" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.160.0/20"
  availability_zone = "ap-northeast-1a"

  tags = {
    Name = "Terraform-subnet-private3-ap-northeast-1a"
  }
}

# プライベートサブネット（AZ: ap-northeast-1c, 別のCIDRブロック）
resource "aws_subnet" "private4" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.176.0/20"
  availability_zone = "ap-northeast-1c"

  tags = {
    Name = "Terraform-subnet-private4-ap-northeast-1c"
  }
}

# インターネットゲートウェイ（IGW）の定義（VPC のインターネット接続用）
resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "Terraform-igw"
  }
}

# パブリックルートテーブルの定義（パブリックサブネット用のルートテーブル）
resource "aws_route_table" "public" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "Terraform-rtb-public"
  }
}

# インターネットアクセス用のデフォルトルート（0.0.0.0/0 → IGW）
resource "aws_route" "public_internet_access" {
  route_table_id         = aws_route_table.public.id
  destination_cidr_block = "0.0.0.0/0"
  gateway_id             = aws_internet_gateway.main.id
}

# パブリックサブネットをルートテーブルに関連付け
resource "aws_route_table_association" "public1" {
  subnet_id      = aws_subnet.public1.id
  route_table_id = aws_route_table.public.id
}

resource "aws_route_table_association" "public2" {
  subnet_id      = aws_subnet.public2.id
  route_table_id = aws_route_table.public.id
}

# NAT ゲートウェイ用の Elastic IP（プライベートサブネットのインターネットアクセス用）
resource "aws_eip" "nat" {
  tags = {
    Name = "Terraform-eip-ap-northeast-1a"
  }
}

# NAT ゲートウェイの定義（プライベートサブネットがインターネットにアクセスできるようにする）
resource "aws_nat_gateway" "public1" {
  subnet_id     = aws_subnet.public1.id
  allocation_id = aws_eip.nat.id

  tags = {
    Name = "Terraform-nat-public1-ap-northeast-1a"
  }
}

# プライベートルートテーブル（AZ: ap-northeast-1a）
resource "aws_route_table" "private1" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "Terraform-rtb-private1-ap-northeast-1a"
  }
}

# プライベートルートの定義（NAT ゲートウェイ経由でインターネットアクセス）
resource "aws_route" "private1_nat_access" {
  route_table_id         = aws_route_table.private1.id
  destination_cidr_block = "0.0.0.0/0"
  nat_gateway_id         = aws_nat_gateway.public1.id
}

# プライベートサブネットをルートテーブルに関連付け
resource "aws_route_table_association" "private1" {
  subnet_id      = aws_subnet.private1.id
  route_table_id = aws_route_table.private1.id
}

# プライベートルートテーブル（AZ: ap-northeast-1c）
resource "aws_route_table" "private2" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "Terraform-rtb-private2-ap-northeast-1c"
  }
}

# プライベートルートの定義（NAT ゲートウェイ経由でインターネットアクセス）
resource "aws_route" "private2_nat_access" {
  route_table_id         = aws_route_table.private2.id
  destination_cidr_block = "0.0.0.0/0"
  nat_gateway_id         = aws_nat_gateway.public1.id
}

# プライベートサブネットをルートテーブルに関連付け
resource "aws_route_table_association" "private2" {
  subnet_id      = aws_subnet.private2.id
  route_table_id = aws_route_table.private2.id
}

# プライベートルートテーブル（AZ: ap-northeast-1a, 別のサブネット用）
resource "aws_route_table" "private3" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "Terraform-rtb-private3-ap-northeast-1a"
  }
}

# プライベートルート（AZ: ap-northeast-1a, NAT ゲートウェイ経由でインターネットアクセス）
resource "aws_route" "private3_nat_access" {
  route_table_id         = aws_route_table.private3.id
  destination_cidr_block = "0.0.0.0/0"
  nat_gateway_id         = aws_nat_gateway.public1.id
}

# プライベートサブネットをルートテーブルに関連付け（AZ: ap-northeast-1a）
resource "aws_route_table_association" "private3" {
  subnet_id      = aws_subnet.private3.id
  route_table_id = aws_route_table.private3.id
}

# プライベートルートテーブル（AZ: ap-northeast-1c, 別のサブネット用）
resource "aws_route_table" "private4" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "Terraform-rtb-private4-ap-northeast-1c"
  }
}

# プライベートルート（AZ: ap-northeast-1c, NAT ゲートウェイ経由でインターネットアクセス）
resource "aws_route" "private4_nat_access" {
  route_table_id         = aws_route_table.private4.id
  destination_cidr_block = "0.0.0.0/0"
  nat_gateway_id         = aws_nat_gateway.public1.id
}

# プライベートサブネットをルートテーブルに関連付け（AZ: ap-northeast-1c）
resource "aws_route_table_association" "private4" {
  subnet_id      = aws_subnet.private4.id
  route_table_id = aws_route_table.private4.id
}

# ECS 用のセキュリティグループ（アプリケーションの通信を制御）
resource "aws_security_group" "ecs_sg" {
  vpc_id = aws_vpc.main.id

  # ALB からのリクエストを許可（ポート 1323）
  ingress {
    from_port       = 1323
    to_port         = 1323
    protocol        = "tcp"
    security_groups = [aws_security_group.public_sg.id]
  }

  # すべてのアウトバウンドトラフィックを許可
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "Terraform-private-instance-sg"
  }
}

# CloudWatch Logs グループの作成
resource "aws_cloudwatch_log_group" "ecs_logs" {
  name              = "/ecs/datadog"
  retention_in_days = 7  # ログの保持期間（必要に応じて変更）
}

# ECS クラスターの定義（Fargate でアプリを実行）
resource "aws_ecs_cluster" "main" {
  name = "my-ecs-cluster"
}

# ECS タスク実行ロールの定義（ECS タスクが必要な AWS サービスにアクセスするための IAM ロール）
resource "aws_iam_role" "ecs_task_execution_role" {
  name = "ecs-task-execution-role"

  # ECS タスクがこのロールを引き受けるためのポリシー
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect    = "Allow"
      Principal = { Service = "ecs-tasks.amazonaws.com" }
      Action    = "sts:AssumeRole"
    }]
  })

  # タスク実行に必要な AWS サービスへのアクセス許可
  inline_policy {
    name = "ecs-task-execution-policy"
    policy = jsonencode({
      Version = "2012-10-17"
      Statement = [
        {
          Effect   = "Allow"
          Action   = [
            "ecr:GetAuthorizationToken",
            "ecr:GetDownloadUrlForLayer",
            "ecr:BatchGetImage",
            "logs:CreateLogStream",
            "logs:PutLogEvents",
            "s3:GetObject"
          ]
          Resource = "*"
        }
      ]
    })
  }
}

# ECS Exec に必要な SSM 権限を付与
resource "aws_iam_role_policy_attachment" "ecs_ssm_policy" {
  role       = aws_iam_role.ecs_task_execution_role.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}

# ECS タスク実行ロールの基本ポリシー
resource "aws_iam_role_policy_attachment" "ecs_task_execution_policy" {
  role       = aws_iam_role.ecs_task_execution_role.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
}

# ECS タスク定義（Fargate で動作するコンテナの定義）
resource "aws_ecs_task_definition" "main" {
  family                   = "Datadog"
  network_mode             = "awsvpc"
  requires_compatibilities = ["FARGATE"]
  cpu                      = "256"
  memory                   = "512"
  execution_role_arn       = aws_iam_role.ecs_task_execution_role.arn
  task_role_arn            = aws_iam_role.ecs_task_execution_role.arn  # <-- 追加

  volume {
    name = "cws-instrumentation-volume"
  }

  container_definitions = jsonencode([
    {
      name       = "cws-instrumentation-init"
      image      = "datadog/cws-instrumentation:latest"
      essential  = false
      user       = "0"
      command    = [
        "/cws-instrumentation",
        "setup",
        "--cws-volume-mount",
        "/cws-instrumentation-volume"
      ]
      mountPoints = [
        {
          sourceVolume  = "cws-instrumentation-volume"
          containerPath = "/cws-instrumentation-volume"
          readOnly      = false
        }
      ]
      logConfiguration = {
        logDriver = "awslogs"
        options = {
          awslogs-group         = "/ecs/datadog"
          awslogs-region        = "ap-northeast-1"
          awslogs-stream-prefix = "cws-instrumentation-init"
        }
      }
    },
    {
      name      = "datadog-agent"
      image     = "datadog/agent:latest"
      essential = true
      environment = [
        {
          name  = "DD_API_KEY"
          value = "xxx"
        },
        {
          name  = "DD_SITE"
          value = "ap1.datadoghq.com"
        },
        {
          name  = "ECS_FARGATE"
          value = "true"
        },
        # メトリクス収集（CPU・メモリ）を有効化
        {
          name  = "DD_CONTAINER_METRICS_ENABLED"
          value = "true"
        },
        # Process Monitoring を完全に無効化
        {
          name  = "DD_PROCESS_AGENT_ENABLED"
          value = "false"
        },
        {
          name  = "DD_PROCESS_CONFIG_ENABLED"
          value = "false"
        },
        {
          name  = "DD_ORCHESTRATOR_EXPLORER_ENABLED"
          value = "false"
        },
        {
          name  = "DD_SYSTEM_PROBE_ENABLED"
          value = "false"
        },
        # APM, ログ, セキュリティ機能も無効化
        {
          name  = "DD_LOGS_ENABLED"
          value = "false"
        },
        {
          name  = "DD_APM_ENABLED"
          value = "false"
        },
        {
          name  = "DD_TRACE_ENABLED"
          value = "false"
        },
        {
          name  = "DD_SECURITY_AGENT_ENABLED"
          value = "false"
        },
        {
          name  = "DD_RUNTIME_SECURITY_CONFIG_ENABLED"
          value = "false"
        },
        {
          name  = "DD_RUNTIME_SECURITY_CONFIG_EBPFLESS_ENABLED"
          value = "false"
        }
      ]
      healthCheck = {
        command     = ["CMD-SHELL", "/probe.sh"]
        interval    = 30
        timeout     = 5
        retries     = 2
        startPeriod = 60
      }
      logConfiguration = {
        logDriver = "awslogs"
        options = {
          awslogs-group         = "/ecs/datadog"
          awslogs-region        = "ap-northeast-1"
          awslogs-stream-prefix = "datadog-agent"
        }
      }
    },
    {
      name  = "my-app-repo"
      image = "xxx"
      entryPoint = ["/bin/sh", "-c", "/app/migrate_app && /app/server"]

      environment = [
        # MySQL 環境変数
        {
          "name": "GO_ENV",
          "value": "prod"
        },
        {
          "name": "MYSQL_ROOT_PASSWORD",
          "value": "root"
        },        
        {
          "name": "MYSQL_USER",
          "value": "myuser"
        },
        {
          "name": "MYSQL_PW",
          "value": "${jsondecode(data.aws_secretsmanager_secret_version.rds_password_v5.secret_string)["password"]}"
        },
        {
          "name": "MYSQL_HOST",
          "value": "${aws_db_instance.rds_instance.address}"
        },
        {
          "name": "MYSQL_PORT",
          "value": "3306"
        },
        {
          "name": "MYSQL_DB",
          "value": "mydatabase"
        },

        # phpMyAdmin 環境変数
        {
          "name": "PMA_ARBITRARY",
          "value": "1"
        },
        {
          "name": "PMA_USER",
          "value": "myuser"
        },
        {
          "name": "PMA_PASSWORD",
          "value": "root"
        },
        {
          "name": "PMA_HOST",
          "value": "dev-mysql"
        },
        {
          "name": "PMA_PORT",
          "value": "3306"
        },

        # Cognito 環境変数
        {
          "name": "COGNITO_USER_POOL_ID",
          "value": "xxx"
        },
        {
          "name": "COGNITO_CLIENT_ID",
          "value": "xxx"
        },
        {
          "name": "AWS_REGION",
          "value": "ap-northeast-1"
        },

        # OpenAI APIキー
        {
          "name": "OPENAI_API_KEY",
          "value": "xxx"
        }
      ]

      mountPoints = [
        {
          sourceVolume  = "cws-instrumentation-volume"
          containerPath = "/cws-instrumentation-volume"
          readOnly      = true
        }
      ]
      linuxParameters = {
        capabilities = {
          add = ["SYS_PTRACE"]
        }
      }
      dependsOn = [
        {
          containerName = "datadog-agent"
          condition     = "HEALTHY"
        },
        {
          containerName = "cws-instrumentation-init"
          condition     = "SUCCESS"
        }
      ]
      portMappings = [
        {
          containerPort = 1323
          hostPort      = 1323
          protocol      = "tcp"
        }
      ]
      logConfiguration = {
        logDriver = "awslogs"
        options = {
          awslogs-group         = "/ecs/datadog"
          awslogs-region        = "ap-northeast-1"
          awslogs-stream-prefix = "my-app-repo"
        }
      }
    }
  ])
}

# ECS サービスの定義（Fargate で実行し、プライベートサブネットに配置）
resource "aws_ecs_service" "main" {
  name            = "my-ecs-service"
  cluster         = aws_ecs_cluster.main.id
  task_definition = aws_ecs_task_definition.main.arn
  desired_count   = 1
  launch_type     = "FARGATE"
  enable_execute_command = true  # <-- 追加

  # ネットワーク設定（プライベートサブネットで実行し、パブリック IP を付与しない）
  network_configuration {
    subnets         = [aws_subnet.private1.id, aws_subnet.private2.id]
    security_groups = [aws_security_group.ecs_sg.id]
    assign_public_ip = false # パブリック IP を付与せず、NAT 経由で通信
  }

  # ALB との接続設定（ECS タスクを ALB に登録）
  load_balancer {
    target_group_arn = aws_lb_target_group.main_target_group.arn
    container_name   = "my-app-repo"
    container_port   = 1323
  }
}

# パブリック（ALB）用セキュリティグループの定義（HTTPS トラフィックを許可）
resource "aws_security_group" "public_sg" {
  vpc_id = aws_vpc.main.id

  # インバウンドルール: HTTPS (443) の受信を全インターネットから許可
  ingress {
    from_port   = 443
    to_port     = 443
    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"]
  }

  tags = {
    Name = "Terraform-public-sg"
  }
}

# アプリケーションロードバランサー（ALB）の定義（パブリックアクセス可能な ALB）
resource "aws_lb" "main_alb" {
  name               = "terraform-main-alb"
  internal           = false # パブリック ALB
  load_balancer_type = "application"
  security_groups    = [aws_security_group.public_sg.id] # ALB に適用するセキュリティグループ
  subnets            = [aws_subnet.public1.id, aws_subnet.public2.id] # ALB の配置サブネット

  enable_deletion_protection = false # 削除保護を無効化

  tags = {
    Name = "terraform-main-alb"
  }
}

# ターゲットグループの定義（ALB がリクエストを転送する先）
resource "aws_lb_target_group" "main_target_group" {
  name     = "terraform-main-target-group"
  port     = 80
  protocol = "HTTP"
  vpc_id   = aws_vpc.main.id
  target_type = "ip" # Fargate の場合は 'ip' に設定

  # ヘルスチェックの設定（ALB が正常なターゲットを判断する）
  health_check {
    interval            = 30
    path                = "/"
    protocol            = "HTTP"
    timeout             = 5
    healthy_threshold   = 3
    unhealthy_threshold = 3
  }

  # セッション維持設定（ALB の負荷分散時にセッションを保持）
  stickiness {
    type            = "lb_cookie"
    enabled         = true
    cookie_duration = 86400
  }

  tags = {
    Name = "terraform-main-target-group"
  }
}

# ALB のリスナー設定（HTTPS リクエストをターゲットグループに転送）
resource "aws_lb_listener" "http_listener" {
  load_balancer_arn = aws_lb.main_alb.arn
  port              = 443
  protocol          = "HTTPS"
  ssl_policy        = "ELBSecurityPolicy-2016-08"
  
  certificate_arn = var.acm_certificate_arn # SSL 証明書の ARN を指定

  # ターゲットグループへのリクエスト転送設定
  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.main_target_group.arn
  }
}

# RDS 用セキュリティグループ（データベースへのアクセスを制御）
resource "aws_security_group" "rds_sg" {
  vpc_id = aws_vpc.main.id

  # アウトバウンドルール: すべての通信を許可
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "Terraform-rds-sg"
  }
}

# RDS のインバウンドルールを ECS のセキュリティグループ（ecs_sg）のみに制限
resource "aws_security_group_rule" "rds_allow_ecs" {
  type                     = "ingress"
  from_port                = 3306
  to_port                  = 3306
  protocol                 = "tcp"
  security_group_id        = aws_security_group.rds_sg.id
  source_security_group_id = aws_security_group.ecs_sg.id  # ← ECSのセキュリティグループのみ許可
  description              = "Allow ECS to access RDS"
}

# RDS 用サブネットグループの定義（RDS を配置するサブネットを指定）
resource "aws_db_subnet_group" "rds_subnet_group" {
  name       = "terraform-rds-subnet-group"
  subnet_ids = [aws_subnet.private3.id, aws_subnet.private4.id]

  tags = {
    Name = "Terraform-rds-subnet-group"
  }
}

# Secrets Manager を使用して RDS のパスワードを管理
resource "aws_secretsmanager_secret" "rds_password_v5" {
  name = "rds_password_v5"
}

# Secrets Manager に保存する RDS のパスワード（初期設定）
resource "aws_secretsmanager_secret_version" "rds_password_version_v5" {
  secret_id     = aws_secretsmanager_secret.rds_password_v5.id
  secret_string = jsonencode({ password = "mypassword123" })
}

# Secrets Manager から RDS のパスワードを取得
data "aws_secretsmanager_secret_version" "rds_password_v5" {
  secret_id  = aws_secretsmanager_secret.rds_password_v5.arn
  depends_on = [aws_secretsmanager_secret_version.rds_password_version_v5]
}

# RDS インスタンスの定義（MySQL 8.0 を使用）
resource "aws_db_instance" "rds_instance" {
  allocated_storage    = 20
  storage_type         = "gp2"
  engine               = "mysql"
  engine_version       = "8.0.39"
  instance_class       = "db.t4g.micro"
  username             = "myuser"  # 変更
  password             = jsondecode(data.aws_secretsmanager_secret_version.rds_password_v5.secret_string)["password"]
  db_name              = "mydatabase"  # ← ここを追加
  db_subnet_group_name    = aws_db_subnet_group.rds_subnet_group.name
  vpc_security_group_ids  = [aws_security_group.rds_sg.id]

  publicly_accessible = false
  multi_az            = false

  tags = {
    Name = "Terraform-rds-instance"
  }

  # 削除時の最終スナップショット作成をスキップ
  skip_final_snapshot = true
}
```