AWSTemplateFormatVersion: '2010-09-09'
Description: >
  VPC + Public Subnet + Single EC2 instance with Security Group, Elastic IP, and SSM access.
  No SSH key required - use AWS Systems Manager Session Manager instead.

# ──────────────────────────────────────────
# Parameters
# ──────────────────────────────────────────
Parameters:

  EnvironmentName:
    Type: String
    Default: dev
    AllowedValues: [dev, staging, prod]
    Description: Environment name (used for tagging)

  VpcCidr:
    Type: String
    Default: 10.0.0.0/16
    AllowedPattern: '(\d{1,3}\.){3}\d{1,3}/\d{1,2}'
    Description: CIDR block for the VPC

  PublicSubnetCidr:
    Type: String
    Default: 10.0.1.0/24
    AllowedPattern: '(\d{1,3}\.){3}\d{1,3}/\d{1,2}'
    Description: CIDR block for the public subnet

  InstanceType:
    Type: String
    Default: t3.micro
    AllowedValues:
      - t3.micro
      - t3.small
      - t3.medium
      - t3.large
    Description: EC2 instance type

  AmiId:
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64
    Description: Amazon Linux 2023 latest AMI (auto-resolved via SSM)

  RootVolumeSize:
    Type: Number
    Default: 20
    MinValue: 8
    MaxValue: 500
    Description: Root EBS volume size in GiB

  KeyPairName:
    Type: AWS::EC2::KeyPair::KeyName
    Description: EC2 Key Pair for SSH access (must exist in your AWS account)

  AssignElasticIP:
    Type: String
    Default: 'true'
    AllowedValues: ['true', 'false']
    Description: Attach an Elastic IP to the instance

# ──────────────────────────────────────────
# Conditions
# ──────────────────────────────────────────
Conditions:
  CreateEIP: !Equals [!Ref AssignElasticIP, 'true']

