{ "AWSTemplateFormatVersion" : "2010-09-09", "Description" : "Creates an AWS Network Load balancer, which multiplexes traffic to registered scaled out back end web servers", "Parameters": { "KeyName" : { "Description" : "Amazon EC2 Key Pair", "Type" : "AWS::EC2::KeyPair::KeyName" }, "ILBName": { "Type" : "String", "Description": "Enter the name to associate with the ILB", "Default": "prot-ilb", "MinLength" : "3", "MaxLength" : "120" }, "QueueURL": { "Type" : "String", "Description": "Enter the URL of the Queue to send ILB updates to", "MinLength" : "3", "MaxLength" : "1024" }, "SSHLocation" : { "Description" : "Restrict SSH & HTTPS access to the Web Servers (by default can be accessed from anywhere)", "Type" : "String", "MinLength": "9", "MaxLength": "18", "Default" : "0.0.0.0/0", "AllowedPattern" : "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})", "ConstraintDescription" : "must be a valid CIDR range of the form x.x.x.x/x." }, "S3BucketName": { "Type" : "String", "Description": "Enter the name of the S3 Bucket which contains the lambda function code", "MinLength" : "3", "MaxLength" : "120" }, "PeerConnectionTargetCIDRs": { "Type": "CommaDelimitedList", "Default": "", "Description": "Comma delimited List of firewall trust subnet CIDRs to allow traffic from (based on number of firewall AZs above)" }, "LambdaZipFileName": { "Type" : "String", "Description": "Enter the name of the S3 object which contains the lambda function code", "MinLength" : "3", "MaxLength" : "120" }, "NumberOfFWAZs": { "Description" : "Total number of AZs in the firewall deployment (Min 2 and Max 4 depending on az availability)", "Type": "Number", "MinValue": "2", "MaxValue": "4", "Default": "2" }, "VpcAzs": { "Type": "List", "Description": "Enter the list of Availability Zones (Based on Number of AZs above)" }, "NumberOfAZs": { "Description" : "Total Number of AZs which will be used in this deployment (Min 2 and Max 4 depending on az availability)", "Type" : "Number", "MinValue" : "2", "Default" : "2", "MaxValue" : "4" }, "VPCID" : { "Type": "AWS::EC2::VPC::Id", "Description" : "VPC ID to be deployed into" }, "VPCSubnetCIDRs": { "Type": "CommaDelimitedList", "Default": "172.32.0.0/24, 172.32.1.0/24", "Description": "Comma-delimited list of CIDR blocks for the application trust subnets" }, "ILBSubnets": { "Description": "Comma-delimited list of subnets thats need to be associated to ILB", "Type": "CommaDelimitedList" }, "SameAccount": { "Type": "String", "Default": "true", "Description": "Flag to indicate if the application will be deployed into the same account as the firewall, or a different one", "AllowedValues": [ "true", "false" ] }, "CrossAccountRole": { "Type": "String", "Description": "Enter the ARN of the role to be used.", "Default": "" }, "PeerConnectionTargetAccountId": { "Type": "String", "Description": "Enter the Account ID number of the role to be used.", "Default": "" } }, "Mappings" : { "Constants": { "S3URL": { "URL1": "https://s3.amazonaws.com" }, "ILB": { "Type": "application" }, "ILBRouteTable": { "id": "None" } } }, "Conditions" : { "IsSameAccount" : {"Fn::Equals" : [{"Ref" : "SameAccount"}, "true"]}, "IsCrossAccount" : {"Fn::Equals" : [{"Ref" : "SameAccount"}, "false"]}, "FwAz2" : {"Fn::Equals" : [{"Ref" : "NumberOfFWAZs"}, "2"]}, "FwAz3" : {"Fn::Equals" : [{"Ref" : "NumberOfFWAZs"}, "3"]}, "FwAz3more" : {"Fn::Or": [ {"Fn::Equals" : [{"Ref" : "NumberOfFWAZs"}, "3"]}, {"Fn::Equals" : [{"Ref" : "NumberOfFWAZs"}, "4"]}]}, "FwAz4" : {"Fn::Equals" : [{"Ref" : "NumberOfFWAZs"}, "4"]}, "CreateSubnet2" : {"Fn::Equals" : [{"Ref" : "NumberOfAZs"}, "2"]}, "CreateSubnet3" : {"Fn::Equals" : [{"Ref" : "NumberOfAZs"}, "3"]}, "CreateSubnet3more" : {"Fn::Or": [ {"Fn::Equals" : [{"Ref" : "NumberOfAZs"}, "3"]}, {"Fn::Equals" : [{"Ref" : "NumberOfAZs"}, "4"]}]}, "CreateSubnet4" : {"Fn::Equals" : [{"Ref" : "NumberOfAZs"}, "4"]} }, "Metadata" : { "AWS::CloudFormation::Interface" : { "ParameterGroups" : [ { "Label": {"default": "Application-VPC Section"}, "Parameters": ["VPCID","NumberOfAZs", "VpcAzs", "VPCSubnetCIDRs", "ILBSubnets"] }, { "Label": {"default": "Load Balancer Section"}, "Parameters": ["ILBName"] }, { "Label": {"default": "Lambda Section"}, "Parameters": [ "S3BucketName", "LambdaZipFileName", "QueueURL" ] }, { "Label": {"default": "Access Section"}, "Parameters": ["KeyName", "SSHLocation"] }, { "Label": {"default": "VPC connectivity Section"}, "Parameters": ["NumberOfFWAZs", "PeerConnectionTargetCIDRs"] }, { "Label": {"default": "Cross Account Deployment"}, "Parameters": ["SameAccount", "CrossAccountRole", "PeerConnectionTargetAccountId"] } ], "ParameterLabels" : { "NumberOfAZs": {"default": "Number of AZs for Deployment:"}, "VpcAzs": {"default": "Select List of AZ:"}, "VPCID": {"default": "VPCID:"}, "VPCSubnetCIDRs": {"default": "VPC Subnet CIDRs:"}, "ILBSubnets": {"default": "ILBSubnets:"}, "ILBName": {"default": "ILB Name:"}, "S3BucketName": {"default": "S3 Bucket Name:"}, "LambdaZipFileName": {"default": "Lambda Zip File Name:"}, "QueueURL": {"default": "SQS Queue URL:"}, "KeyName": {"default": "Key Pair:"}, "SSHLocation": {"default": "SSH From:"}, "NumberOfFWAZs": {"default": "Number of Firewall AZs:"}, "PeerConnectionTargetCIDRs": {"default": "Firewall VPC trust Subnet CIDR"}, "CrossAccountRole": {"default": "Cross Account Role ARN (If cross account):"}, "SameAccount": {"default": "Same Account Deployment?:"}, "PeerConnectionTargetAccountId": {"default": "DMZ Firewall Account number (If cross account)"} } } }, "Resources": { "ILBSecurityGroup2fwaz" : { "Type" : "AWS::EC2::SecurityGroup", "Condition" : "FwAz2", "Properties" : { "GroupDescription" : "Internal Load Balancer Security Group with HTTP access on port 80 from for firewall template with 2 Az", "VpcId" : { "Ref" : "VPCID" }, "Tags": [ { "Key": "Name", "Value": { "Fn::Join": [ "-", [ { "Ref": "AWS::StackName" }, "ILBSecurityGroup2fwaz" ] ] } } ], "SecurityGroupIngress" : [ { "IpProtocol" : "-1", "FromPort" : "80", "ToPort" : "80", "CidrIp" : {"Fn::Select" : ["0", { "Ref": "PeerConnectionTargetCIDRs" }]} }, { "IpProtocol" : "-1", "FromPort" : "80", "ToPort" : "80", "CidrIp" : {"Fn::Select" : ["1", { "Ref": "PeerConnectionTargetCIDRs" }]} } ] } }, "ILBSecurityGroup3fwaz" : { "Type" : "AWS::EC2::SecurityGroup", "Condition" : "FwAz3", "Properties" : { "GroupDescription" : "Internal Load Balancer Security Group with HTTP access on port 80 from for firewall template with 3 Az", "VpcId" : { "Ref" : "VPCID" }, "Tags": [ { "Key": "Name", "Value": { "Fn::Join": [ "-", [ { "Ref": "AWS::StackName" }, "ILBSecurityGroup3fwaz" ] ] } } ], "SecurityGroupIngress" : [ { "IpProtocol" : "-1", "FromPort" : "80", "ToPort" : "80", "CidrIp" : {"Fn::Select" : ["0", { "Ref": "PeerConnectionTargetCIDRs" }]} }, { "IpProtocol" : "-1", "FromPort" : "80", "ToPort" : "80", "CidrIp" : {"Fn::Select" : ["1", { "Ref": "PeerConnectionTargetCIDRs" }]} }, { "IpProtocol" : "-1", "FromPort" : "80", "ToPort" : "80", "CidrIp" : {"Fn::Select" : ["2", { "Ref": "PeerConnectionTargetCIDRs" }]} } ] } }, "ILBSecurityGroup4fwaz" : { "Type" : "AWS::EC2::SecurityGroup", "Condition" : "FwAz4", "Properties" : { "GroupDescription" : "Internal Load Balancer Security Group with HTTP access on port 80 from for firewall template with 4 Az", "VpcId" : { "Ref" : "VPCID" }, "Tags": [ { "Key": "Name", "Value": { "Fn::Join": [ "-", [ { "Ref": "AWS::StackName" }, "ILBSecurityGroup4fwaz" ] ] } } ], "SecurityGroupIngress" : [ { "IpProtocol" : "-1", "FromPort" : "80", "ToPort" : "80", "CidrIp" : {"Fn::Select" : ["0", { "Ref": "PeerConnectionTargetCIDRs" }]} }, { "IpProtocol" : "-1", "FromPort" : "80", "ToPort" : "80", "CidrIp" : {"Fn::Select" : ["1", { "Ref": "PeerConnectionTargetCIDRs" }]} }, { "IpProtocol" : "-1", "FromPort" : "80", "ToPort" : "80", "CidrIp" : {"Fn::Select" : ["2", { "Ref": "PeerConnectionTargetCIDRs" }]} }, { "IpProtocol" : "-1", "FromPort" : "80", "ToPort" : "80", "CidrIp" : {"Fn::Select" : ["3", { "Ref": "PeerConnectionTargetCIDRs" }]} } ] } }, "InternalLoadBalancer" : { "Type" : "AWS::ElasticLoadBalancingV2::LoadBalancer", "Properties" : { "Name" : { "Ref" : "ILBName" }, "Subnets" : { "Fn::If" : [ "CreateSubnet2", [ { "Fn::Select" : [ "0", {"Ref" : "ILBSubnets"} ] }, { "Fn::Select" : [ "1", {"Ref" : "ILBSubnets"} ] } ], {"Fn::If" : ["CreateSubnet3", [ { "Fn::Select" : [ "0", {"Ref" : "ILBSubnets"} ] }, { "Fn::Select" : [ "1", {"Ref" : "ILBSubnets"} ] }, { "Fn::Select" : [ "2", {"Ref" : "ILBSubnets"} ] } ], [ { "Fn::Select" : [ "0", {"Ref" : "ILBSubnets"} ] }, { "Fn::Select" : [ "1", {"Ref" : "ILBSubnets"} ] }, { "Fn::Select" : [ "2", {"Ref" : "ILBSubnets"} ] }, { "Fn::Select" : [ "3", {"Ref" : "ILBSubnets"} ] } ] ] } ] }, "Scheme" : "internal", "Type": {"Fn::FindInMap" : ["Constants", "ILB", "Type"]}, "SecurityGroups": [{ "Fn::If" : [ "FwAz2", {"Ref": "ILBSecurityGroup2fwaz"}, {"Fn::If" : ["FwAz3", {"Ref": "ILBSecurityGroup3fwaz"}, {"Ref": "ILBSecurityGroup4fwaz"} ] } ] }] }, }, "WebServerTargetGroup": { "Type" : "AWS::ElasticLoadBalancingV2::TargetGroup", "Properties" : { "Port" : "80", "Protocol" : "HTTP", "UnhealthyThresholdCount" : "3", "VpcId" : { "Ref" : "VPCID" } } }, "WebServerListener": { "Type" : "AWS::ElasticLoadBalancingV2::Listener", "Properties" : { "DefaultActions" : [{ "Type": "forward", "TargetGroupArn": { "Ref": "WebServerTargetGroup" } }], "LoadBalancerArn" : {"Ref" : "InternalLoadBalancer"}, "Port" : "80", "Protocol" : "HTTP" }, "DependsOn": ["WebServerTargetGroup", "InternalLoadBalancer"] }, "LambdaExecutionRole0" : { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }, "Path":"/", "Policies": [ { "PolicyName": "LambdaExecutionRolePolicy", "PolicyDocument":{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["sts:AssumeRole"], "Resource": ["*"] }, { "Effect": "Allow", "Action": "s3:ListBucket", "Resource": { "Fn::Join": [ "", [ "arn:aws:s3:::", {"Ref": "S3BucketName" }, "/*" ] ] } }, { "Effect": "Allow", "Action": "s3:GetObject", "Resource": { "Fn::Join": [ "", [ "arn:aws:s3:::", { "Ref": "S3BucketName" }, "/*" ] ] } }, { "Effect": "Allow", "Action": [ "ec2:DescribeSubnets", "ec2:CreateRoute", "ec2:DeleteRoute", "ec2:DescribeVpcs" ], "Resource": [ "*" ] }, { "Effect": "Allow", "Action": [ "events:*" ], "Resource": [ "*" ] }, { "Effect": "Allow", "Action": [ "cloudwatch:*" ], "Resource": [ "*" ] }, { "Effect": "Allow", "Action": [ "lambda:AddPermission", "lambda:CreateEventSourceMapping", "lambda:CreateFunction", "lambda:DeleteEventSourceMapping", "lambda:DeleteFunction", "lambda:GetEventSourceMapping", "lambda:ListEventSourceMappings", "lambda:RemovePermission", "lambda:UpdateEventSourceMapping", "lambda:UpdateFunctionCode", "lambda:UpdateFunctionConfiguration", "lambda:GetFunction", "lambda:ListFunctions" ], "Resource": [ "*" ] }, { "Effect": "Allow", "Action": [ "sqs:ReceiveMessage", "sqs:SendMessage", "sqs:SetQueueAttributes", "sqs:PurgeQueue" ], "Resource": [ "*" ] }, { "Effect": "Allow", "Action": [ "elasticloadbalancing:AddTags", "elasticloadbalancing:AttachLoadBalancerToSubnets", "elasticloadbalancing:ConfigureHealthCheck", "elasticloadbalancing:DescribeInstanceHealth", "elasticloadbalancing:DescribeLoadBalancerAttributes", "elasticloadbalancing:DescribeLoadBalancerPolicyTypes", "elasticloadbalancing:DescribeLoadBalancerPolicies", "elasticloadbalancing:DescribeLoadBalancers", "elasticloadbalancing:DescribeTags", "elasticloadbalancing:DetachLoadBalancerFromSubnets", "elasticloadbalancing:ModifyLoadBalancerAttributes", "elasticloadbalancing:RemoveTags" ], "Resource": [ "*" ] }, { "Effect": "Allow", "Action": [ "iam:PassRole", "iam:GetRole" ], "Resource": [ "*" ] }, { "Effect": "Allow", "Action": ["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"], "Resource": "arn:aws:logs:*:*:*" }, { "Effect": "Allow", "Action": ["cloudformation:DescribeStacks"], "Resource": "*" }, { "Effect": "Allow", "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutDestination", "logs:PutDestinationPolicy", "logs:PutLogEvents", "logs:PutMetricFilter" ], "Resource": [ "*" ] }, { "Effect": "Allow", "Action": [ "dynamodb:CreateTable", "dynamodb:DeleteItem", "dynamodb:DeleteTable", "dynamodb:GetItem", "dynamodb:PutItem" ], "Resource": [ "*" ] } ] }}]} }, "ILBDeployerLambda0" : { "Type": "AWS::Lambda::Function", "Properties": { "Handler": "ilb_deployer.ilb_deploy_handler", "Role": {"Fn::GetAtt" : ["LambdaExecutionRole0", "Arn" ] }, "Code": { "S3Bucket": { "Ref": "S3BucketName"}, "S3Key": { "Ref": "LambdaZipFileName"} }, "Runtime": "python2.7", "Timeout": "300" }, "DependsOn": ["InternalLoadBalancer"] }, "LambdaCustomResource0": { "Type": "AWS::CloudFormation::CustomResource", "Version" : "1.0", "DependsOn": ["ILBDeployerLambda0"], "Properties" : { "ServiceToken": { "Fn::GetAtt" : ["ILBDeployerLambda0", "Arn"] }, "StackName": {"Ref": "AWS::StackName"}, "Region": {"Ref": "AWS::Region"}, "ILB-TYPE": {"Fn::FindInMap" : ["Constants", "ILB", "Type"]}, "ILB-ARN": {"Ref": "InternalLoadBalancer"}, "ILB-NAME": {"Ref": "ILBName"}, "ILB-DNS": {"Fn::GetAtt" : ["InternalLoadBalancer", "DNSName"]}, "ILBRouteTable": {"Fn::FindInMap" : ["Constants", "ILBRouteTable", "id"]}, "PeerConnectionTargetCIDRs": {"Ref": "PeerConnectionTargetCIDRs"}, "NumberOfFWAZs": {"Ref": "NumberOfFWAZs"}, "NumberOfAZs": {"Ref": "NumberOfAZs"}, "VpcAzs": {"Ref": "VpcAzs"}, "VPCSubnetCIDRs": {"Ref": "VPCSubnetCIDRs"}, "LambdaExecutionRole": {"Ref": "LambdaExecutionRole0"}, "CrossAccountRoleARN": {"Ref": "CrossAccountRole"}, "S3BucketName": {"Ref": "S3BucketName"}, "S3ObjectName": {"Ref": "LambdaZipFileName"}, "QueueURL": {"Ref": "QueueURL"} } } } }