-
-
Save Femi-lawal/1a542fc3f3f782db615d2bb028e49cc6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
AWSTemplateFormatVersion: "2010-09-09" | |
Description: > | |
This template creates ECS Fargate Services. | |
############################################################ | |
# PARAMETERS RECORDS BLOCK | |
############################################################ | |
Parameters: | |
ImageTag: | |
Type: String | |
Default: latest | |
ServiceName: | |
Type: String | |
Default: rest-api | |
ContainerPort: | |
Type: Number | |
Default: 80 | |
ContainerCpu: | |
Type: String | |
Default: 256 | |
ContainerMemory: | |
Type: String | |
Default: 1GB | |
HealthCheckPath: | |
Type: String | |
Default: / | |
MinContainers: | |
Type: Number | |
Default: 1 | |
VpcCIDR: | |
Description: "IP range for this VPC" | |
Type: "String" | |
Default: "10.0.0.0/16" | |
PublicSubnetOneCIDR: | |
Description: "IP range for the public subnet in the first Availability Zone" | |
Type: "String" | |
Default: "10.0.1.0/24" | |
PublicSubnetTwoCIDR: | |
Description: "IP range for the public subnet in the second Availability Zone" | |
Type: "String" | |
Default: "10.0.2.0/24" | |
Resources: | |
############################################################ | |
# VPC & PUBLIC SUBNETS | |
############################################################ | |
RestVPC: | |
Type: "AWS::EC2::VPC" | |
Properties: | |
CidrBlock: !Ref "VpcCIDR" | |
Tags: | |
- Key: "Name" | |
Value: "Rest-API-VPC" | |
####### Create Public Subnet ####### | |
PublicSubnetOne: | |
Type: "AWS::EC2::Subnet" | |
Properties: | |
VpcId: !Ref RestVPC | |
CidrBlock: !Ref "PublicSubnetOneCIDR" | |
AvailabilityZone: !Select ["0", !GetAZs ] | |
MapPublicIpOnLaunch: "True" | |
Tags: | |
- Key: "Name" | |
Value: !Sub "${PublicSubnetOneCIDR}-PublicSubnetOne" | |
PublicSubnetTwo: | |
Type: "AWS::EC2::Subnet" | |
Properties: | |
VpcId: !Ref RestVPC | |
CidrBlock: !Ref "PublicSubnetTwoCIDR" | |
AvailabilityZone: !Select ["1", !GetAZs ] | |
MapPublicIpOnLaunch: "True" | |
Tags: | |
- Key: "Name" | |
Value: !Sub "${PublicSubnetTwoCIDR}-PublicSubnetTwo" | |
######## Create Public Route Table ####### | |
PublicRouteTable1: | |
Type: "AWS::EC2::RouteTable" | |
Properties: | |
VpcId: !Ref RestVPC | |
Tags: | |
- Key: "Name" | |
Value: "PublicRoute1" | |
PublicRouteTable2: | |
Type: "AWS::EC2::RouteTable" | |
Properties: | |
VpcId: !Ref RestVPC | |
Tags: | |
- Key: "Name" | |
Value: "PublicRoute2" | |
######## Create Internet Gateway ####### | |
InternetGateway: | |
Type: "AWS::EC2::InternetGateway" | |
Properties: | |
Tags: | |
- Key: "Name" | |
Value: "InternetGateway" | |
######## Attach Internet Gateway to VPC ####### | |
GatewayToInternet: | |
Type: "AWS::EC2::VPCGatewayAttachment" | |
Properties: | |
VpcId: !Ref RestVPC | |
InternetGatewayId: !Ref "InternetGateway" | |
######## Route-out Public Route Table to Internet Gateway (Internet connection) ####### | |
PublicRouteIGW1: | |
Type: "AWS::EC2::Route" | |
DependsOn: "GatewayToInternet" | |
Properties: | |
RouteTableId: !Ref "PublicRouteTable1" | |
DestinationCidrBlock: "0.0.0.0/0" | |
GatewayId: !Ref "InternetGateway" | |
PublicRouteIGW2: | |
Type: "AWS::EC2::Route" | |
DependsOn: "GatewayToInternet" | |
Properties: | |
RouteTableId: !Ref "PublicRouteTable2" | |
DestinationCidrBlock: "0.0.0.0/0" | |
GatewayId: !Ref "InternetGateway" | |
######## Associate Public Route Table with Public Subnet1 & Subnet2 ####### | |
PublicSubnetOneRouteTableAssociation: | |
Type: "AWS::EC2::SubnetRouteTableAssociation" | |
Properties: | |
SubnetId: !Ref "PublicSubnetOne" | |
RouteTableId: !Ref "PublicRouteTable1" | |
PublicSubnetTwoRouteTableAssociation: | |
Type: "AWS::EC2::SubnetRouteTableAssociation" | |
Properties: | |
SubnetId: !Ref "PublicSubnetTwo" | |
RouteTableId: !Ref "PublicRouteTable2" | |
######## Create Custom Network ACL ####### | |
PublicNetworkACL: | |
Type: "AWS::EC2::NetworkAcl" | |
Properties: | |
VpcId: !Ref RestVPC | |
Tags: | |
- Key: "Name" | |
Value: "PublicNetworkACL" | |
PublicInboundPublicACL: | |
Type: "AWS::EC2::NetworkAclEntry" | |
Properties: | |
NetworkAclId: !Ref PublicNetworkACL | |
RuleNumber: "100" | |
Protocol: "-1" | |
RuleAction: "allow" | |
Egress: "false" | |
CidrBlock: "0.0.0.0/0" | |
PublicOutboundPublicACL: | |
Type: "AWS::EC2::NetworkAclEntry" | |
Properties: | |
NetworkAclId: !Ref PublicNetworkACL | |
RuleNumber: "100" | |
Protocol: "-1" | |
RuleAction: "allow" | |
Egress: "true" | |
CidrBlock: "0.0.0.0/0" | |
######## Associate Public Subnet to Network ACL ####### | |
PublicSubnetOneNetworkAclAssociation: | |
Type: "AWS::EC2::SubnetNetworkAclAssociation" | |
Properties: | |
SubnetId: !Ref "PublicSubnetOne" | |
NetworkAclId: !Ref "PublicNetworkACL" | |
PublicSubnetTwoNetworkAclAssociation: | |
Type: "AWS::EC2::SubnetNetworkAclAssociation" | |
Properties: | |
SubnetId: !Ref "PublicSubnetTwo" | |
NetworkAclId: !Ref "PublicNetworkACL" | |
############################################################ | |
# ECS CLUSTER BLOCK | |
############################################################ | |
Cluster: | |
Type: AWS::ECS::Cluster | |
Properties: | |
ClusterName: !Join ["-", [!Ref ServiceName, cluster]] | |
############################################################ | |
# ECS TASK DEFINITION | |
############################################################ | |
TaskDefinition: | |
Type: AWS::ECS::TaskDefinition | |
DependsOn: LogGroup | |
Properties: | |
# Name of the task definition. Subsequent versions of the task definition are grouped together under this name. | |
Family: !Join ["-", [!Ref ServiceName, TaskDefinition]] | |
# awsvpc is required for Fargate | |
NetworkMode: awsvpc | |
RequiresCompatibilities: | |
- FARGATE | |
Cpu: !Ref ContainerCpu | |
Memory: !Ref ContainerMemory | |
ExecutionRoleArn: !Ref ExecutionRole | |
TaskRoleArn: !Ref TaskRole | |
ContainerDefinitions: | |
- Name: !Ref ServiceName | |
Image: | |
!Join [ | |
".", | |
[ | |
!Ref AWS::AccountId, | |
"dkr.ecr", | |
!Ref AWS::Region, | |
!Sub "amazonaws.com/ecr-repository:${ImageTag}", | |
], | |
] | |
PortMappings: | |
- ContainerPort: !Ref ContainerPort | |
# Send logs to CloudWatch Logs | |
LogConfiguration: | |
LogDriver: awslogs | |
Options: | |
awslogs-region: !Ref AWS::Region | |
awslogs-group: !Ref LogGroup | |
awslogs-stream-prefix: ecs | |
############################################################ | |
# IAM ROLE | |
############################################################ | |
ExecutionRole: | |
Type: AWS::IAM::Role | |
Properties: | |
RoleName: !Join ["-", [!Ref ServiceName, ExecutionRole]] | |
AssumeRolePolicyDocument: | |
Statement: | |
- Effect: Allow | |
Principal: | |
Service: ecs-tasks.amazonaws.com | |
Action: "sts:AssumeRole" | |
ManagedPolicyArns: | |
- "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy" | |
TaskRole: | |
Type: AWS::IAM::Role | |
Properties: | |
RoleName: !Join ["-", [!Ref ServiceName, TaskRole]] | |
AssumeRolePolicyDocument: | |
Statement: | |
- Effect: Allow | |
Principal: | |
Service: ecs-tasks.amazonaws.com | |
Action: "sts:AssumeRole" | |
Policies: | |
- PolicyName: "systems-manager" | |
PolicyDocument: | |
Version: "2012-10-17" | |
Statement: | |
- Effect: "Allow" | |
Action: | |
- "ssmmessages:CreateControlChannel" | |
- "ssmmessages:CreateDataChannel" | |
- "ssmmessages:OpenControlChannel" | |
- "ssmmessages:OpenDataChannel" | |
Resource: "*" | |
- Effect: "Allow" | |
Action: | |
- "kms:Decrypt" | |
Resource: !Sub "arn:aws:kms:us-east-1:${AWS::AccountId}:key/${KMSKey}" | |
############################################################ | |
# KMS KEY | |
############################################################ | |
KMSKey: | |
Type: AWS::KMS::Key | |
Properties: | |
Description: Key needed to encrypt docker exec data channel | |
KeyPolicy: | |
Version: "2012-10-17" | |
Statement: | |
- Effect: "Allow" | |
Principal: | |
AWS: !Sub "arn:aws:iam::${AWS::AccountId}:root" | |
Action: | |
- "kms:*" | |
Resource: "*" | |
############################################################ | |
# SECURITY GROUP | |
############################################################ | |
ContainerSecurityGroup: | |
Type: AWS::EC2::SecurityGroup | |
Properties: | |
GroupDescription: !Join ["-", [!Ref ServiceName, ContainerSecurityGroup]] | |
VpcId: !Ref RestVPC | |
SecurityGroupIngress: | |
- IpProtocol: tcp | |
FromPort: !Ref ContainerPort | |
ToPort: !Ref ContainerPort | |
SourceSecurityGroupId: !Ref LoadBalancerSecurityGroup | |
LoadBalancerSecurityGroup: | |
Type: AWS::EC2::SecurityGroup | |
Properties: | |
GroupDescription: | |
!Join ["-", [!Ref ServiceName, LoadBalancerSecurityGroup]] | |
VpcId: !Ref RestVPC | |
SecurityGroupIngress: | |
- IpProtocol: tcp | |
FromPort: 80 | |
ToPort: 80 | |
CidrIp: 0.0.0.0/0 | |
############################################################ | |
# ECS SERVICE | |
############################################################ | |
Service: | |
Type: AWS::ECS::Service | |
# This dependency is needed so that the load balancer is setup correctly in time | |
DependsOn: | |
- ApplicationLoadBalancer | |
- ALBHTTPListener | |
- ListenerRule | |
- TargetGroup | |
Properties: | |
ServiceName: !Ref ServiceName | |
Cluster: !Ref Cluster | |
TaskDefinition: !Ref TaskDefinition | |
EnableExecuteCommand: true | |
DeploymentConfiguration: | |
MinimumHealthyPercent: 100 | |
MaximumPercent: 200 | |
DesiredCount: !Ref MinContainers | |
HealthCheckGracePeriodSeconds: 300 | |
LaunchType: FARGATE | |
NetworkConfiguration: | |
AwsvpcConfiguration: | |
AssignPublicIp: ENABLED | |
Subnets: | |
- !Ref PublicSubnetOne | |
- !Ref PublicSubnetTwo | |
SecurityGroups: | |
- !Ref ContainerSecurityGroup | |
LoadBalancers: | |
- ContainerName: !Ref ServiceName | |
ContainerPort: !Ref ContainerPort | |
TargetGroupArn: !Ref TargetGroup | |
############################################################ | |
# ECS TARGET GROUP | |
############################################################ | |
TargetGroup: | |
Type: AWS::ElasticLoadBalancingV2::TargetGroup | |
Properties: | |
HealthCheckIntervalSeconds: 10 | |
HealthCheckPath: !Ref HealthCheckPath | |
HealthCheckTimeoutSeconds: 5 | |
UnhealthyThresholdCount: 2 | |
HealthyThresholdCount: 2 | |
Name: !Join ["-", [!Ref ServiceName, TargetGroup]] | |
Port: !Ref ContainerPort | |
Protocol: HTTP | |
TargetGroupAttributes: | |
- Key: deregistration_delay.timeout_seconds | |
Value: 60 | |
TargetType: ip | |
VpcId: !Ref RestVPC | |
Matcher: | |
HttpCode: 200 | |
############################################################ | |
# APPLICATION LOAD BALANCER | |
############################################################ | |
ApplicationLoadBalancer: | |
Type: AWS::ElasticLoadBalancingV2::LoadBalancer | |
Properties: | |
LoadBalancerAttributes: | |
- Key: idle_timeout.timeout_seconds | |
Value: 60 | |
Name: !Join ["-", [!Ref ServiceName, ApplicationLoadBalancer]] | |
Scheme: internet-facing | |
SecurityGroups: | |
- !Ref LoadBalancerSecurityGroup | |
Subnets: | |
- !Ref PublicSubnetOne | |
- !Ref PublicSubnetTwo | |
ALBHTTPListener: | |
Type: "AWS::ElasticLoadBalancingV2::Listener" | |
Properties: | |
LoadBalancerArn: !Ref ApplicationLoadBalancer | |
DefaultActions: | |
- FixedResponseConfig: | |
StatusCode: 200 | |
Type: fixed-response | |
Port: "80" | |
Protocol: HTTP | |
# ---- Applcation Load Balancer Listener Rule ---- # | |
ListenerRule: | |
Type: "AWS::ElasticLoadBalancingV2::ListenerRule" | |
Properties: | |
Actions: | |
- Type: forward | |
TargetGroupArn: !Ref TargetGroup | |
Conditions: | |
- Field: path-pattern | |
Values: | |
- "*" | |
ListenerArn: !Ref ALBHTTPListener | |
Priority: 1 | |
############################################################ | |
# CLOUDWATCH LOG GROUPS | |
############################################################ | |
LogGroup: | |
Type: AWS::Logs::LogGroup | |
Properties: | |
LogGroupName: !Join ["", [/ecs/, !Ref ServiceName, TaskDefinition]] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment