From d26329ff0cb0d2e852f66f12202f087418fa04f9 Mon Sep 17 00:00:00 2001 From: AJ Schmidt Date: Tue, 15 Mar 2022 08:59:58 -0700 Subject: [PATCH] Add documentation for using ECS with CloudFormation --- deployments/ecs/cloudformation/s3gateway.cf | 0 deployments/ecs/cloudformation/s3gateway.yaml | 263 ++++++++++++++++++ docs/getting_started.md | 46 +++ 3 files changed, 309 insertions(+) delete mode 100644 deployments/ecs/cloudformation/s3gateway.cf create mode 100644 deployments/ecs/cloudformation/s3gateway.yaml diff --git a/deployments/ecs/cloudformation/s3gateway.cf b/deployments/ecs/cloudformation/s3gateway.cf deleted file mode 100644 index e69de29b..00000000 diff --git a/deployments/ecs/cloudformation/s3gateway.yaml b/deployments/ecs/cloudformation/s3gateway.yaml new file mode 100644 index 00000000..a64bb2d1 --- /dev/null +++ b/deployments/ecs/cloudformation/s3gateway.yaml @@ -0,0 +1,263 @@ +AWSTemplateFormatVersion: '2010-09-09' +Parameters: + NewBucketName: + Default: + Description: S3 Bucket Name + Type: String + Subnet1: + Default: + Description: ID of the first subnet to be used for resources + Type: String + Subnet2: + Default: + Description: ID of the second subnet to be used for resources + Type: String + VpcId: + Default: + Description: ID of the VPC to be used for resources + Type: String + ContainerName: + Default: s3gateway + Description: Name of the NGINX Container. No need to change this + Type: String + ResourceNamePrefix: + Default: nginx-s3-gateway + Description: Common prefix used for resource names. No need to change this + Type: String +Outputs: + PublicDNS: + Description: DNS name of load balancer + Value: !GetAtt 'ALB.DNSName' +Resources: + ALB: + Properties: + Name: !Join + - '-' + - - !Ref 'ResourceNamePrefix' + - alb + SecurityGroups: + - !GetAtt 'S3GatewaySG.GroupId' + SubnetMappings: + - SubnetId: !Ref 'Subnet1' + - SubnetId: !Ref 'Subnet2' + Type: application + Type: AWS::ElasticLoadBalancingV2::LoadBalancer + ALBHttpListener: + Properties: + DefaultActions: + - ForwardConfig: + TargetGroups: + - TargetGroupArn: !Ref 'ALBTargetGroup' + Type: forward + LoadBalancerArn: !Ref 'ALB' + Port: 80 + Protocol: HTTP + Type: AWS::ElasticLoadBalancingV2::Listener + ALBTargetGroup: + Properties: + Name: !Join + - '-' + - - !Ref 'ResourceNamePrefix' + - log-group + Port: 80 + Protocol: HTTP + ProtocolVersion: HTTP1 + TargetGroupAttributes: + - Key: deregistration_delay.timeout_seconds + Value: '150' + TargetType: ip + VpcId: !Ref 'VpcId' + Type: AWS::ElasticLoadBalancingV2::TargetGroup + Cluster: + Properties: + ClusterName: !Join + - '-' + - - !Ref 'ResourceNamePrefix' + - cluster + Type: AWS::ECS::Cluster + ECSLogGroup: + Properties: + LogGroupName: !Join + - '-' + - - !Ref 'ResourceNamePrefix' + - logs + RetentionInDays: 14 + Type: AWS::Logs::LogGroup + ECSTaskExecutionPolicy: + Properties: + PolicyDocument: + Statement: + - Action: + - logs:CreateLogStream + - logs:CreateLogGroup + - logs:PutLogEvents + Effect: Allow + Resource: + - '*' + Version: '2012-10-17' + PolicyName: !Join + - '-' + - - !Ref 'ResourceNamePrefix' + - ecs-task-execution-policy + Roles: + - !Ref 'ECSTaskExecutionRole' + Type: AWS::IAM::Policy + ECSTaskExecutionRole: + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: + - sts:AssumeRole + Effect: Allow + Principal: + Service: + - ecs-tasks.amazonaws.com + Version: '2012-10-17' + Description: An IAM role to enable ECS agents to perform AWS operations such as creating CloudWatch logs. + RoleName: !Join + - '-' + - - !Ref 'ResourceNamePrefix' + - ecs-task-execution-role + Type: AWS::IAM::Role + ECSTaskPolicy: + Properties: + PolicyDocument: + Statement: + - Action: + - s3:GetObject + - s3:ListBucket + Effect: Allow + Resource: + - !Sub + - arn:aws:s3:::${bucketName}/* + - bucketName: !Ref 'NewBucketName' + - !Sub + - arn:aws:s3:::${bucketName} + - bucketName: !Ref 'NewBucketName' + Version: '2012-10-17' + PolicyName: !Join + - '-' + - - !Ref 'ResourceNamePrefix' + - ecs-task-policy + Roles: + - !Ref 'ECSTaskRole' + Type: AWS::IAM::Policy + ECSTaskRole: + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: + - sts:AssumeRole + Effect: Allow + Principal: + Service: + - ecs-tasks.amazonaws.com + Version: '2012-10-17' + Description: An IAM role to enable ECS containers to perform AWS operations such as accessing S3 buckets. + RoleName: !Join + - '-' + - - !Ref 'ResourceNamePrefix' + - ecs-task-role + Type: AWS::IAM::Role + S3Bucket: + Properties: + BucketName: !Ref 'NewBucketName' + Type: AWS::S3::Bucket + S3GatewaySG: + Properties: + GroupDescription: Security group for NGINX S3 Gateway Infra + GroupName: !Join + - '-' + - - !Ref 'ResourceNamePrefix' + - sg + SecurityGroupEgress: + - CidrIp: '0.0.0.0/0' + Description: Allow all outbound IPv4 traffic + IpProtocol: '-1' + - CidrIpv6: ::/0 + Description: Allow all outbound IPv6 traffic + IpProtocol: '-1' + SecurityGroupIngress: + - CidrIp: '0.0.0.0/0' + Description: Allow HTTP Traffic on 80 + FromPort: 80 + IpProtocol: tcp + ToPort: 80 + - CidrIp: '0.0.0.0/0' + Description: Allow HTTPS Traffic on 443 + FromPort: 443 + IpProtocol: tcp + ToPort: 443 + VpcId: !Ref 'VpcId' + Type: AWS::EC2::SecurityGroup + S3GatewayService: + DependsOn: ALBHttpListener + Properties: + Cluster: !Ref 'Cluster' + DesiredCount: 1 + LaunchType: FARGATE + LoadBalancers: + - ContainerName: !Ref 'ContainerName' + ContainerPort: 80 + TargetGroupArn: !Ref 'ALBTargetGroup' + NetworkConfiguration: + AwsvpcConfiguration: + AssignPublicIp: ENABLED + SecurityGroups: + - !GetAtt 'S3GatewaySG.GroupId' + Subnets: + - !Ref 'Subnet1' + - !Ref 'Subnet2' + ServiceName: !Join + - '-' + - - !Ref 'ResourceNamePrefix' + - service + TaskDefinition: !Ref 'TaskDefinition' + Type: AWS::ECS::Service + TaskDefinition: + DependsOn: S3Bucket + Properties: + ContainerDefinitions: + - Environment: + - Name: ALLOW_DIRECTORY_LIST + Value: 'true' + - Name: AWS_SIGS_VERSION + Value: '4' + - Name: S3_BUCKET_NAME + Value: !Ref 'S3Bucket' + - Name: S3_REGION + Value: !Ref 'AWS::Region' + - Name: S3_SERVER_PORT + Value: '443' + - Name: S3_SERVER_PROTO + Value: https + - Name: S3_SERVER + Value: !Join + - . + - - s3 + - !Ref 'AWS::Region' + - amazonaws.com + - Name: S3_STYLE + Value: default + - Name: S3_DEBUG + Value: 'false' + Image: ghcr.io/nginxinc/nginx-s3-gateway/nginx-oss-s3-gateway:latest-njs-oss + LogConfiguration: + LogDriver: awslogs + Options: + awslogs-group: !Ref 'ECSLogGroup' + awslogs-region: !Ref 'AWS::Region' + awslogs-stream-prefix: ecs + Name: !Ref 'ContainerName' + PortMappings: + - ContainerPort: 80 + HostPort: 80 + Cpu: '1024' + ExecutionRoleArn: !GetAtt 'ECSTaskExecutionRole.Arn' + Family: !Ref 'ContainerName' + Memory: '2048' + NetworkMode: awsvpc + RequiresCompatibilities: + - FARGATE + TaskRoleArn: !GetAtt 'ECSTaskRole.Arn' + Type: AWS::ECS::TaskDefinition diff --git a/docs/getting_started.md b/docs/getting_started.md index b95eef75..a5dc150a 100644 --- a/docs/getting_started.md +++ b/docs/getting_started.md @@ -200,3 +200,49 @@ aws ec2 modify-instance-metadata-options --instance-id \ After that has been run we can start the container normally and omit the `S3_ACCESS_KEY_ID` and `S3_SECRET_KEY` environment variables. +### Running in ECS with an IAM Policy + +The commands below all reference the [`deployments/ecs/cloudformation/s3gateway.cf`](/deployments/ecs/cloudformation/s3gateway.yaml) file. This file will need to be +modified. + +- Update the following 4 parameters in the `Parameters` section of the CloudFormation file for your specific AWS account: + - `NewBucketName` - any S3 bucket name. Remember that S3 bucket names must be globally unique + - `VpcId` - Any VPC ID on your AWS account + - `Subnet1` - Any subnet ID that's in the VPC used above + - `Subnet2` - Any subnet ID that's in the VPC used above +- Run the following command to deploy the stack (this assumes you have the AWS CLI & credentials setup correctly on your host machine and you are running in the project root directory): + + ```sh + aws cloudformation create-stack \ + --stack-name nginx-s3-gateway \ + --capabilities CAPABILITY_NAMED_IAM \ + --template-body file://deployments/ecs/cloudformation/s3gateway.yaml + ``` + +- Wait for the CloudFormation Stack deployment to complete + (can take about 3-5 minutes) + - You can query the stack status with this command: + ```sh + aws cloudformation describe-stacks \ + --stack-name nginx-s3-gateway \ + --query "Stacks[0].StackStatus" + ``` +- Wait until the query above shows `"CREATE_COMPLETE"` +- Run the following command to get the URL used to access the service: + ```sh + aws cloudformation describe-stacks \ + --stack-name nginx-s3-gateway \ + --query "Stacks[0].Outputs[0].OutputValue" + ``` + - Upload a file to the bucket first to prevent getting a `404` when visiting + the URL in your browser + ```sh + # i.e. + aws s3 cp README.md s3:// + ``` +- View the container logs in CloudWatch from the AWS web console +- Run the following command to delete the stack and all resources: + ```sh + aws cloudformation delete-stack \ + --stack-name nginx-s3-gateway + ```