AWSTemplateFormatVersion: "2010-09-09"
Description: AWS Infrastructure Setup with ASG, ALB, Target Group, Apache HTTPD, NAT Gateway, and Dedicated Security Groups

Parameters:
  VPCCIDR:
    Type: String
    Default: "10.0.0.0/16"
  PublicSubnetACIDR:
    Type: String
    Default: "10.0.0.0/24"
  PublicSubnetCCIDR:
    Type: String
    Default: "10.0.1.0/24"
  PrivateSubnetACIDR:
    Type: String
    Default: "10.0.10.0/24"
  PrivateSubnetCCIDR:
    Type: String
    Default: "10.0.11.0/24"
  InstanceType:
    Type: String
    Default: "t3.micro"
    AllowedValues: [t2.micro, t3.micro, t3.small]
  ImageId:
    Type: String
    Description: The AMI ID for the EC2 instances
    Default: ami-062cddb9d94dcf95d # 기본값은 Amazon Linux 2 (us-east-1)
  DesiredCapacity:
    Type: Number
    Default: 2
    Description: The number of EC2 instances to launch
  MaxSize:
    Type: Number
    Default: 4
    Description: The maximum number of EC2 instances that can be launched
  MinSize:
    Type: Number
    Default: 2
    Description: The minimum number of EC2 instances that must be running

