AWSTemplateFormatVersion: '2010-09-09'
Description: AWS IPv6 Hands-On Advance
Parameters:
  LinuxLatestAmi :
    Type : AWS::SSM::Parameter::Value<String>
    Default : /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
    AllowedValues :
      - /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2

Resources:
# VPC
  ClientVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock : 172.16.0.0/24
      EnableDnsSupport: true
      EnableDnsHostnames: true
      InstanceTenancy: default
      Tags:
      - Key: Name
        Value: !Sub '${AWS::StackName}-VPC'
  ClientVPCCidrBlock:
    Type: AWS::EC2::VPCCidrBlock
    Properties:
      AmazonProvidedIpv6CidrBlock: true
      VpcId: !Ref 'ClientVPC'

# Subnet
# PublicSubnet
  ClientPublicSubnet:
    Type: AWS::EC2::Subnet
    DependsOn:
      - AttachGateway
      - ClientVPCCidrBlock
    Properties:
      AvailabilityZone: !Select [0, !GetAZs {Ref: 'AWS::Region'}]
      CidrBlock : 172.16.0.0/25
      Ipv6CidrBlock: !Sub ['${Param1}00::/64', {Param1: !Select ['0', !Split ['00::/',
                     !Select [0, !GetAtt 'ClientVPC.Ipv6CidrBlocks']]]}]
      AssignIpv6AddressOnCreation: true
      Tags:
        - Key: Name
          Value: !Sub '${AWS::StackName}-ClientPublicSubnet'
      VpcId: !Ref 'ClientVPC'

  ClientPublicSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref 'ClientPublicSubnet'
      RouteTableId: !Ref 'PublicRouteTable'

# PrivateSubnet
  ClientPrivateSubnet:
    Type: AWS::EC2::Subnet
    DependsOn:
      - AttachGateway
      - ClientVPCCidrBlock
    Properties:
      AvailabilityZone: !Select [0, !GetAZs {Ref: 'AWS::Region'}]
      Ipv6Native: true
      EnableDns64 : true
      Ipv6CidrBlock: !Sub ['${Param1}01::/64', {Param1: !Select ['0', !Split ['00::/',
                     !Select [0, !GetAtt 'ClientVPC.Ipv6CidrBlocks']]]}]
      AssignIpv6AddressOnCreation: true
      Tags:
        - Key: Name
          Value: !Sub '${AWS::StackName}-ClientPrivateSubnet'
      VpcId: !Ref 'ClientVPC'

  ClientPrivateSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref 'ClientPrivateSubnet'
      RouteTableId: !Ref 'PrivateRouteTable'

# Gateway
  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
      - Key: Name
        Value: !Sub '${AWS::StackName}-IGW'

  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref 'ClientVPC'
      InternetGatewayId: !Ref 'InternetGateway'

  EgressOnlyInternetGateway:
    Type: AWS::EC2::EgressOnlyInternetGateway
    Properties:
      VpcId: !Ref 'ClientVPC'

# RouteTable/RouteRecord
# for Public Subnet
  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    DependsOn: AttachGateway
    Properties:
      VpcId: !Ref 'ClientVPC'
      Tags:
      - Key: Name
        Value: !Sub '${AWS::StackName}-PublicRoute'

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

# for Private Subnet
  PrivateRouteTable:
    Type: AWS::EC2::RouteTable
    DependsOn: AttachGateway
    Properties:
      VpcId: !Ref 'ClientVPC'
      Tags:
        - Key: Name
          Value: !Sub '${AWS::StackName}-PrivateRoute'

  PrivateRoute64ff9b :
    Type : AWS::EC2::Route
    DependsOn : PrivateRouteTable
    Properties :
      RouteTableId : !Ref 'PrivateRouteTable'
      DestinationIpv6CidrBlock : 64:ff9b::/96
      NatGatewayId : !Ref 'ClientVPCNatGateway'

  PrivateRouteDefualtV6:
    Type: AWS::EC2::Route
    DependsOn: PrivateRouteTable
    Properties:
      DestinationIpv6CidrBlock: ::/0
      RouteTableId: !Ref 'PrivateRouteTable'
      EgressOnlyInternetGatewayId: !Ref 'EgressOnlyInternetGateway'

