-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add CloudFormation template to deploy signed API (#122)
* Fix docker scripts * Implement signed API CF template * Generalize the template * Remove port configuration from signed API * Fix link to a private repository * Rename cloudformation template
- Loading branch information
Showing
12 changed files
with
337 additions
and
24 deletions.
There are no files selected for viewing
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,272 @@ | ||
{ | ||
"AWSTemplateFormatVersion": "2010-09-09", | ||
"Description": "CloudFormation template for deploying Signed API with public access", | ||
"Outputs": { | ||
"LoadBalancerDNS": { | ||
"Description": "The DNS name of the load balancer", | ||
"Value": { "Fn::GetAtt": ["ELB", "DNSName"] }, | ||
"Export": { | ||
"Name": { "Fn::Sub": "${AWS::StackName}-LoadBalancerDNS" } | ||
} | ||
} | ||
}, | ||
"Resources": { | ||
"SignedApiLogsGroup": { | ||
"Type": "AWS::Logs::LogGroup", | ||
"Properties": { | ||
"LogGroupName": "/ecs/signedApi", | ||
"RetentionInDays": 7 | ||
} | ||
}, | ||
"SignedApiTaskDefinition": { | ||
"Type": "AWS::ECS::TaskDefinition", | ||
"Properties": { | ||
"Family": "signed-api-task", | ||
"Cpu": "256", | ||
"Memory": "512", | ||
"NetworkMode": "awsvpc", | ||
"RequiresCompatibilities": ["FARGATE"], | ||
"ExecutionRoleArn": { "Ref": "ECSTaskRole" }, | ||
"ContainerDefinitions": [ | ||
{ | ||
"Name": "signed-api-container", | ||
"Image": "<DOCKER_IMAGE>", | ||
"Environment": [ | ||
{ | ||
"Name": "CONFIG_SOURCE", | ||
"Value": "local" | ||
}, | ||
{ | ||
"Name": "LOG_LEVEL", | ||
"Value": "debug" | ||
} | ||
], | ||
"EntryPoint": [ | ||
"/bin/sh", | ||
"-c", | ||
"wget -O - <SIGNED_API_CONFIGURATION_URL> >> ./config/signed-api.json && node dist/index.js" | ||
], | ||
"PortMappings": [ | ||
{ | ||
"ContainerPort": 80, | ||
"HostPort": 80 | ||
} | ||
], | ||
"LogConfiguration": { | ||
"LogDriver": "awslogs", | ||
"Options": { | ||
"awslogs-group": { "Ref": "SignedApiLogsGroup" }, | ||
"awslogs-region": { "Ref": "AWS::Region" }, | ||
"awslogs-stream-prefix": "ecs" | ||
} | ||
} | ||
} | ||
] | ||
} | ||
}, | ||
"SignedApiService": { | ||
"Type": "AWS::ECS::Service", | ||
"DependsOn": "SignedApiListener", | ||
"Properties": { | ||
"Cluster": { "Ref": "ECSCluster" }, | ||
"LaunchType": "FARGATE", | ||
"TaskDefinition": { "Ref": "SignedApiTaskDefinition" }, | ||
"DesiredCount": 1, | ||
"NetworkConfiguration": { | ||
"AwsvpcConfiguration": { | ||
"Subnets": [{ "Ref": "PublicSubnet1" }, { "Ref": "PublicSubnet2" }], | ||
"SecurityGroups": [{ "Ref": "ECSSecurityGroup" }], | ||
"AssignPublicIp": "ENABLED" | ||
} | ||
}, | ||
"LoadBalancers": [ | ||
{ | ||
"ContainerName": "signed-api-container", | ||
"ContainerPort": 80, | ||
"TargetGroupArn": { "Ref": "SignedApiTargetGroup" } | ||
} | ||
] | ||
} | ||
}, | ||
"ECSCluster": { | ||
"Type": "AWS::ECS::Cluster", | ||
"Properties": { | ||
"ClusterName": "signed-api-cluster" | ||
} | ||
}, | ||
"ELB": { | ||
"Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", | ||
"Properties": { | ||
"Name": "signed-api-elb", | ||
"Subnets": [{ "Ref": "PublicSubnet1" }, { "Ref": "PublicSubnet2" }], | ||
"SecurityGroups": [{ "Ref": "ELBSecurityGroup" }], | ||
"Scheme": "internet-facing" | ||
} | ||
}, | ||
"SignedApiListener": { | ||
"Type": "AWS::ElasticLoadBalancingV2::Listener", | ||
"Properties": { | ||
"DefaultActions": [ | ||
{ | ||
"Type": "forward", | ||
"TargetGroupArn": { "Ref": "SignedApiTargetGroup" } | ||
} | ||
], | ||
"LoadBalancerArn": { "Ref": "ELB" }, | ||
"Port": 80, | ||
"Protocol": "HTTP" | ||
} | ||
}, | ||
"SignedApiTargetGroup": { | ||
"Type": "AWS::ElasticLoadBalancingV2::TargetGroup", | ||
"Properties": { | ||
"Port": 80, | ||
"Protocol": "HTTP", | ||
"VpcId": { "Ref": "VPC" }, | ||
"TargetType": "ip" | ||
} | ||
}, | ||
"VPC": { | ||
"Type": "AWS::EC2::VPC", | ||
"Properties": { | ||
"CidrBlock": "10.0.0.0/16", | ||
"EnableDnsSupport": "true", | ||
"EnableDnsHostnames": "true" | ||
} | ||
}, | ||
"PublicSubnet1": { | ||
"Type": "AWS::EC2::Subnet", | ||
"Properties": { | ||
"VpcId": { "Ref": "VPC" }, | ||
"CidrBlock": "10.0.1.0/24", | ||
"AvailabilityZone": { "Fn::Select": [0, { "Fn::GetAZs": "" }] }, | ||
"MapPublicIpOnLaunch": "true" | ||
} | ||
}, | ||
"PublicSubnet2": { | ||
"Type": "AWS::EC2::Subnet", | ||
"Properties": { | ||
"VpcId": { "Ref": "VPC" }, | ||
"CidrBlock": "10.0.2.0/24", | ||
"AvailabilityZone": { "Fn::Select": [1, { "Fn::GetAZs": "" }] }, | ||
"MapPublicIpOnLaunch": "true" | ||
} | ||
}, | ||
"InternetGateway": { | ||
"Type": "AWS::EC2::InternetGateway" | ||
}, | ||
"GatewayAttachment": { | ||
"Type": "AWS::EC2::VPCGatewayAttachment", | ||
"Properties": { | ||
"VpcId": { "Ref": "VPC" }, | ||
"InternetGatewayId": { "Ref": "InternetGateway" } | ||
} | ||
}, | ||
"RouteTable": { | ||
"Type": "AWS::EC2::RouteTable", | ||
"Properties": { | ||
"VpcId": { "Ref": "VPC" } | ||
} | ||
}, | ||
"Route": { | ||
"Type": "AWS::EC2::Route", | ||
"DependsOn": "GatewayAttachment", | ||
"Properties": { | ||
"RouteTableId": { "Ref": "RouteTable" }, | ||
"DestinationCidrBlock": "0.0.0.0/0", | ||
"GatewayId": { "Ref": "InternetGateway" } | ||
} | ||
}, | ||
"Subnet1RouteTableAssociation": { | ||
"Type": "AWS::EC2::SubnetRouteTableAssociation", | ||
"Properties": { | ||
"SubnetId": { "Ref": "PublicSubnet1" }, | ||
"RouteTableId": { "Ref": "RouteTable" } | ||
} | ||
}, | ||
"Subnet2RouteTableAssociation": { | ||
"Type": "AWS::EC2::SubnetRouteTableAssociation", | ||
"Properties": { | ||
"SubnetId": { "Ref": "PublicSubnet2" }, | ||
"RouteTableId": { "Ref": "RouteTable" } | ||
} | ||
}, | ||
"ECSSecurityGroup": { | ||
"Type": "AWS::EC2::SecurityGroup", | ||
"Properties": { | ||
"GroupDescription": "Security Group for ECS Tasks", | ||
"VpcId": { "Ref": "VPC" }, | ||
"SecurityGroupIngress": [ | ||
{ | ||
"IpProtocol": "tcp", | ||
"FromPort": 80, | ||
"ToPort": 80, | ||
"SourceSecurityGroupId": { "Ref": "ELBSecurityGroup" } | ||
} | ||
] | ||
} | ||
}, | ||
"ELBSecurityGroup": { | ||
"Type": "AWS::EC2::SecurityGroup", | ||
"Properties": { | ||
"GroupDescription": "Security Group for ELB", | ||
"VpcId": { "Ref": "VPC" }, | ||
"SecurityGroupIngress": [ | ||
{ | ||
"IpProtocol": "tcp", | ||
"FromPort": 80, | ||
"ToPort": 80, | ||
"CidrIp": "0.0.0.0/0" | ||
} | ||
] | ||
} | ||
}, | ||
"ECSTaskRole": { | ||
"Type": "AWS::IAM::Role", | ||
"Properties": { | ||
"AssumeRolePolicyDocument": { | ||
"Version": "2012-10-17", | ||
"Statement": [ | ||
{ | ||
"Effect": "Allow", | ||
"Principal": { | ||
"Service": ["ecs-tasks.amazonaws.com"] | ||
}, | ||
"Action": ["sts:AssumeRole"] | ||
} | ||
] | ||
}, | ||
"Path": "/", | ||
"Policies": [ | ||
{ | ||
"PolicyName": "ecs-service", | ||
"PolicyDocument": { | ||
"Version": "2012-10-17", | ||
"Statement": [ | ||
{ | ||
"Effect": "Allow", | ||
"Action": [ | ||
"ec2:AuthorizeSecurityGroupIngress", | ||
"ec2:Describe*", | ||
"elasticloadbalancing:DeregisterInstancesFromLoadBalancer", | ||
"elasticloadbalancing:DeregisterTargets", | ||
"elasticloadbalancing:Describe*", | ||
"elasticloadbalancing:RegisterInstancesWithLoadBalancer", | ||
"elasticloadbalancing:RegisterTargets", | ||
"ec2:CreateSecurityGroup", | ||
"ec2:DeleteSecurityGroup", | ||
"logs:CreateLogGroup", | ||
"logs:CreateLogStream", | ||
"logs:DescribeLogStreams", | ||
"logs:PutLogEvents" | ||
], | ||
"Resource": "*" | ||
} | ||
] | ||
} | ||
} | ||
] | ||
} | ||
} | ||
} | ||
} |
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import z from 'zod'; | ||
|
||
import { fetchAndCacheConfig } from './config'; | ||
import { logger } from './logger'; | ||
import { DEFAULT_PORT, startServer } from './server'; | ||
|
||
const portSchema = z.number().int().positive(); | ||
|
||
const startDevServer = async () => { | ||
const config = await fetchAndCacheConfig(); | ||
logger.info('Using configuration', config); | ||
|
||
const parsedPort = portSchema.safeParse(process.env.DEV_SERVER_PORT); | ||
let port: number; | ||
if (parsedPort.success) { | ||
port = parsedPort.data; | ||
logger.debug('Using DEV_SERVER_PORT environment variable as port number.', { | ||
port, | ||
}); | ||
} else { | ||
port = DEFAULT_PORT; | ||
logger.debug('DEV_SERVER_PORT environment variable not set or invalid. Using default port.', { | ||
port, | ||
}); | ||
} | ||
|
||
startServer(config, port); | ||
}; | ||
|
||
void startDevServer(); |
Oops, something went wrong.