AWSTemplateFormatVersion: '2010-09-09'
Description: High Availability 3-Tier Architecture (Public-Private-DB) with 2 NatGateways

Parameters:
  KeyName:
    Description: Name of an existing EC2 KeyPair
    Type: AWS::EC2::KeyPair::KeyName
  
  LatestAmiId:
    Type: 'AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>'
    Default: '/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64'

Resources:
  # --- 1. 네트워크 구성 (VPC & Subnets) ---
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags: [{Key: Name, Value: HA-VPC}]

  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags: [{Key: Name, Value: HA-IGW}]

  GatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway

  # 퍼블릭 서브넷 (ALB, NAT Gateway용)
  PublicSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.1.0/24
      MapPublicIpOnLaunch: true
      AvailabilityZone: !Select [ 0, !GetAZs '' ]
      Tags: [{Key: Name, Value: HA-Pub-Sub-1}]

  PublicSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.2.0/24
      MapPublicIpOnLaunch: true
      AvailabilityZone: !Select [ 1, !GetAZs '' ]
      Tags: [{Key: Name, Value: HA-Pub-Sub-2}]

  # 프라이빗 서브넷 (WAS/애플리케이션용)
  PrivateSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.11.0/24
      AvailabilityZone: !Select [ 0, !GetAZs '' ]
      Tags: [{Key: Name, Value: HA-Pri-Sub-1}]

  PrivateSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.12.0/24
      AvailabilityZone: !Select [ 1, !GetAZs '' ]
      Tags: [{Key: Name, Value: HA-Pri-Sub-2}]

  # DB 서브넷
  DBSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.21.0/24
      AvailabilityZone: !Select [ 0, !GetAZs '' ]
      Tags: [{Key: Name, Value: HA-DB-Sub-1}]

  DBSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.22.0/24
      AvailabilityZone: !Select [ 1, !GetAZs '' ]
      Tags: [{Key: Name, Value: HA-DB-Sub-2}]

  # --- 2. NAT Gateway (2개 구성) ---
  NAT1EIP:
    Type: AWS::EC2::EIP
    Properties: { Domain: vpc }

  NAT2EIP:
    Type: AWS::EC2::EIP
    Properties: { Domain: vpc }

  NATGateway1:
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId: !GetAtt NAT1EIP.AllocationId
      SubnetId: !Ref PublicSubnet1
      Tags: [{Key: Name, Value: HA-NAT-GW-1}]

  NATGateway2:
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId: !GetAtt NAT2EIP.AllocationId
      SubnetId: !Ref PublicSubnet2
      Tags: [{Key: Name, Value: HA-NAT-GW-2}]

  # --- 3. 라우팅 테이블 ---
  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties: { VpcId: !Ref VPC, Tags: [{Key: Name, Value: HA-Pub-RT}] }

  PublicRoute:
    Type: AWS::EC2::Route
    DependsOn: GatewayAttachment
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway

  PrivateRouteTable1:
    Type: AWS::EC2::RouteTable
    Properties: { VpcId: !Ref VPC, Tags: [{Key: Name, Value: HA-Pri-RT-1}] }

  PrivateRoute1:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PrivateRouteTable1
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref NATGateway1

  PrivateRouteTable2:
    Type: AWS::EC2::RouteTable
    Properties: { VpcId: !Ref VPC, Tags: [{Key: Name, Value: HA-Pri-RT-2}] }

  PrivateRoute2:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PrivateRouteTable2
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref NATGateway2

  # 서브넷 연결
  PubSub1Assoc:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties: {SubnetId: !Ref PublicSubnet1, RouteTableId: !Ref PublicRouteTable}
  PubSub2Assoc:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties: {SubnetId: !Ref PublicSubnet2, RouteTableId: !Ref PublicRouteTable}
  PriSub1Assoc:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties: {SubnetId: !Ref PrivateSubnet1, RouteTableId: !Ref PrivateRouteTable1}
  PriSub2Assoc:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties: {SubnetId: !Ref PrivateSubnet2, RouteTableId: !Ref PrivateRouteTable2}

  # --- 4. 보안 그룹 ---
  ALBSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: ALB HTTP access
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - {IpProtocol: tcp, FromPort: 80, ToPort: 80, CidrIp: 0.0.0.0/0}

  WASSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: WAS access from ALB
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - {IpProtocol: tcp, FromPort: 80, ToPort: 80, SourceSecurityGroupId: !Ref ALBSecurityGroup}
        - {IpProtocol: tcp, FromPort: 22, ToPort: 22, CidrIp: 0.0.0.0/0}

  DBSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: DB access from WAS
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - {IpProtocol: tcp, FromPort: 3306, ToPort: 3306, SourceSecurityGroupId: !Ref WASSecurityGroup}

  # --- 5. 로드 밸런서 & 오토 스케일링 ---
  ApplicationLoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Subnets: [!Ref PublicSubnet1, !Ref PublicSubnet2]
      SecurityGroups: [!Ref ALBSecurityGroup]

  ALBTargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      Port: 80
      Protocol: HTTP
      VpcId: !Ref VPC
      TargetType: instance

  ALBListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions: [{Type: forward, TargetGroupArn: !Ref ALBTargetGroup}]
      LoadBalancerArn: !Ref ApplicationLoadBalancer
      Port: 80
      Protocol: HTTP

  LaunchTemplate:
    Type: AWS::EC2::LaunchTemplate
    Properties:
      LaunchTemplateData:
        ImageId: !Ref LatestAmiId
        InstanceType: t3.micro
        KeyName: !Ref KeyName
        SecurityGroupIds: [!Ref WASSecurityGroup]
        UserData:
          Fn::Base64: !Sub |
            #!/bin/bash
            dnf update -y
            dnf install -y httpd
            systemctl start httpd
            systemctl enable httpd
            echo "<h1>Private WAS - High Availability</h1>" > /var/www/html/index.html

  AutoScalingGroup:
    Type: AWS::AutoScaling::AutoScalingGroup
    Properties:
      VPCZoneIdentifier: [!Ref PrivateSubnet1, !Ref PrivateSubnet2]
      LaunchTemplate:
        LaunchTemplateId: !Ref LaunchTemplate
        Version: !GetAtt LaunchTemplate.LatestVersionNumber
      MinSize: '2'
      MaxSize: '4'
      DesiredCapacity: '2'
      TargetGroupARNs: [!Ref ALBTargetGroup]

Outputs:
  LoadBalancerDNS:
    Value: !Sub "http://${ApplicationLoadBalancer.DNSName}"