# ──────────────────────────────────────────
# Resources
# ──────────────────────────────────────────
Resources:

  # ── VPC ──
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VpcCidr
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Sub '${EnvironmentName}-vpc'
        - Key: Environment
          Value: !Ref EnvironmentName

  # ── Internet Gateway ──
  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: !Sub '${EnvironmentName}-igw'
        - Key: Environment
          Value: !Ref EnvironmentName

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

  # ── Public Subnet ──
  PublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: !Ref PublicSubnetCidr
      AvailabilityZone: !Select [0, !GetAZs ""]
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Sub '${EnvironmentName}-public-subnet'
        - Key: Environment
          Value: !Ref EnvironmentName

  # ── Public Route Table ──
  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub '${EnvironmentName}-public-rtb'
        - Key: Environment
          Value: !Ref EnvironmentName

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

  PublicSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet
      RouteTableId: !Ref PublicRouteTable

  # ── IAM Role for SSM Session Manager ──
  EC2InstanceRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub '${EnvironmentName}-ec2-ssm-role'
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: ec2.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
      Tags:
        - Key: Name
          Value: !Sub '${EnvironmentName}-ec2-role'
        - Key: Environment
          Value: !Ref EnvironmentName

  EC2InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      InstanceProfileName: !Sub '${EnvironmentName}-ec2-instance-profile'
      Roles:
        - !Ref EC2InstanceRole

  # ── Security Group ──
  EC2SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub '${EnvironmentName}-ec2-sg'
      GroupDescription: Security group for EC2 instance
      VpcId: !Ref VPC
      # Inbound: HTTPS only (80 is commented out — enable if needed)
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
          Description: SSH inbound
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: 0.0.0.0/0
          Description: HTTPS inbound
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
          Description: HTTP inbound
      # Outbound: allow all
      SecurityGroupEgress:
        - IpProtocol: -1
          CidrIp: 0.0.0.0/0
          Description: Allow all outbound
      Tags:
        - Key: Name
          Value: !Sub '${EnvironmentName}-ec2-sg'
        - Key: Environment
          Value: !Ref EnvironmentName

  # ── EC2 Instance ──
  EC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: !Ref InstanceType
      ImageId: !Ref AmiId
      AvailabilityZone: !GetAtt PublicSubnet.AvailabilityZone
      SubnetId: !Ref PublicSubnet
      KeyName: !Ref KeyPairName
      IamInstanceProfile: !Ref EC2InstanceProfile
      SecurityGroupIds:
        - !Ref EC2SecurityGroup
      BlockDeviceMappings:
        - DeviceName: /dev/xvda
          Ebs:
            VolumeSize: !Ref RootVolumeSize
            VolumeType: gp3
            Encrypted: true
            DeleteOnTermination: true
      # UserData: runs on first boot
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash
          # 기본 환경 설정
          hostnamectl --static set-hostname mgmt-server
          ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime
          dnf update -y
          dnf install -y tree jq git htop wget unzip tar

          # 툴 설치 (kubectl, kops, helm)
          cd /root
          curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
          install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl

          curl -Lo kops https://github.com/kubernetes/kops/releases/download/$(curl -s https://api.github.com/repos/kubernetes/kops/releases/latest | grep tag_name | cut -d '"' -f 4)/kops-linux-amd64
          chmod +x kops
          mv kops /usr/local/bin/kops

          curl -s https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash

          # AWS CLI v2
          curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
          unzip awscliv2.zip
          ./aws/install
          echo "export AWS_DEFAULT_REGION=${AWS::Region}" >> /etc/profile

          # Terraform
          dnf install -y yum-utils
          dnf config-manager --add-repo https://rpm.releases.hashicorp.com/AmazonLinux/hashicorp.repo
          dnf install -y terraform

          # Docker
          dnf install -y docker
          systemctl start docker
          systemctl enable docker
          usermod -aG docker ec2-user

          # SSM Agent
          dnf install -y amazon-ssm-agent
          systemctl enable amazon-ssm-agent
          systemctl start amazon-ssm-agent

          # 사용자 편의 설정 (Alias 등)
          echo 'alias k=kubectl' >> /etc/profile
          echo 'alias vi=vim' >> /etc/profile
          echo 'alias wa="watch -d kubectl get svc,no,pods,deploy,rs"' >> /etc/profile
          echo 'source <(kubectl completion bash)' >> /etc/profile
          echo "sudo su -" >> /home/ec2-user/.bashrc

          # eksctl 설치
          curl --silent --location "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp
          mv /tmp/eksctl /usr/local/bin

          # kube-ps1 설치
          git clone https://github.com/jonmosco/kube-ps1.git /root/kube-ps1
          printf '%s\n' 'source /root/kube-ps1/kube-ps1.sh' 'KUBE_PS1_SYMBOL_ENABLE=false' "PS1='\$(kube_ps1)'\$PS1" >> /root/.bash_profile
      Tags:
        - Key: Name
          Value: !Sub '${EnvironmentName}-ec2'
        - Key: Environment
          Value: !Ref EnvironmentName

  # ── Elastic IP (optional) ──
  ElasticIP:
    Type: AWS::EC2::EIP
    Condition: CreateEIP
    Properties:
      Domain: vpc
      Tags:
        - Key: Name
          Value: !Sub '${EnvironmentName}-ec2-eip'

  EIPAssociation:
    Type: AWS::EC2::EIPAssociation
    Condition: CreateEIP
    Properties:
      InstanceId: !Ref EC2Instance
      EIP: !Ref ElasticIP

# ──────────────────────────────────────────
# Outputs
# ──────────────────────────────────────────
Outputs:

  VpcId:
    Description: VPC ID
    Value: !Ref VPC
    Export:
      Name: !Sub '${AWS::StackName}-VpcId'

  PublicSubnetId:
    Description: Public Subnet ID
    Value: !Ref PublicSubnet
    Export:
      Name: !Sub '${AWS::StackName}-PublicSubnetId'

  VpcCidrOutput:
    Description: VPC CIDR Block
    Value: !GetAtt VPC.CidrBlock

  InstanceId:
    Description: EC2 Instance ID
    Value: !Ref EC2Instance
    Export:
      Name: !Sub '${AWS::StackName}-InstanceId'

  PrivateIP:
    Description: Private IP address of the EC2 instance
    Value: !GetAtt EC2Instance.PrivateIp

  PublicIP:
    Description: Elastic IP (public) — only if AssignElasticIP=true
    Value: !If [CreateEIP, !Ref ElasticIP, 'N/A (EIP disabled)']

  SecurityGroupId:
    Description: Security Group ID
    Value: !Ref EC2SecurityGroup
    Export:
      Name: !Sub '${AWS::StackName}-SGID'

  SSMConnectCommand:
    Description: Connect to instance via SSM Session Manager (no SSH key needed)
    Value: !Sub 'aws ssm start-session --target ${EC2Instance} --region ${AWS::Region}'
