You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
We need to write a CloudFormation template that represents our Environment Infrastructure:
This should mostly be parametrized as much as possible. We'll focus on Fargate first, but in the future we'll add additional parameters to work with EC2 providers.
We'll also need to include 2 additional roles. One for CodePipelines and one for CLI management to use. These two roles have not been defined yet, so it's ok to get started without them, we can update them later.
The ALB should be optional (specified via a parameter).
A rough starting point would be:
AWSTemplateFormatVersion: '2010-09-09'Description: This stack deploys a Fargate cluster that is in a VPC with bothpublic and private subnets. Containers can be deployed into eitherthe public subnets or the private subnets, and there are two loadbalancers. One is inside the public subnet, which can be used tosend traffic to the containers in the private subnet, and one inthe private subnet, which can be used for private internal trafficbetween internal services.Parameters:
ClusterName:
Type: StringMappings:
# Hard values for the subnet masks. These masks define# the range of internal IP addresses that can be assigned.# The VPC can have all IP's from 10.0.0.0 to 10.0.255.255# There are four subnets which cover the ranges:## 10.0.0.0 - 10.0.0.255# 10.0.1.0 - 10.0.1.255# 10.0.2.0 - 10.0.2.255# 10.0.3.0 - 10.0.3.255## If you need more IP addresses (perhaps you have so many# instances that you run out) then you can customize these# ranges to add moreSubnetConfig:
VPC:
CIDR: '10.0.0.0/16'PublicOne:
CIDR: '10.0.0.0/24'PublicTwo:
CIDR: '10.0.1.0/24'PrivateOne:
CIDR: '10.0.2.0/24'PrivateTwo:
CIDR: '10.0.3.0/24'Resources:
# VPC in which containers will be networked.# It has two public subnets, and two private subnets.# We distribute the subnets across the first two available subnets# for the region, for high availability.VPC:
Type: AWS::EC2::VPCProperties:
EnableDnsSupport: trueEnableDnsHostnames: trueCidrBlock: !FindInMap ['SubnetConfig', 'VPC', 'CIDR']Tags:
- Key: ecs-cli-projectValue: !Ref ClusterName# Two public subnets, where containers can have public IP addressesPublicSubnetOne:
Type: AWS::EC2::SubnetProperties:
AvailabilityZone:
Fn::Select:
- 0
- Fn::GetAZs: {Ref: 'AWS::Region'}VpcId: !Ref 'VPC'CidrBlock: !FindInMap ['SubnetConfig', 'PublicOne', 'CIDR']MapPublicIpOnLaunch: truePublicSubnetTwo:
Type: AWS::EC2::SubnetProperties:
AvailabilityZone:
Fn::Select:
- 1
- Fn::GetAZs: {Ref: 'AWS::Region'}VpcId: !Ref 'VPC'CidrBlock: !FindInMap ['SubnetConfig', 'PublicTwo', 'CIDR']MapPublicIpOnLaunch: true# Two private subnets where containers will only have private# IP addresses, and will only be reachable by other members of the# VPCPrivateSubnetOne:
Type: AWS::EC2::SubnetProperties:
AvailabilityZone:
Fn::Select:
- 0
- Fn::GetAZs: {Ref: 'AWS::Region'}VpcId: !Ref 'VPC'CidrBlock: !FindInMap ['SubnetConfig', 'PrivateOne', 'CIDR']PrivateSubnetTwo:
Type: AWS::EC2::SubnetProperties:
AvailabilityZone:
Fn::Select:
- 1
- Fn::GetAZs: {Ref: 'AWS::Region'}VpcId: !Ref 'VPC'CidrBlock: !FindInMap ['SubnetConfig', 'PrivateTwo', 'CIDR']# Setup networking resources for the public subnets. Containers# in the public subnets have public IP addresses and the routing table# sends network traffic via the internet gateway.InternetGateway:
Type: AWS::EC2::InternetGatewayGatewayAttachement:
Type: AWS::EC2::VPCGatewayAttachmentProperties:
VpcId: !Ref 'VPC'InternetGatewayId: !Ref 'InternetGateway'PublicRouteTable:
Type: AWS::EC2::RouteTableProperties:
VpcId: !Ref 'VPC'PublicRoute:
Type: AWS::EC2::RouteDependsOn: GatewayAttachementProperties:
RouteTableId: !Ref 'PublicRouteTable'DestinationCidrBlock: '0.0.0.0/0'GatewayId: !Ref 'InternetGateway'PublicSubnetOneRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociationProperties:
SubnetId: !Ref PublicSubnetOneRouteTableId: !Ref PublicRouteTablePublicSubnetTwoRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociationProperties:
SubnetId: !Ref PublicSubnetTwoRouteTableId: !Ref PublicRouteTable# Setup networking resources for the private subnets. Containers# in these subnets have only private IP addresses, and must use a NAT# gateway to talk to the internet. We launch two NAT gateways, one for# each private subnet.NatGatewayOneAttachment:
Type: AWS::EC2::EIPDependsOn: GatewayAttachementProperties:
Domain: vpcNatGatewayTwoAttachment:
Type: AWS::EC2::EIPDependsOn: GatewayAttachementProperties:
Domain: vpcNatGatewayOne:
Type: AWS::EC2::NatGatewayProperties:
AllocationId: !GetAtt NatGatewayOneAttachment.AllocationIdSubnetId: !Ref PublicSubnetOneNatGatewayTwo:
Type: AWS::EC2::NatGatewayProperties:
AllocationId: !GetAtt NatGatewayTwoAttachment.AllocationIdSubnetId: !Ref PublicSubnetTwoPrivateRouteTableOne:
Type: AWS::EC2::RouteTableProperties:
VpcId: !Ref 'VPC'PrivateRouteOne:
Type: AWS::EC2::RouteProperties:
RouteTableId: !Ref PrivateRouteTableOneDestinationCidrBlock: 0.0.0.0/0NatGatewayId: !Ref NatGatewayOnePrivateRouteTableOneAssociation:
Type: AWS::EC2::SubnetRouteTableAssociationProperties:
RouteTableId: !Ref PrivateRouteTableOneSubnetId: !Ref PrivateSubnetOnePrivateRouteTableTwo:
Type: AWS::EC2::RouteTableProperties:
VpcId: !Ref 'VPC'PrivateRouteTwo:
Type: AWS::EC2::RouteProperties:
RouteTableId: !Ref PrivateRouteTableTwoDestinationCidrBlock: 0.0.0.0/0NatGatewayId: !Ref NatGatewayTwoPrivateRouteTableTwoAssociation:
Type: AWS::EC2::SubnetRouteTableAssociationProperties:
RouteTableId: !Ref PrivateRouteTableTwoSubnetId: !Ref PrivateSubnetTwo# OPTIONAL: VPC Endpoint for DynamoDB# If a container needs to access DynamoDB this allows a container in the private subnet# to talk to DynamoDB directly without needing to go via the NAT gateway. This reduces# the amount of bandwidth through the gateway, meaning that the gateway is free to serve# your other traffic.DynamoDBEndpoint:
Type: AWS::EC2::VPCEndpointProperties:
PolicyDocument:
Version: "2012-10-17"Statement:
- Effect: AllowAction: "*"Principal: "*"Resource: "*"RouteTableIds:
- !Ref'PrivateRouteTableOne'
- !Ref'PrivateRouteTableTwo'ServiceName: !Join [ "", [ "com.amazonaws.", { "Ref": "AWS::Region" }, ".dynamodb" ] ]VpcId: !Ref 'VPC'# ECS ResourcesECSCluster:
Type: AWS::ECS::ClusterProperties:
ClusterName: !Ref ClusterName# A security group for the containers we will run in Fargate.# Three rules, allowing network traffic from a public facing load# balancer, a private internal load balancer, and from other members# of the security group.## Remove any of the following ingress rules that are not needed.FargateContainerSecurityGroup:
Type: AWS::EC2::SecurityGroupProperties:
GroupDescription: Access to the Fargate containersVpcId: !Ref 'VPC'EcsSecurityGroupIngressFromPublicALB:
Type: AWS::EC2::SecurityGroupIngressProperties:
Description: Ingress from the public ALBGroupId: !Ref 'FargateContainerSecurityGroup'IpProtocol: -1SourceSecurityGroupId: !Ref 'PublicLoadBalancerSG'EcsSecurityGroupIngressFromPrivateALB:
Type: AWS::EC2::SecurityGroupIngressProperties:
Description: Ingress from the private ALBGroupId: !Ref 'FargateContainerSecurityGroup'IpProtocol: -1SourceSecurityGroupId: !Ref 'PrivateLoadBalancerSG'EcsSecurityGroupIngressFromSelf:
Type: AWS::EC2::SecurityGroupIngressProperties:
Description: Ingress from other containers in the same security groupGroupId: !Ref 'FargateContainerSecurityGroup'IpProtocol: -1SourceSecurityGroupId: !Ref 'FargateContainerSecurityGroup'# Load balancers for getting traffic to containers.# This sample template creates two load balancers:## - One public load balancer, hosted in public subnets that is accessible# to the public, and is intended to route traffic to one or more public# facing services.# - One private load balancer, hosted in private subnets, that only# accepts traffic from other containers in the Fargate cluster, and is# intended for private services that should not be accessed directly# by the public.# A public facing load balancer, this is used for accepting traffic from the public# internet and directing it to public facing microservicesPublicLoadBalancerSG:
Type: AWS::EC2::SecurityGroupProperties:
GroupDescription: Access to the public facing load balancerVpcId: !Ref 'VPC'SecurityGroupIngress:
# Allow access to ALB from anywhere on the internet
- CidrIp: 0.0.0.0/0IpProtocol: -1PublicLoadBalancer:
Type: AWS::ElasticLoadBalancingV2::LoadBalancerDependsOn: GatewayAttachementProperties:
Scheme: internet-facingLoadBalancerAttributes:
- Key: idle_timeout.timeout_secondsValue: '30'Subnets:
# The load balancer is placed into the public subnets, so that traffic# from the internet can reach the load balancer directly via the internet gateway
- !RefPublicSubnetOne
- !RefPublicSubnetTwoSecurityGroups: [!Ref 'PublicLoadBalancerSG']# A dummy target group is used to setup the ALB to just drop traffic# initially, before any real service target groups have been added.DummyTargetGroupPublic:
Type: AWS::ElasticLoadBalancingV2::TargetGroupProperties:
HealthCheckIntervalSeconds: 6HealthCheckPath: /HealthCheckProtocol: HTTPHealthCheckTimeoutSeconds: 5HealthyThresholdCount: 2Name: !Join ['-', [!Ref 'AWS::StackName', 'drop-1']]Port: 80Protocol: HTTPUnhealthyThresholdCount: 2VpcId: !Ref 'VPC'PublicLoadBalancerListener:
Type: AWS::ElasticLoadBalancingV2::ListenerDependsOn:
- PublicLoadBalancerProperties:
DefaultActions:
- TargetGroupArn: !Ref 'DummyTargetGroupPublic'Type: 'forward'LoadBalancerArn: !Ref 'PublicLoadBalancer'Port: 80Protocol: HTTP# An internal load balancer, this would be used for a service that is not# directly accessible to the public, but instead should only receive traffic# from your other services.PrivateLoadBalancerSG:
Type: AWS::EC2::SecurityGroupProperties:
GroupDescription: Access to the internal load balancerVpcId: !Ref 'VPC'PrivateLoadBalancerIngressFromECS:
Type: AWS::EC2::SecurityGroupIngressProperties:
Description: Only accept traffic from a container in the fargate container security groupGroupId: !Ref 'PrivateLoadBalancerSG'IpProtocol: -1SourceSecurityGroupId: !Ref 'FargateContainerSecurityGroup'PrivateLoadBalancer:
Type: AWS::ElasticLoadBalancingV2::LoadBalancerProperties:
Scheme: internalLoadBalancerAttributes:
- Key: idle_timeout.timeout_secondsValue: '30'Subnets:
# This load balancer is put into the private subnet, so that there is no# route for the public to even be able to access the private load balancer.
- !RefPrivateSubnetOne
- !RefPrivateSubnetTwoSecurityGroups: [!Ref 'PrivateLoadBalancerSG']# This dummy target group is used to setup the ALB to just drop traffic# initially, before any real service target groups have been added.DummyTargetGroupPrivate:
Type: AWS::ElasticLoadBalancingV2::TargetGroupProperties:
HealthCheckIntervalSeconds: 6HealthCheckPath: /HealthCheckProtocol: HTTPHealthCheckTimeoutSeconds: 5HealthyThresholdCount: 2Name: !Join ['-', [!Ref 'AWS::StackName', 'drop-2']]Port: 80Protocol: HTTPUnhealthyThresholdCount: 2VpcId: !Ref 'VPC'PrivateLoadBalancerListener:
Type: AWS::ElasticLoadBalancingV2::ListenerDependsOn:
- PrivateLoadBalancerProperties:
DefaultActions:
- TargetGroupArn: !Ref 'DummyTargetGroupPrivate'Type: 'forward'LoadBalancerArn: !Ref 'PrivateLoadBalancer'Port: 80Protocol: HTTP# This is an IAM role which authorizes ECS to manage resources on your# account on your behalf, such as updating your load balancer with the# details of where your containers are, so that traffic can reach your# containers.ECSRole:
Type: AWS::IAM::RoleProperties:
AssumeRolePolicyDocument:
Statement:
- Effect: AllowPrincipal:
Service: [ecs.amazonaws.com]Action: ['sts:AssumeRole']Path: /Policies:
- PolicyName: ecs-servicePolicyDocument:
Statement:
- Effect: AllowAction:
# Rules which allow ECS to attach network interfaces to instances# on your behalf in order for awsvpc networking mode to work right
- 'ec2:AttachNetworkInterface'
- 'ec2:CreateNetworkInterface'
- 'ec2:CreateNetworkInterfacePermission'
- 'ec2:DeleteNetworkInterface'
- 'ec2:DeleteNetworkInterfacePermission'
- 'ec2:Describe*'
- 'ec2:DetachNetworkInterface'# Rules which allow ECS to update load balancers on your behalf# with the information sabout how to send traffic to your containers
- 'elasticloadbalancing:DeregisterInstancesFromLoadBalancer'
- 'elasticloadbalancing:DeregisterTargets'
- 'elasticloadbalancing:Describe*'
- 'elasticloadbalancing:RegisterInstancesWithLoadBalancer'
- 'elasticloadbalancing:RegisterTargets'Resource: '*'# This is a role which is used by the ECS tasks themselves.ECSTaskExecutionRole:
Type: AWS::IAM::RoleProperties:
AssumeRolePolicyDocument:
Statement:
- Effect: AllowPrincipal:
Service: [ecs-tasks.amazonaws.com]Action: ['sts:AssumeRole']Path: /Policies:
- PolicyName: AmazonECSTaskExecutionRolePolicyPolicyDocument:
Statement:
- Effect: AllowAction:
# Allow the ECS Tasks to download images from ECR
- 'ecr:GetAuthorizationToken'
- 'ecr:BatchCheckLayerAvailability'
- 'ecr:GetDownloadUrlForLayer'
- 'ecr:BatchGetImage'# Allow the ECS tasks to upload logs to CloudWatch
- 'logs:CreateLogStream'
- 'logs:PutLogEvents'Resource: '*'# These are the values output by the CloudFormation template. Be careful# about changing any of them, because of them are exported with specific# names so that the other task related CF templates can use them.Outputs:
ClusterName:
Description: The name of the ECS clusterValue: !Ref 'ECSCluster'Export:
Name: !Join [ ':', [ !Ref 'AWS::StackName', 'ClusterName' ] ]InternalUrl:
Description: The url of the internal load balancerValue: !Join ['', ['http://', !GetAtt 'PrivateLoadBalancer.DNSName']]Export:
Name: !Join [ ':', [ !Ref 'AWS::StackName', 'InternalUrl' ] ]ExternalUrl:
Description: The url of the external load balancerValue: !Join ['', ['http://', !GetAtt 'PublicLoadBalancer.DNSName']]Export:
Name: !Join [ ':', [ !Ref 'AWS::StackName', 'ExternalUrl' ] ]ECSRole:
Description: The ARN of the ECS roleValue: !GetAtt 'ECSRole.Arn'Export:
Name: !Join [ ':', [ !Ref 'AWS::StackName', 'ECSRole' ] ]ECSTaskExecutionRole:
Description: The ARN of the ECS roleValue: !GetAtt 'ECSTaskExecutionRole.Arn'Export:
Name: !Join [ ':', [ !Ref 'AWS::StackName', 'ECSTaskExecutionRole' ] ]PublicListener:
Description: The ARN of the public load balancer's ListenerValue: !Ref PublicLoadBalancerListenerExport:
Name: !Join [ ':', [ !Ref 'AWS::StackName', 'PublicListener' ] ]PrivateListener:
Description: The ARN of the private load balancer's ListenerValue: !Ref PrivateLoadBalancerListenerExport:
Name: !Join [ ':', [ !Ref 'AWS::StackName', 'PrivateListener' ] ]VPCId:
Description: The ID of the VPC that this stack is deployed inValue: !Ref 'VPC'Export:
Name: !Join [ ':', [ !Ref 'AWS::StackName', 'VPCId' ] ]PublicSubnetOne:
Description: Public subnet oneValue: !Ref 'PublicSubnetOne'Export:
Name: !Join [ ':', [ !Ref 'AWS::StackName', 'PublicSubnetOne' ] ]PublicSubnetTwo:
Description: Public subnet twoValue: !Ref 'PublicSubnetTwo'Export:
Name: !Join [ ':', [ !Ref 'AWS::StackName', 'PublicSubnetTwo' ] ]PrivateSubnetOne:
Description: Private subnet oneValue: !Ref 'PrivateSubnetOne'Export:
Name: !Join [ ':', [ !Ref 'AWS::StackName', 'PrivateSubnetOne' ] ]PrivateSubnetTwo:
Description: Private subnet twoValue: !Ref 'PrivateSubnetTwo'Export:
Name: !Join [ ':', [ !Ref 'AWS::StackName', 'PrivateSubnetTwo' ] ]FargateContainerSecurityGroup:
Description: A security group used to allow Fargate containers to receive trafficValue: !Ref 'FargateContainerSecurityGroup'Export:
Name: !Join [ ':', [ !Ref 'AWS::StackName', 'FargateContainerSecurityGroup' ] ]
The text was updated successfully, but these errors were encountered:
We need to write a CloudFormation template that represents our Environment Infrastructure:
This should mostly be parametrized as much as possible. We'll focus on Fargate first, but in the future we'll add additional parameters to work with EC2 providers.
We'll also need to include 2 additional roles. One for CodePipelines and one for CLI management to use. These two roles have not been defined yet, so it's ok to get started without them, we can update them later.
The ALB should be optional (specified via a parameter).
A rough starting point would be:
The text was updated successfully, but these errors were encountered: