AWSTemplateFormatVersion: '2010-09-09'
Description: HA 3-Tier Architecture with Auto-Naming ASG Instances

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:
    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::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway

  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

  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

  # --- 2. NAT Gateway 및 라우팅 ---
  NAT1EIP:
    Type: AWS::EC2::EIP
    DependsOn: GatewayAttachment
    Properties:
      Domain: vpc

  NAT2EIP:
    Type: AWS::EC2::EIP
    DependsOn: GatewayAttachment
    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

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: HA-Pub-RT

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

  PubSub1Assoc:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet1
      RouteTableId: !Ref PublicRouteTable

  PubSub2Assoc:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet2
      RouteTableId: !Ref PublicRouteTable

  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

  PriSub1Assoc:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet1
      RouteTableId: !Ref PrivateRouteTable1

  PriSub2Assoc:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet2
      RouteTableId: !Ref PrivateRouteTable2

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

  InternalALBSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Internal ALB HTTP access
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          SourceSecurityGroupId: !Ref ALBSecurityGroup

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

  StandAloneWASSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security Group for Standalone ASG servers
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0

  # --- 4. 로드 밸런서 ---
  ApplicationLoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Scheme: internet-facing
      Subnets: [ !Ref PublicSubnet1, !Ref PublicSubnet2 ]
      SecurityGroups: [ !Ref ALBSecurityGroup ]
      Tags:
        - Key: Name
          Value: HA-External-ALB

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

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

  InternalApplicationLoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Scheme: internal
      Subnets: [ !Ref PrivateSubnet1, !Ref PrivateSubnet2 ]
      SecurityGroups: [ !Ref InternalALBSecurityGroup ]
      Tags:
        - Key: Name
          Value: HA-Internal-ALB

  InternalALBListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions: [ { Type: forward, TargetGroupArn: !Ref InternalALBTargetGroup } ]
      LoadBalancerArn: !Ref InternalApplicationLoadBalancer
      Port: 80
      Protocol: HTTP

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

  # --- 5. 오토 스케일링 그룹 1 (Main WAS) ---
  MainLaunchTemplate:
    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>Main WAS Group</h1>" > /var/www/html/index.html

  MainAutoScalingGroup:
    Type: AWS::AutoScaling::AutoScalingGroup
    DependsOn: [ NATGateway1, NATGateway2, PrivateRoute1, PrivateRoute2 ]
    Properties:
      VPCZoneIdentifier: [ !Ref PrivateSubnet1, !Ref PrivateSubnet2 ]
      LaunchTemplate:
        LaunchTemplateId: !Ref MainLaunchTemplate
        Version: !GetAtt MainLaunchTemplate.LatestVersionNumber
      MinSize: '2'
      MaxSize: '4'
      DesiredCapacity: '2'
      TargetGroupARNs: [ !Ref ALBTargetGroup, !Ref InternalALBTargetGroup ]
      Tags:
        - Key: Name
          Value: ASG-Main-WAS-Instance # 생성되는 서버의 이름으로 표시됩니다.
          PropagateAtLaunch: true      # 이 설정이 있어야 개별 서버에 이름이 붙습니다.

  # --- 6. 오토 스케일링 그룹 2 (Standalone 대체용) ---
  StandAloneLaunchTemplate:
    Type: AWS::EC2::LaunchTemplate
    Properties:
      LaunchTemplateData:
        ImageId: !Ref LatestAmiId
        InstanceType: t3.micro
        KeyName: !Ref KeyName
        SecurityGroupIds: [ !Ref StandAloneWASSecurityGroup ]
        UserData:
          Fn::Base64: !Sub |
            #!/bin/bash
            dnf update -y
            dnf install -y httpd
            systemctl start httpd
            systemctl enable httpd
            echo "<h1>Standalone WAS Group</h1>" > /var/www/html/index.html

  StandAloneAutoScalingGroup:
    Type: AWS::AutoScaling::AutoScalingGroup
    DependsOn: [ NATGateway1, NATGateway2, PrivateRoute1, PrivateRoute2 ]
    Properties:
      VPCZoneIdentifier: [ !Ref PrivateSubnet1, !Ref PrivateSubnet2 ]
      LaunchTemplate:
        LaunchTemplateId: !Ref StandAloneLaunchTemplate
        Version: !GetAtt StandAloneLaunchTemplate.LatestVersionNumber
      MinSize: '2'
      MaxSize: '4'
      DesiredCapacity: '2'
      Tags:
        - Key: Name
          Value: ASG-Standalone-Instance # 생성되는 서버의 이름으로 표시됩니다.
          PropagateAtLaunch: true        # 이 설정이 있어야 개별 서버에 이름이 붙습니다.

  # --- 7. 퍼블릭 Web 서버 ---
  PublicWebServer:
    Type: AWS::EC2::Instance
    DependsOn: GatewayAttachment
    Properties:
      InstanceType: t3.micro
      ImageId: !Ref LatestAmiId
      KeyName: !Ref KeyName
      SubnetId: !Ref PublicSubnet1
      SecurityGroupIds: [ !Ref ALBSecurityGroup ]
      Tags:
        - Key: Name
          Value: Public-Web-Server
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash
          dnf update -y
          dnf install -y httpd
          systemctl start httpd
          systemctl enable httpd
          echo "<h1>Public Web Server</h1>" > /var/www/html/index.html

Outputs:
  ExternalALBDNS:
    Value: !Sub "http://${ApplicationLoadBalancer.DNSName}"
  InternalALBDNS:
    Value: !GetAtt InternalApplicationLoadBalancer.DNSName
  PublicWebServerIP:
    Value: !GetAtt PublicWebServer.PublicIp