Parameters: VpcCIDR: Description: Please enter the IP range (CIDR notation) for this VPC Type: String Default: 10.10.0.0/16 PublicSubnet1CIDR: Description: Please enter the IP range (CIDR notation) for the public subnet in the first Availability Zone Type: String Default: 10.10.10.0/24 PublicSubnet2CIDR: Description: Please enter the IP range (CIDR notation) for the public subnet in the second Availability Zone Type: String Default: 10.10.11.0/24 PrivateSubnet1CIDR: Description: Please enter the IP range (CIDR notation) for the private subnet in the first Availability Zone Type: String Default: 10.10.20.0/24 PrivateSubnet2CIDR: Description: Please enter the IP range (CIDR notation) for the private subnet in the second Availability Zone Type: String Default: 10.10.21.0/24 LatestLinux2AmiId: Description: Region specific image from the Parameter Store Type: 'AWS::SSM::Parameter::Value' Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2' ResourceName: Type: String Default: ipv6-app Description: Prefix of Resources created for this workshop. Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: default: "Resource Configuration" Parameters: - ResourceName ParameterLabels: ResourceName: default: "Resource Prefix" Resources: VPC: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref VpcCIDR EnableDnsSupport: true EnableDnsHostnames: true Tags: - Key: Name Value: !Join [ -, [!Ref ResourceName, 'VPC'] ] VpcCidrBlockIpv6: Type: AWS::EC2::VPCCidrBlock Properties: VpcId: !Ref VPC AmazonProvidedIpv6CidrBlock: true InternetGateway: Type: AWS::EC2::InternetGateway Properties: Tags: - Key: Name Value: !Join [ -, [!Ref ResourceName, 'IGW'] ] InternetGatewayAttachment: Type: AWS::EC2::VPCGatewayAttachment Properties: InternetGatewayId: !Ref InternetGateway VpcId: !Ref VPC PublicSubnet1: Type: AWS::EC2::Subnet DependsOn: VpcCidrBlockIpv6 Properties: VpcId: !Ref VPC AvailabilityZone: !Select [ 0, !GetAZs '' ] CidrBlock: !Ref PublicSubnet1CIDR Ipv6CidrBlock: !Select [ 0, !Cidr [ !Select [ 0, !GetAtt VPC.Ipv6CidrBlocks], 256, 64 ]] AssignIpv6AddressOnCreation: true Tags: - Key: Name Value: Public Subnet (AZ1) PublicSubnet2: Type: AWS::EC2::Subnet DependsOn: VpcCidrBlockIpv6 Properties: VpcId: !Ref VPC AvailabilityZone: !Select [ 1, !GetAZs '' ] CidrBlock: !Ref PublicSubnet2CIDR Ipv6CidrBlock: !Select [ 1, !Cidr [ !Select [ 0, !GetAtt VPC.Ipv6CidrBlocks], 256, 64 ]] AssignIpv6AddressOnCreation: true Tags: - Key: Name Value: Public Subnet (AZ2) PrivateSubnet1: Type: AWS::EC2::Subnet DependsOn: VpcCidrBlockIpv6 Properties: VpcId: !Ref VPC AvailabilityZone: !Select [ 0, !GetAZs '' ] CidrBlock: !Ref PrivateSubnet1CIDR Ipv6CidrBlock: !Select [ 2, !Cidr [ !Select [ 0, !GetAtt VPC.Ipv6CidrBlocks], 256, 64 ]] Tags: - Key: Name Value: Private Subnet (AZ1) PrivateSubnet2: Type: AWS::EC2::Subnet DependsOn: VpcCidrBlockIpv6 Properties: VpcId: !Ref VPC AvailabilityZone: !Select [ 1, !GetAZs '' ] CidrBlock: !Ref PrivateSubnet2CIDR Ipv6CidrBlock: !Select [ 3, !Cidr [ !Select [ 0, !GetAtt VPC.Ipv6CidrBlocks], 256, 64 ]] Tags: - Key: Name Value: Private Subnet (AZ2) NatGateway1EIP: Type: AWS::EC2::EIP DependsOn: InternetGatewayAttachment Properties: Domain: vpc NatGateway2EIP: Type: AWS::EC2::EIP DependsOn: InternetGatewayAttachment Properties: Domain: vpc NatGateway1: Type: AWS::EC2::NatGateway Properties: AllocationId: !GetAtt NatGateway1EIP.AllocationId SubnetId: !Ref PublicSubnet1 NatGateway2: Type: AWS::EC2::NatGateway Properties: AllocationId: !GetAtt NatGateway2EIP.AllocationId SubnetId: !Ref PublicSubnet2 EgressOnlyInternetGateway: Type: AWS::EC2::EgressOnlyInternetGateway Properties: VpcId: !Ref VPC PublicRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: Public Routes DefaultPublicRoute: Type: AWS::EC2::Route DependsOn: InternetGatewayAttachment Properties: RouteTableId: !Ref PublicRouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway DefaultPublicRouteIpv6: Type: AWS::EC2::Route DependsOn: InternetGatewayAttachment Properties: RouteTableId: !Ref PublicRouteTable DestinationIpv6CidrBlock: ::/0 GatewayId: !Ref InternetGateway PublicSubnet1RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PublicRouteTable SubnetId: !Ref PublicSubnet1 PublicSubnet2RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PublicRouteTable SubnetId: !Ref PublicSubnet2 PrivateRouteTable1: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: Private Routes (AZ1) DefaultPrivateRoute1: Type: AWS::EC2::Route Properties: RouteTableId: !Ref PrivateRouteTable1 DestinationCidrBlock: 0.0.0.0/0 NatGatewayId: !Ref NatGateway1 DefaultPrivateRoute1Ipv6: Type: AWS::EC2::Route Properties: RouteTableId: !Ref PrivateRouteTable1 DestinationIpv6CidrBlock: ::/0 EgressOnlyInternetGatewayId: !Ref EgressOnlyInternetGateway PrivateSubnet1RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PrivateRouteTable1 SubnetId: !Ref PrivateSubnet1 PrivateRouteTable2: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: Private Routes (AZ2) DefaultPrivateRoute2: Type: AWS::EC2::Route Properties: RouteTableId: !Ref PrivateRouteTable2 DestinationCidrBlock: 0.0.0.0/0 NatGatewayId: !Ref NatGateway2 DefaultPrivateRoute2Ipv6: Type: AWS::EC2::Route Properties: RouteTableId: !Ref PrivateRouteTable2 DestinationIpv6CidrBlock: ::/0 EgressOnlyInternetGatewayId: !Ref EgressOnlyInternetGateway PrivateSubnet2RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PrivateRouteTable2 SubnetId: !Ref PrivateSubnet2 WebServerSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupName: "web-server-sg" GroupDescription: "Security Group for Web Servers" VpcId: !Ref VPC SecurityGroupIngress: - IpProtocol: tcp SourceSecurityGroupId: !Ref ALBSecurityGroup FromPort: 80 ToPort: 80 # ALB ALBListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - Type: forward TargetGroupArn: Ref: WebServerTargetGroup LoadBalancerArn: Ref: ApplicationLoadBalancer Port: 80 Protocol: HTTP ApplicationLoadBalancer: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Scheme: internet-facing IpAddressType: dualstack Subnets: - Ref: PublicSubnet1 - Ref: PublicSubnet2 SecurityGroups: - Ref: ALBSecurityGroup # ALB Security Group with Allowed IPs ALBSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: 'alb-with-ipv6-support' VpcId: Ref: VPC SecurityGroupIngress: - IpProtocol: tcp CidrIpv6: ::/0 FromPort: 80 ToPort: 80 - IpProtocol: tcp CidrIp: 0.0.0.0/0 FromPort: 80 ToPort: 80 WebServerTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: HealthCheckIntervalSeconds: 5 HealthCheckProtocol: HTTP HealthCheckTimeoutSeconds: 3 HealthyThresholdCount: 3 Matcher: HttpCode: '200' Name: WebServerTargetGroup Port: 80 Protocol: HTTP TargetGroupAttributes: - Key: deregistration_delay.timeout_seconds Value: '10' UnhealthyThresholdCount: 3 VpcId: Ref: 'VPC' LaunchConfigWebServer: Type: AWS::AutoScaling::LaunchConfiguration Properties: ImageId: !Ref LatestLinux2AmiId IamInstanceProfile: !Ref WebServerInstanceProfile SecurityGroups: - Ref: WebServerSecurityGroup InstanceType: t3.micro UserData: !Base64 | #!/bin/bash -x yum update -y yum install httpd -y sudo amazon-linux-extras install -y php7.2 service httpd start chkconfig httpd on cd /var/www/html cat <<'EOT' >> /var/www/html/index.php EOT cat <<'EOT' >> /etc/httpd/conf.d/log.conf RemoteIPHeader X-Forwarded-For LogFormat "%{X-Forwarded-For}i %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\ " combined EOT service httpd restart EbsOptimized: "true" AutoScalingWebServer: Type: AWS::AutoScaling::AutoScalingGroup Properties: VPCZoneIdentifier: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 LaunchConfigurationName: !Ref LaunchConfigWebServer MinSize: '1' MaxSize: '1' HealthCheckGracePeriod: 300 MaxInstanceLifetime: 2592000 TargetGroupARNs: - !Ref WebServerTargetGroup Tags: - Key: Name PropagateAtLaunch: True Value: Fn::Join: - ': ' - [!Ref ResourceName, 'Web Server'] ### WebServer IAM Role WebServerRole: Type: AWS::IAM::Role Properties: RoleName: Fn::Join: - '-' - ['webserver-role', !Ref "AWS::Region"] AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - ec2.amazonaws.com Action: - sts:AssumeRole Path: / ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM Policies: - PolicyName: !Join [ -, ['webserver-policy', !Ref "AWS::Region"] ] PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - ssm:GetParameter - ssm:GetParameters - ssm:DescribeParameters Resource: Fn::Join: - ':' - ["arn:aws:ssm", !Ref "AWS::Region", !Ref "AWS::AccountId", "*"] WebServerInstanceProfile: Type: AWS::IAM::InstanceProfile Properties: InstanceProfileName: Fn::Join: - '-' - ['webserver-profile', !Ref "AWS::Region"] Path: / Roles: - !Ref WebServerRole TestServerSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupName: "test-server-sg" GroupDescription: "Security Group for Test Server" VpcId: !Ref VPC TestServer: Type: AWS::EC2::Instance Properties: IamInstanceProfile: !Ref WebServerInstanceProfile InstanceType: t3.micro ImageId: !Ref LatestLinux2AmiId NetworkInterfaces: - AssociatePublicIpAddress: 'true' DeviceIndex: '0' Ipv6AddressCount: 1 GroupSet: - !Ref TestServerSecurityGroup SubnetId: Ref: PublicSubnet1 Tags: - Key: Name Value: Fn::Join: - ': ' - [!Ref ResourceName, 'Test Server'] Outputs: ALBDNSName: Description: "The DNS name for the load balancer." Value: !GetAtt ApplicationLoadBalancer.DNSName