Resources:
  # VPC
  WSVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VPCCIDR
      EnableDnsSupport: "true"
      EnableDnsHostnames: "true"
      Tags:
        - Key: Name
          Value: ws-vpc

  # Internet Gateway
  WSIGW:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: ws-igw

  WSVPCGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref WSVPC
      InternetGatewayId: !Ref WSIGW

  # Public Subnets
  WSPublicSubnetA:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref WSVPC
      CidrBlock: !Ref PublicSubnetACIDR
      AvailabilityZone: !Select [0, !GetAZs ""]
      MapPublicIpOnLaunch: "true"
      Tags:
        - Key: Name
          Value: ws-pub-a

  WSPublicSubnetC:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref WSVPC
      CidrBlock: !Ref PublicSubnetCCIDR
      AvailabilityZone: !Select [2, !GetAZs ""]
      MapPublicIpOnLaunch: "true"
      Tags:
        - Key: Name
          Value: ws-pub-c

  # Private Subnets
  WSPrivateSubnetA:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref WSVPC
      CidrBlock: !Ref PrivateSubnetACIDR
      AvailabilityZone: !Select [0, !GetAZs ""]
      Tags:
        - Key: Name
          Value: ws-priv-a

  WSPrivateSubnetC:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref WSVPC
      CidrBlock: !Ref PrivateSubnetCCIDR
      AvailabilityZone: !Select [2, !GetAZs ""]
      Tags:
        - Key: Name
          Value: ws-priv-c

  # Elastic IP for NAT Gateway
  WSEIPA:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc

  WSEIPC:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc

  # NAT Gateway in Public Subnet A
  WSNATGatewayA:
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId: !GetAtt WSEIPA.AllocationId
      SubnetId: !Ref WSPublicSubnetA
      Tags:
        - Key: Name
          Value: ws-natgw-c

  WSNATGatewayC:
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId: !GetAtt WSEIPC.AllocationId
      SubnetId: !Ref WSPublicSubnetC
      Tags:
        - Key: Name
          Value: ws-natgw-c

  # Route Table for Public Subnets
  WSPublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref WSVPC
      Tags:
        - Key: Name
          Value: ws-pub-rt

  # Route for Public Subnets to Internet Gateway
  WSPublicRoute:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref WSPublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref WSIGW

  # Associate Public Subnets with Public Route Table
  WSPublicSubnetARouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref WSPublicSubnetA
      RouteTableId: !Ref WSPublicRouteTable

  WSPublicSubnetCRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref WSPublicSubnetC
      RouteTableId: !Ref WSPublicRouteTable

  # Private Route Table for Private Subnet A
  WSPrivateRouteTableA:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref WSVPC
      Tags:
        - Key: Name
          Value: ws-priv-a-rt

  # Route for Private Subnet A to NAT Gateway
  WSPrivateRouteA:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref WSPrivateRouteTableA
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref WSNATGatewayA

  # Associate Private Subnet A with Private Route Table A
  WSPrivateSubnetARouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref WSPrivateSubnetA
      RouteTableId: !Ref WSPrivateRouteTableA

  # Private Route Table for Private Subnet C
  WSPrivateRouteTableC:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref WSVPC
      Tags:
        - Key: Name
          Value: ws-priv-c-rt

  # Route for Private Subnet C to NAT Gateway
  WSPrivateRouteB:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref WSPrivateRouteTableC
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref WSNATGatewayC

  # Associate Private Subnet C with Private Route Table C
  WSPrivateSubnetCRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref WSPrivateSubnetC
      RouteTableId: !Ref WSPrivateRouteTableC

  # Security Group for App Servers
  AppServerSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: "Allow HTTP access to App Servers"
      VpcId: !Ref WSVPC
      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 # Allow SSH access for debugging (restrict this in production)
      Tags:
        - Key: Name
          Value: app-server-sg

  # Launch Template for Auto Scaling Group
  AppServerLaunchTemplate:
    Type: AWS::EC2::LaunchTemplate
    Properties:
      LaunchTemplateName: app-server-launch-template
      LaunchTemplateData:
        ImageId: !Ref ImageId
        InstanceType: !Ref InstanceType
        SecurityGroupIds:
          - !Ref AppServerSecurityGroup
        UserData: !Base64 |
          #!/bin/bash
          sudo yum update -y
          sudo yum install -y httpd
          echo "Hello from Auto Scaling Group instance $(hostname)" > /var/www/html/index.html
          sudo systemctl start httpd
          sudo systemctl enable httpd

  # Auto Scaling Group
  AppServerASG:
    Type: AWS::AutoScaling::AutoScalingGroup
    Properties:
      AutoScalingGroupName: app-server-asg
      LaunchTemplate:
        LaunchTemplateId: !Ref AppServerLaunchTemplate
        Version: !GetAtt AppServerLaunchTemplate.LatestVersionNumber
      MinSize: !Ref MinSize
      MaxSize: !Ref MaxSize
      DesiredCapacity: !Ref DesiredCapacity
      HealthCheckType: ELB
      HealthCheckGracePeriod: 300
      VPCZoneIdentifier:
        - !Ref WSPrivateSubnetA
        - !Ref WSPrivateSubnetC
      TargetGroupARNs:
        - !Ref WSTargetGroup
      Tags:
        - Key: Name
          Value: app-server-instance
          PropagateAtLaunch: true

  # Target Group for ALB
  WSTargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      Name: ws-target-group
      Protocol: HTTP
      Port: "80"
      VpcId: !Ref WSVPC
      TargetType: instance
      HealthCheckProtocol: HTTP
      HealthCheckPort: "80"
      HealthCheckPath: /
      Matcher:
        HttpCode: "200"

  # ALB
  WSALB:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Name: ws-alb
      Subnets:
        - Ref: WSPublicSubnetA
        - Ref: WSPublicSubnetC
      LoadBalancerAttributes:
        - Key: idle_timeout.timeout_seconds
          Value: "60"
      Scheme: internet-facing
      Type: application
      SecurityGroups:
        - !Ref AppServerSecurityGroup

  WSALBListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref WSTargetGroup
      LoadBalancerArn: !Ref WSALB
      Port: "80"
      Protocol: HTTP

Outputs:
  VPCId:
    Value: !Ref WSVPC
  PublicSubnetAId:
    Value: !Ref WSPublicSubnetA
  PublicSubnetBId:
    Value: !Ref WSPublicSubnetC
  PrivateSubnetAId:
    Value: !Ref WSPrivateSubnetA
  PrivateSubnetBId:
    Value: !Ref WSPrivateSubnetC
  LoadBalancerDNSName:
    Value: !GetAtt WSALB.DNSName
  AutoScalingGroupName:
    Value: !Ref AppServerASG