#SecurityGroup
  SessionManagerSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: "For Security VPC Session Manager"
      GroupDescription: Enable HTTPs access via port 443
      VpcId: !Ref ClientVPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: 172.16.0.0/25

# Endpoint for Session Manager
  ClientVPCEndpointSSM:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: True
      SecurityGroupIds:
        - !Ref SessionManagerSecurityGroup
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ssm
      SubnetIds:
        - !Ref ClientPublicSubnet
      VpcEndpointType: Interface
      VpcId: !Ref ClientVPC

  SecurityVPCEndpointSMMMessages:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: True
      SecurityGroupIds:
        - !Ref SessionManagerSecurityGroup
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ssmmessages
      SubnetIds:
        - !Ref ClientPublicSubnet
      VpcEndpointType: Interface
      VpcId: !Ref ClientVPC

# NATGateway
  ClientVPCNatGatewayEIP :
    Type : AWS::EC2::EIP
    Properties :
      Domain : vpc
      Tags :
        - Key : Name
          Value :  !Sub '${AWS::StackName}-ClientVPCNatGatewayEIP'

  ClientVPCNatGateway :
    Type : AWS::EC2::NatGateway
    Properties :
      AllocationId : !GetAtt ClientVPCNatGatewayEIP.AllocationId
      ConnectivityType : public
      SubnetId : !Ref ClientPublicSubnet
      Tags :
        - Key : Name
          Value :  !Sub '${AWS::StackName}-ClientVPCNatGateway'

# BastionLinuxServer
  BastionLinuxServer :
    Type : 'AWS::EC2::Instance'
    Properties :
      DisableApiTermination : 'FALSE'
      ImageId : !Ref LinuxLatestAmi
      InstanceType : t3.micro
      Monitoring : 'false'
      IamInstanceProfile: !Ref EC2InstanceProfile
      Tags :
        - Key : Name
          Value : !Sub '${AWS::StackName}-BastionLinuxServer'
      NetworkInterfaces :
        - DeleteOnTermination : 'true'
          Description : Primary network interface
          DeviceIndex : 0
          SubnetId : !Ref ClientPrivateSubnet

# EC2 Instance Profile
  EC2InstanceProfile :
    Type : AWS::IAM::InstanceProfile
    Properties :
      Roles :
        - Ref : EC2IAMRole
      InstanceProfileName : EC2InstanceProfile

# IAM Policy for SSM
  EC2IAMRole :
    Type : AWS::IAM::Role
    Properties :
      RoleName:  !Sub '${AWS::StackName}-Ipv6-HandsOn-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

#Outputs
Outputs :
  BastionLinuxServer:
    Value: !Ref 'BastionLinuxServer'
  ClientVPC:
    Value: !Ref 'ClientVPC'
    Export:
      Name: !Sub '${AWS::StackName}-VPC'
  Ipv4CidrBlock:
    Value: !GetAtt ClientVPC.CidrBlock
  ClientPublicSubnet:
    Value: !Ref 'ClientPublicSubnet'
    Export:
      Name: !Sub '${AWS::StackName}-ClientPublicSubnet'
  ClientPublicSubnetIpv4Cidr:
    Value: 172.16.0.0/25
  ClientCidrBlock:
    Value: !Select [ 0, !GetAtt ClientVPC.Ipv6CidrBlocks ]
    Export:
      Name: !Sub '${AWS::StackName}-ClientCidrBlock'
  ClientPublicSubnetClientCidrBlocks:
    Value: !Select [ 0, !GetAtt ClientPublicSubnet.Ipv6CidrBlocks ]
