AWSTemplateFormatVersion: '2010-09-09'
Description: >
  TheSimplifiedTech — Site-to-Site VPN Lab A scaffold.
  Builds a "cloud" VPC and a separate "fake on-premises" VPC whose public EC2 runs
  strongSwan to act as your Customer Gateway device. You then build the AWS VPN side
  by hand (Customer Gateway, Virtual Private Gateway, VPN connection, routes) and bring
  a real IPsec tunnel UP. Tear the stack down when finished — see the lab teardown step.

Parameters:
  KeyName:
    Type: AWS::EC2::KeyPair::KeyName
    Description: An existing EC2 key pair, used to SSH into the strongSwan host.
  SshCidr:
    Type: String
    Default: 0.0.0.0/0
    Description: CIDR allowed to SSH to the strongSwan host. Restrict to your-ip/32 for safety.
  LatestUbuntuAmi:
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/canonical/ubuntu/server/22.04/stable/current/amd64/hvm/ebs-gp2/ami-id
    Description: Resolves the latest Ubuntu 22.04 AMI in this region (do not change).

Resources:
  # ──────────────── "Cloud" side — the VPC your VPN connects INTO ────────────────
  CloudVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags: [{ Key: Name, Value: s2s-lab-cloud-vpc }]

  CloudSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref CloudVPC
      CidrBlock: 10.0.1.0/24
      Tags: [{ Key: Name, Value: s2s-lab-cloud-subnet }]

  CloudRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref CloudVPC
      Tags: [{ Key: Name, Value: s2s-lab-cloud-rt }]

  CloudSubnetAssoc:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref CloudSubnet
      RouteTableId: !Ref CloudRouteTable

  CloudInstanceSG:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Cloud test instance — allow ICMP from the on-prem network
      VpcId: !Ref CloudVPC
      SecurityGroupIngress:
        - { IpProtocol: icmp, FromPort: -1, ToPort: -1, CidrIp: 172.16.0.0/16 }
      Tags: [{ Key: Name, Value: s2s-lab-cloud-sg }]

  CloudInstance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t3.micro
      ImageId: !Ref LatestUbuntuAmi
      SubnetId: !Ref CloudSubnet
      SecurityGroupIds: [!Ref CloudInstanceSG]
      Tags: [{ Key: Name, Value: s2s-lab-cloud-instance }]

  # ──────────────── "Fake on-prem" side — strongSwan = your Customer Gateway ─────
  OnPremVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 172.16.0.0/16
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags: [{ Key: Name, Value: s2s-lab-onprem-vpc }]

  OnPremSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref OnPremVPC
      CidrBlock: 172.16.1.0/24
      MapPublicIpOnLaunch: true
      Tags: [{ Key: Name, Value: s2s-lab-onprem-subnet }]

  OnPremIGW:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags: [{ Key: Name, Value: s2s-lab-onprem-igw }]

  OnPremIGWAttach:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref OnPremVPC
      InternetGatewayId: !Ref OnPremIGW

  OnPremRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref OnPremVPC
      Tags: [{ Key: Name, Value: s2s-lab-onprem-rt }]

  OnPremSubnetAssoc:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref OnPremSubnet
      RouteTableId: !Ref OnPremRouteTable

  OnPremDefaultRoute:
    Type: AWS::EC2::Route
    DependsOn: OnPremIGWAttach
    Properties:
      RouteTableId: !Ref OnPremRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref OnPremIGW

  # Route cloud-bound traffic at the strongSwan host so it can tunnel it to AWS.
  OnPremToCloudRoute:
    Type: AWS::EC2::Route
    DependsOn: StrongSwanInstance
    Properties:
      RouteTableId: !Ref OnPremRouteTable
      DestinationCidrBlock: 10.0.0.0/16
      InstanceId: !Ref StrongSwanInstance

  StrongSwanSG:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: strongSwan host — IKE/IPsec from AWS VPN endpoints, SSH from you, ICMP from cloud
      VpcId: !Ref OnPremVPC
      SecurityGroupIngress:
        - { IpProtocol: udp, FromPort: 500, ToPort: 500, CidrIp: 0.0.0.0/0 }
        - { IpProtocol: udp, FromPort: 4500, ToPort: 4500, CidrIp: 0.0.0.0/0 }
        - { IpProtocol: '50', FromPort: -1, ToPort: -1, CidrIp: 0.0.0.0/0 }
        - { IpProtocol: icmp, FromPort: -1, ToPort: -1, CidrIp: 10.0.0.0/16 }
        - { IpProtocol: tcp, FromPort: 22, ToPort: 22, CidrIp: !Ref SshCidr }
      Tags: [{ Key: Name, Value: s2s-lab-strongswan-sg }]

  StrongSwanInstance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t3.micro
      ImageId: !Ref LatestUbuntuAmi
      KeyName: !Ref KeyName
      SubnetId: !Ref OnPremSubnet
      SecurityGroupIds: [!Ref StrongSwanSG]
      SourceDestCheck: false   # REQUIRED — this host routes traffic, not just sends its own
      Tags: [{ Key: Name, Value: s2s-lab-strongswan }]
      UserData:
        Fn::Base64: |
          #!/bin/bash
          set -eux
          export DEBIAN_FRONTEND=noninteractive
          apt-get update -y
          apt-get install -y strongswan
          # The strongSwan host forwards traffic between the VPN tunnel and the subnet.
          sysctl -w net.ipv4.ip_forward=1
          echo 'net.ipv4.ip_forward=1' > /etc/sysctl.d/99-vpn.conf
          # Helper the student runs with the values from the AWS "Download configuration" file.
          cat > /opt/configure-vpn.sh <<'SCRIPT'
          #!/bin/bash
          # Usage: sudo /opt/configure-vpn.sh <TUNNEL1_AWS_OUTSIDE_IP> <TUNNEL1_PSK> <TUNNEL2_AWS_OUTSIDE_IP> <TUNNEL2_PSK>
          set -eu
          T1="$1"; P1="$2"; T2="$3"; P2="$4"
          TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 60")
          MYPUB=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/public-ipv4)
          cat > /etc/ipsec.conf <<EOF
          config setup
          conn %default
            keyexchange=ikev2
            ike=aes128-sha1-modp1024
            esp=aes128-sha1-modp1024
            dpdaction=restart
            dpddelay=10s
            rekey=yes
            leftid=${MYPUB}
            left=%defaultroute
            leftsubnet=172.16.0.0/16
            rightsubnet=10.0.0.0/16
            auto=start
          conn aws-tunnel-1
            right=${T1}
          conn aws-tunnel-2
            right=${T2}
          EOF
          cat > /etc/ipsec.secrets <<EOF
          ${MYPUB} ${T1} : PSK "${P1}"
          ${MYPUB} ${T2} : PSK "${P2}"
          EOF
          ipsec restart
          sleep 5
          echo "Done. Check with: sudo ipsec statusall"
          SCRIPT
          chmod +x /opt/configure-vpn.sh

  StrongSwanEIP:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc
      Tags: [{ Key: Name, Value: s2s-lab-strongswan-eip }]

  StrongSwanEIPAssoc:
    Type: AWS::EC2::EIPAssociation
    Properties:
      AllocationId: !GetAtt StrongSwanEIP.AllocationId
      InstanceId: !Ref StrongSwanInstance

Outputs:
  StrongSwanPublicIp:
    Description: Use this as the Customer Gateway IP address in AWS, and SSH target.
    Value: !Ref StrongSwanEIP
  CloudInstancePrivateIp:
    Description: Ping THIS from the strongSwan host to prove the tunnel works.
    Value: !GetAtt CloudInstance.PrivateIp
  CloudCidr:
    Description: The cloud network (the remote network for your VPN connection).
    Value: 10.0.0.0/16
  OnPremCidr:
    Description: The on-prem network (the static route for your VPN connection).
    Value: 172.16.0.0/16
  CloudRouteTableId:
    Description: Enable VGW route propagation on THIS route table.
    Value: !Ref CloudRouteTable
