Last active
September 6, 2019 21:36
-
-
Save btotharye/d9de3ed45b17cc4ba87ea7d902b8ec65 to your computer and use it in GitHub Desktop.
ECS Fargate Setup with Multi Stack
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
#!/usr/bin/env python3 | |
from aws_cdk import core | |
from cdk.vpc_stack import VpcStack | |
from cdk.ecs_stack import EcsStack | |
app = core.App() | |
# Params and stage info | |
stage = app.node.try_get_context('stage') | |
props = app.node.try_get_context(stage) | |
service = app.node.try_get_context('serviceName') | |
app_id = app.node.try_get_context('appId') | |
cost_centre = app.node.try_get_context('costCentre') | |
dcl = app.node.try_get_context('dcl') | |
region = app.node.try_get_context(stage)['region'] | |
account = app.node.try_get_context(stage)['account'] | |
# Build out stack | |
VpcStack(app, "{0}-{1}".format(service, stage), props=props, env={'region': region, 'account': account}) | |
# Tagging | |
core.Tag.add(app, 't_environment', stage.upper()) | |
core.Tag.add(app, 't_AppID', app_id) | |
core.Tag.add(app, 't_cost_centre', cost_centre) | |
core.Tag.add(app, 't_dcl', dcl) | |
core.Tag.add(app, 'Application', service) | |
# Synth the CF template | |
app.synth() |
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
from aws_cdk import ( | |
aws_ec2 as ec2, | |
aws_ecs as ecs, | |
aws_ecr as ecr, | |
aws_iam as iam, | |
aws_logs as logs, | |
aws_elasticloadbalancingv2 as elbv2, | |
aws_route53 as route53, | |
aws_route53_targets, | |
core, | |
) | |
class EcsStack(core.Stack): | |
def __init__( | |
self, | |
scope: core.Construct, | |
id: str, | |
props, | |
vpc: ec2.Vpc, | |
execution_role: iam.Role, | |
task_role: iam.Role, | |
log_group: logs.LogGroup, | |
**kwargs) -> None: | |
super().__init__(scope, id, **kwargs) | |
vpn_connection = ec2.Peer.ipv4( | |
'0.0.0.0/16' | |
) | |
# Props Setup | |
stage = scope.node.try_get_context('stage') | |
my_service_name = scope.node.try_get_context('serviceName') | |
region = scope.node.try_get_context(stage)['region'] | |
account = scope.node.try_get_context(stage)['account'] | |
# Default Target Group | |
fargate_tg = elbv2.ApplicationTargetGroup( | |
self,'DefaultTargetGroup', | |
port=8443, | |
protocol=elbv2.ApplicationProtocol.HTTP, | |
vpc=vpc | |
) | |
# Setup Fargate Task Definition | |
fargate_taskdef = ecs.FargateTaskDefinition( | |
self,'ECSFargateTask', | |
memory_limit_mib=8192, | |
cpu=2048, | |
execution_role=execution_role, | |
task_role=task_role, | |
family="{0}-{1}-taskdef".format(my_service_name, stage) | |
) | |
api_repo = ecr.Repository.from_repository_arn( | |
self,'AppImage', | |
repository_arn="arn:aws:ecr:us-east-1:x:repository/x" | |
) | |
# Add Container Info to Task | |
ecs_container = fargate_taskdef.add_container( | |
"MyFargateTask", | |
image=ecs.EcrImage( | |
repository=api_repo, tag="latest" | |
), | |
logging=ecs.LogDriver.aws_logs( | |
stream_prefix="{0}-{1}-api".format(my_service_name, stage), | |
log_group=log_group | |
) | |
) | |
# Setup ECS Cluster | |
ecs_cluster = ecs.Cluster( | |
self, | |
'ECSCluster', | |
vpc=vpc, | |
cluster_name="{0}-{1}".format(my_service_name, stage) | |
) |
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
from aws_cdk import ( | |
aws_ec2 as ec2, | |
aws_ecs as ecs, | |
aws_ecr as ecr, | |
aws_iam as iam, | |
aws_logs as logs, | |
aws_elasticloadbalancingv2 as elbv2, | |
aws_route53 as route53, | |
aws_route53_targets, | |
core, | |
) | |
from .ecs_stack import EcsStack | |
class VpcStack(core.Stack): | |
def __init__(self, scope: core.Construct, id: str, props, **kwargs) -> None: | |
super().__init__(scope, id, **kwargs) | |
vpn_connection = ec2.Peer.ipv4( | |
'0.0.0.0/16' | |
) | |
# Props Setup | |
stage = scope.node.try_get_context('stage') | |
my_service_name = scope.node.try_get_context('serviceName') | |
region = scope.node.try_get_context(stage)['region'] | |
account = scope.node.try_get_context(stage)['account'] | |
# Setup IAM user for logs | |
vpc_flow_role = iam.Role( | |
self, 'FlowLog', | |
assumed_by=iam.ServicePrincipal('vpc-flow-logs.amazonaws.com') | |
) | |
# Create Cloudwatch log group | |
log_group = logs.LogGroup( | |
self, 'LogGroup', | |
log_group_name=my_service_name, | |
retention=logs.RetentionDays('ONE_YEAR'), | |
removal_policy=core.RemovalPolicy('DESTROY') | |
) | |
# Setup VPC resource | |
vpc = ec2.Vpc( | |
self, '{0}-{1}-vpc'.format(my_service_name, stage), | |
cidr=props['cidr'], | |
max_azs=props['vpcAzCount'] | |
) | |
# Setup VPC flow logs | |
vpc_log = ec2.CfnFlowLog( | |
self, 'FlowLogs', | |
resource_id=vpc.vpc_id, | |
resource_type='VPC', | |
traffic_type='ALL', | |
deliver_logs_permission_arn=vpc_flow_role.role_arn, | |
log_destination_type='cloud-watch-logs', | |
log_group_name=log_group.log_group_name | |
) | |
# Setup Security Group in VPC | |
vpc_sg = ec2.SecurityGroup( | |
self, | |
'EcSSG', | |
vpc=vpc, | |
allow_all_outbound=None, | |
description="Security Group for vpc", | |
security_group_name="{0}-{1}-vpc-sg".format(my_service_name, stage) | |
) | |
# Add Rules to Security Group | |
vpc_sg.add_ingress_rule( | |
peer=pearson_vpn_connection, | |
connection=ec2.Port.tcp(22) | |
) | |
# ALB Security Group | |
alb_sg = ec2.SecurityGroup( | |
self, | |
'AlbSG', | |
vpc=vpc, | |
allow_all_outbound=None, | |
description="Security group for ALB", | |
security_group_name="{0}-{1}-alb-sg".format(my_service_name,stage) | |
) | |
alb_sg.add_ingress_rule( | |
peer=vpn_connection, | |
connection=ec2.Port.tcp(443) | |
) | |
# Setup ALB | |
alb = elbv2.ApplicationLoadBalancer( | |
self,'ALB', | |
vpc=vpc, | |
internet_facing=True, | |
security_group=alb_sg | |
) | |
core.CfnOutput(self, | |
'VPCId', | |
value=vpc.vpc_id | |
) | |
# ECS Execution Role - Grants ECS agent to call AWS APIs | |
ecs_execution_role = iam.Role( | |
self, 'ECSExecutionRole', | |
assumed_by=iam.ServicePrincipal('ecs-tasks.amazonaws.com'), | |
role_name="{0}-{1}-execution-role".format(my_service_name, stage) | |
) | |
# Setup Role Permissions | |
ecs_execution_role.add_to_policy( | |
iam.PolicyStatement( | |
effect=iam.Effect.ALLOW, | |
actions=[ | |
'elasticloadbalancing:DeregisterInstancesFromLoadBalancer', | |
'elasticloadbalancing:DeregisterTargets', | |
'elasticloadbalancing:Describe*', | |
'elasticloadbalancing:RegisterInstancesWithLoadBalancer', | |
'elasticloadbalancing:RegisterTargets', | |
'ec2:Describe*', | |
'ec2:AuthorizeSecurityGroupIngress', | |
'sts:AssumeRole', | |
'ssm:GetParameters' | |
], | |
resources=["*"] | |
) | |
) | |
# ECS Task Role - Grants containers in task permission to AWS APIs | |
ecs_task_role = iam.Role( | |
self, 'ECSTaskRole', | |
assumed_by=iam.ServicePrincipal('ecs-tasks.amazonaws.com'), | |
role_name="{0}-{1}-task-role".format(my_service_name, stage) | |
) | |
# Setup Role Permissions | |
ecs_task_role.add_to_policy( | |
iam.PolicyStatement( | |
effect=iam.Effect.ALLOW, | |
actions=[ | |
'ecr:GetAuthorizationToken', | |
'ecr:BatchCheckLayerAvailability', | |
'ecr:GetDownloadUrlForLayer', | |
'ecr:BatchGetImage', | |
'logs:CreateLogStream', | |
'logs:PutLogEvents', | |
'dynamodb:Query', | |
'dynamodb:ListTables' | |
], | |
resources=["*"] | |
) | |
) | |
EcsStack(self, "{0}-{1}-ecs".format( | |
my_service_name, | |
stage | |
), | |
props=props, | |
vpc=vpc, | |
execution_role=ecs_execution_role, | |
task_role=ecs_task_role, | |
log_group=log_group, | |
env={ | |
'region': region, | |
'account': account | |
} | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment