#https://github.com/aws-samples/startup-kit-templates/blob/master/templates/fargate.cfn.yml #https://aws.amazon.com/blogs/compute/access-private-applications-on-aws-fargate-using-amazon-api-gateway-privatelink/ #https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-nlb-for-vpclink-using-console.html --- AWSTemplateFormatVersion: 2010-09-09 Transform: 'AWS::Serverless-2016-10-31' # A CloudFormation template to create/configure an AWS Fargate Cluster, Amazon API Gateway, AWS Network Load Balancer (NLB), VPC Link (PrivateLink), # Amazon Elastic Container Registry (ECR), AWS CodePipeline and Service based on parameters. # # From the Startup Kit Templates, this template requires the name of an existing vpc.cfn.yml stack as # a parameter. # # If you pass the optional database stack name, it pulls the values for the DB endpoint and username # and sets them as environment variables in the container. # # The service creates CloudWatch Alarms to monitor CPU utilization in order to determine container # counts (up and down), but other metrics may be more important in your system. # See: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/service_autoscaling_tutorial.html # # This template is released under Apache Version 2.0, and can be forked, copied, modified, # customized, etc. to match your application/system requirements. Description: Fargate Django Web App with Amazon API Gateway and AWS Network Load Balancer Parameters: PrimaryRegion: Type: String Description: Primary Region SecondaryRegion: Type: String Description: Secondary Region with CMK and read only ColumnEncryptionKeyAlias: Type: String Description: Column Encryption Key Alias KMSAccountID: Type: Number Description: KMS Account ID for the KMS Keys MinValue: 000000000001 MaxValue: 999999999999 NetworkStackName: Type: String Description: Name of an active Startup Kit CloudFormation stack that contains networking resources MinLength: 1 MaxLength: 255 AllowedPattern: "^[a-zA-Z][-a-zA-Z0-9]*$" DjangoDatabaseEngine: Type: String Description: Django Database Connector Type MinLength: 10 MaxLength: 255 AllowedPattern: "^[a-zA-Z][-a-zA-Z0-9.]*$" Default: django.db.backends.mysql AllowedValues: - django.db.backends.mysql - django.db.backends.postgresql ConstraintDescription: Specify either django.db.backends.mysql or django.db.backends.postgresql to match DatabaseEngine DatabaseStackName: Type: String Description: Name of an optional active Startup Kit CloudFormation stack that contains database resources Default: "" HostedZoneName: Type: String Description: The Amazon Route 53 Hosted Zone Name for the optional load balancer alias record - do not include a period at the end Default: "" AllowedPattern: "(^$|^((?!-)[A-Za-z0-9-]{1,63}(? ../build.json artifacts: files: build.json - ServiceName: !Ref GitSourceRepo Environment: ComputeType: BUILD_GENERAL1_SMALL Type: LINUX_CONTAINER Image: !Ref CodeBuildDockerImage EnvironmentVariables: - Name: REPOSITORY_URI Value: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${EcrDockerRepository} - Name: ENVIRONMENT_NAME Value: !Ref EnvironmentName - Name: REPOSITORY_NAME Value: !Ref GitSourceRepo - Name: REPOSITORY_BRANCH Value: !Ref GitBranch Name: !Ref AWS::StackName ServiceRole: !Ref CodeBuildServiceRole VpcConfig: VpcId: Fn::ImportValue: !Sub ${NetworkStackName}-VpcID Subnets: - Fn::ImportValue: !Sub ${NetworkStackName}-PrivateSubnet1ID - Fn::ImportValue: !Sub ${NetworkStackName}-PrivateSubnet2ID SecurityGroupIds: - Fn::ImportValue: !Sub ${NetworkStackName}-AppSecurityGroupID CodePipelineServiceRole: Type: AWS::IAM::Role Properties: Path: / AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: codepipeline.amazonaws.com Action: sts:AssumeRole Policies: - PolicyName: codepipeline-access PolicyDocument: Version: 2012-10-17 Statement: - Resource: "*" Effect: Allow Action: - ecs:List* - ecs:Describe* - ecs:RegisterTaskDefinition - ecs:UpdateService - codebuild:StartBuild - codebuild:BatchGetBuilds - codecommit:GetBranch - codecommit:GetCommit - codecommit:UploadArchive - codecommit:GetUploadArchiveStatus - codecommit:CancelUploadArchive - Resource: "*" Effect: Allow Action: - iam:PassRole Condition: StringEqualsIfExists: iam:PassedToService: - ecs-tasks.amazonaws.com - codecommit.amazonaws.com - codebuild.amazonaws.com - Resource: !Sub arn:aws:s3:::${CodePipelineArtifactBucket}/* Effect: Allow Action: - s3:PutObject - s3:GetObject - s3:GetObjectVersion - s3:GetBucketVersioning DependsOn: - CodePipelineArtifactBucket - FargateEcsCluster CodeDeployApplication: Type: AWS::CodeDeploy::Application Properties: ComputePlatform: ECS CodeDeploymentConfiguration: Type: AWS::CodeDeploy::DeploymentConfig Properties: MinimumHealthyHosts: Type: FLEET_PERCENT Value: 50 CodeDeployServiceRole: Type: AWS::IAM::Role Properties: Path: / AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: codedeploy.amazonaws.com Action: sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSCodeDeployRole - arn:aws:iam::aws:policy/AWSCodeDeployRoleForECS # This CodePipeline is used for CodeCommit repos. It triggers on a commit to the Git branch passed, # builds the Docker image and then deploys the container in the Fargate Cluster. CodePipeline can support N stages. # For example, you may want to add a stage to test your build and/or container. CodePipelineCodeCommit: Type: AWS::CodePipeline::Pipeline Condition: IsCodeCommit Properties: RoleArn: !GetAtt CodePipelineServiceRole.Arn ArtifactStore: Type: S3 Location: !Ref CodePipelineArtifactBucket Stages: - Name: Source Actions: - Name: App ActionTypeId: Category: Source Owner: AWS Version: '1' Provider: CodeCommit Configuration: RepositoryName: !Ref GitSourceRepo BranchName: !Ref GitBranch OutputArtifacts: - Name: App RunOrder: 1 - Name: Build Actions: - Name: Build ActionTypeId: Category: Build Owner: AWS Version: '1' Provider: CodeBuild Configuration: ProjectName: !Ref CodeBuildProject InputArtifacts: - Name: App OutputArtifacts: - Name: BuildOutput RunOrder: 1 - Name: Deploy Actions: - Name: Deploy ActionTypeId: Category: Deploy Owner: AWS Version: '1' Provider: ECS Configuration: ClusterName: !Ref FargateEcsCluster ServiceName: !GetAtt DefaultFargateService.Name FileName: build.json InputArtifacts: - Name: BuildOutput RunOrder: 1 DependsOn: - CodePipelineArtifactBucket - CodeBuildProject - CodePipelineServiceRole - DefaultFargateService # This CodePipeline is used for GitHub based repos. It triggers on a commit to the Git branch passed, # builds the Docker image and then deploys the container in the Fargate Cluster. CodePipeline can support N stages. # For example, you may want to add a stage to test your build and/or container. CodePipelineGitHub: Type: AWS::CodePipeline::Pipeline Condition: IsGitHub Properties: RoleArn: !GetAtt CodePipelineServiceRole.Arn ArtifactStore: Type: S3 Location: !Ref CodePipelineArtifactBucket Stages: - Name: Source Actions: - Name: App ActionTypeId: Category: Source Owner: ThirdParty Version: '1' Provider: GitHub Configuration: Owner: !Ref GitHubUser Repo: !Ref GitSourceRepo Branch: !Ref GitBranch OAuthToken: !Ref GitHubToken OutputArtifacts: - Name: App RunOrder: 1 - Name: Build Actions: - Name: Build ActionTypeId: Category: Build Owner: AWS Version: '1' Provider: CodeBuild Configuration: ProjectName: !Ref CodeBuildProject InputArtifacts: - Name: App OutputArtifacts: - Name: BuildOutput RunOrder: 1 - Name: Deploy Actions: - Name: Deploy ActionTypeId: Category: Deploy Owner: AWS Version: '1' Provider: ECS Configuration: ClusterName: !Ref FargateEcsCluster ServiceName: !GetAtt DefaultFargateService.Name FileName: build.json InputArtifacts: - Name: BuildOutput RunOrder: 1 DependsOn: - CodePipelineArtifactBucket - CodeBuildProject - CodePipelineServiceRole - DefaultFargateService # Simple Amazon ECR Lifecycle Policies to try and reduce storage costs # See: https://docs.aws.amazon.com/AmazonECR/latest/userguide/LifecyclePolicies.html EcrDockerRepository: Type: AWS::ECR::Repository Properties: LifecyclePolicy: LifecyclePolicyText: !Sub - | { "rules": [ { "rulePriority": 1, "description": "Only keep untagged images for ${DaysToRetainUntaggedContainerImages} days", "selection": { "tagStatus": "untagged", "countType": "sinceImagePushed", "countUnit": "days", "countNumber": ${DaysToRetainUntaggedContainerImages} }, "action": { "type": "expire" } }, { "rulePriority": 2, "description": "Keep only ${MaxTaggedContainerImagesToRetain} tagged images, expire all others", "selection": { "tagStatus": "tagged", "tagPrefixList": [ "${EnvironmentName}" ], "countType": "imageCountMoreThan", "countNumber": ${MaxTaggedContainerImagesToRetain} }, "action": { "type": "expire" } } ] } - DaysToRetainUntaggedContainerImages: !Ref DaysToRetainUntaggedContainerImages MaxTaggedContainerImagesToRetain: !Ref MaxTaggedContainerImagesToRetain EnvironmentName: !Ref EnvironmentName FargateEcsCluster: Type: AWS::ECS::Cluster Properties: ClusterName: !Ref AWS::StackName # The namespace in Amazon CloudWatch Logs - see https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CloudWatchLogsConcepts.html DefaultLogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub /fargate/${AWS::StackName}/${GitSourceRepo}/${GitBranch}/${EnvironmentName} RetentionInDays: !Ref ContainerLogRetentionInDays TaskRoleManagedPolicy: Type: AWS::IAM::ManagedPolicy Properties: PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - 's3:*' Resource: !GetAtt DefaultContainerBucket.Arn - Effect: Allow Action: secretsmanager:GetSecretValue Resource: !If [ IsDbStackSet, "Fn::ImportValue": !Sub "${DatabaseStackName}-DatabaseSecretsManagerArn", !Ref DatabaseSecretsManagerArn ] Roles: - 'FargateTaskRole' DependsOn: DefaultContainerBucket DefaultTaskExecutionRole: Type: AWS::IAM::Role Properties: Path: / AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: ecs-tasks.amazonaws.com Action: sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy DefaultFargateTaskDefinition: Type: AWS::ECS::TaskDefinition Properties: Family: !Ref AWS::StackName RequiresCompatibilities: - FARGATE Cpu: !Ref DefaultContainerCpu Memory: !Ref DefaultContainerMemory NetworkMode: awsvpc TaskRoleArn: !Sub 'arn:aws:iam::${AWS::AccountId}:role/FargateTaskRole' ExecutionRoleArn: !GetAtt DefaultTaskExecutionRole.Arn ContainerDefinitions: - Name: !Ref GitSourceRepo Image: !Ref SeedDockerImage Essential: true PortMappings: - ContainerPort: Fn::ImportValue: !Sub ${NetworkStackName}-AppIngressPort # Environment variables can be customized by adding parameters/values below. Secrets # should be stored in AWS Secrets Manager Environment: - Name: BUCKET_NAME Value: !Ref DefaultContainerBucket - Name: ENVIRONMENT_NAME Value: !Ref EnvironmentName - Name: KMS_ACCOUNT_ID Value: !Ref KMSAccountID - Name: DJANGO_DATABASE_ENGINE Value: !Ref DjangoDatabaseEngine - Name: DATABASE_NAME Value: !If [ IsDbStackSet, "Fn::ImportValue": !Sub "${DatabaseStackName}-DatabaseName", !Ref DatabaseName ] - Name: DATABASE_HOSTNAME Value: !If [ IsDbStackSet, "Fn::ImportValue": !Sub "${DatabaseStackName}-DatabaseURL", !Ref DatabaseURL ] - Name: DATABASE_PORT Value: !If [ IsDbStackSet, "Fn::ImportValue": !Sub "${DatabaseStackName}-DatabasePort", !Ref DatabasePort ] - Name: DATABASE_SECRETSMANAGER_ARN Value: !If [ IsDbStackSet, "Fn::ImportValue": !Sub "${DatabaseStackName}-DatabaseSecretsManagerArn", !Ref DatabaseSecretsManagerArn ] - Name : COLUMN_ENCRYPTION_KEY_ALIAS Value: !Ref ColumnEncryptionKeyAlias - Name: AWS_PRIMARY_REGION Value: !Ref PrimaryRegion - Name: AWS_SECONDARY_REGION Value: !Ref SecondaryRegion LogConfiguration: LogDriver: awslogs Options: awslogs-region: !Ref AWS::Region awslogs-group: !Ref DefaultLogGroup awslogs-stream-prefix: !Ref GitSourceRepo DependsOn: - DefaultContainerBucket - DefaultLogGroup - DefaultTaskExecutionRole DefaultFargateService: Type: AWS::ECS::Service Properties: Cluster: !Ref FargateEcsCluster ServiceName: !Ref AWS::StackName DesiredCount: !Ref DefaultTaskMinContainerCount LaunchType: FARGATE TaskDefinition: !Ref DefaultFargateTaskDefinition LoadBalancers: - ContainerName: !Ref GitSourceRepo ContainerPort: Fn::ImportValue: !Sub ${NetworkStackName}-AppIngressPort TargetGroupArn: !Ref NetworkLoadBalancerTargetGroup NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: DISABLED SecurityGroups: - Fn::ImportValue: !Sub ${NetworkStackName}-AppSecurityGroupID Subnets: - Fn::ImportValue: !Sub ${NetworkStackName}-PrivateSubnet1ID - Fn::ImportValue: !Sub ${NetworkStackName}-PrivateSubnet2ID DependsOn: - FargateEcsCluster - DefaultFargateTaskDefinition - LoadBalancerListener # 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::Role Properties: AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: [ecs.amazonaws.com] Action: ['sts:AssumeRole'] Path: / Policies: - PolicyName: ecs-service PolicyDocument: Statement: - Effect: Allow Action: # 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: '*' ServiceAutoScalingRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: application-autoscaling.amazonaws.com Action: sts:AssumeRole Path: / Policies: - PolicyName: service-autoscaling PolicyDocument: Statement: - Effect: Allow Action: - application-autoscaling:* - cloudwatch:DescribeAlarms - cloudwatch:PutMetricAlarm - ecs:DescribeServices - ecs:UpdateService Resource: '*' DefaultServiceScalingTarget: Type: AWS::ApplicationAutoScaling::ScalableTarget Properties: MinCapacity: !Ref DefaultTaskMinContainerCount MaxCapacity: !Ref DefaultTaskMaxContainerCount ResourceId: !Sub - service/${EcsClusterName}/${EcsDefaultServiceName} - EcsClusterName: !Ref FargateEcsCluster EcsDefaultServiceName: !GetAtt DefaultFargateService.Name RoleARN: !GetAtt ServiceAutoScalingRole.Arn ScalableDimension: ecs:service:DesiredCount ServiceNamespace: ecs DependsOn: - DefaultFargateService - ServiceAutoScalingRole DefaultServiceScaleOutPolicy: Type: AWS::ApplicationAutoScaling::ScalingPolicy Properties: PolicyName: ScaleOutPolicy PolicyType: StepScaling ScalingTargetId: !Ref DefaultServiceScalingTarget StepScalingPolicyConfiguration: AdjustmentType: ChangeInCapacity Cooldown: 60 MetricAggregationType: Average StepAdjustments: - ScalingAdjustment: 1 MetricIntervalLowerBound: 0 DependsOn: DefaultServiceScalingTarget DefaultServiceScaleInPolicy: Type: AWS::ApplicationAutoScaling::ScalingPolicy Properties: PolicyName: ScaleInPolicy PolicyType: StepScaling ScalingTargetId: !Ref DefaultServiceScalingTarget StepScalingPolicyConfiguration: AdjustmentType: ChangeInCapacity Cooldown: 60 MetricAggregationType: Average StepAdjustments: - ScalingAdjustment: -1 MetricIntervalUpperBound: 0 DependsOn: DefaultServiceScalingTarget DefaultServiceScaleOutAlarm: Type: AWS::CloudWatch::Alarm Properties: EvaluationPeriods: !Ref DefaultServiceScaleEvaluationPeriods Statistic: Average TreatMissingData: notBreaching Threshold: !Ref DefaultServiceCpuScaleOutThreshold AlarmDescription: Alarm to add capacity if CPU is high Period: 60 AlarmActions: - !Ref DefaultServiceScaleOutPolicy Namespace: AWS/ECS Dimensions: - Name: ClusterName Value: !Ref FargateEcsCluster - Name: ServiceName Value: !GetAtt DefaultFargateService.Name ComparisonOperator: GreaterThanThreshold MetricName: CPUUtilization DependsOn: - DefaultFargateService - DefaultServiceScaleOutPolicy DefaultServiceScaleInAlarm: Type: AWS::CloudWatch::Alarm Properties: EvaluationPeriods: !Ref DefaultServiceScaleEvaluationPeriods Statistic: Average TreatMissingData: notBreaching Threshold: !Ref DefaultServiceCpuScaleInThreshold AlarmDescription: Alarm to reduce capacity if container CPU is low Period: 300 AlarmActions: - !Ref DefaultServiceScaleInPolicy Namespace: AWS/ECS Dimensions: - Name: ClusterName Value: !Ref FargateEcsCluster - Name: ServiceName Value: !GetAtt DefaultFargateService.Name ComparisonOperator: LessThanThreshold MetricName: CPUUtilization DependsOn: - DefaultFargateService - DefaultServiceScaleInPolicy APIGatewayCloudWatchRole: Type: 'AWS::IAM::Role' Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - apigateway.amazonaws.com Action: 'sts:AssumeRole' Path: / ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs #https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-account.html APIGatewayAccount: DependsOn: APIProxyMethod Type: 'AWS::ApiGateway::Account' Properties: CloudWatchRoleArn: !GetAtt APIGatewayCloudWatchRole.Arn APIGatewayLogGroup: Type: AWS::Logs::LogGroup Properties: RetentionInDays: 7 APIGatewayDeployment: DependsOn: - APIProxyMethod - APIGatewayAccount Type: 'AWS::ApiGateway::Deployment' Properties: RestApiId: !Ref RestApi Description: API Gateway Deployment StageName: !Ref StageNameAPIGateway StageDescription: DataTraceEnabled: True MetricsEnabled: True AccessLogSetting: DestinationArn: !GetAtt APIGatewayLogGroup.Arn Format: '{"apiId":"$context.apiId","stage":"$context.stage","resourcePath":"$context.resourcePath","requestId":"$context.requestId","awsEndpointRequestId":"$context.awsEndpointRequestId","xrayTraceId":"$context.xrayTraceId","requestTime":"$context.requestTime","requestTimeEpoch":$context.requestTimeEpoch,"httpMethod":"$context.httpMethod","status":"$context.status","path":"$context.path","ip": "$context.identity.sourceIp","caller":"$context.identity.caller", "user":"$context.identity.user", "protocol":"$context.protocol", "responseLength":"$context.responseLength"}' RestApi: Type: AWS::ApiGateway::RestApi Properties: Name: APIGateway EndpointConfiguration: Types: - REGIONAL APIResource: Type: 'AWS::ApiGateway::Resource' Properties: ParentId: !GetAtt RestApi.RootResourceId RestApiId: !Ref RestApi PathPart: '{proxy+}' APIProxyMethod: Type: 'AWS::ApiGateway::Method' Properties: RestApiId: !Ref RestApi ResourceId: !Ref APIResource HttpMethod: ANY AuthorizationType: NONE RequestParameters: method.request.path.proxy: true Integration: PassthroughBehavior: WHEN_NO_MATCH RequestParameters: integration.request.path.proxy: 'method.request.path.proxy' ConnectionId: !Ref APIGatewayVPCLink ConnectionType: VPC_LINK IntegrationHttpMethod: ANY Type: HTTP_PROXY #The URI parameter is not used to route requests to your endpoint, but is used to set the host header and for certificate validation. Uri: http://myapi.example.com/{proxy} APIGatewayVPCLink: Type: AWS::ApiGateway::VpcLink Properties: Name: APIGatewayToNetworkLoadBalancer Description: API Gateway to Network Load Balancer TargetArns: - !Ref NetworkLoadBalancer NetworkLoadBalancer: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Scheme: internal Subnets: - Fn::ImportValue: !Sub ${NetworkStackName}-PrivateSubnet1ID - Fn::ImportValue: !Sub ${NetworkStackName}-PrivateSubnet2ID Tags: - Key: StackName Value: !Ref AWS::StackName Type: network NetworkLoadBalancerTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: HealthCheckIntervalSeconds: 30 HealthCheckProtocol: TCP HealthyThresholdCount: 10 UnhealthyThresholdCount: 10 TargetType: ip # Only use the stack name here because the full name can only be 32 characters, service prefix + stack name is often too long Port: Fn::ImportValue: !Sub ${NetworkStackName}-AppIngressPort Protocol: TCP VpcId: Fn::ImportValue: !Sub ${NetworkStackName}-VpcID # Create a rule on the load balancer for routing traffic to the target group LoadBalancerListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - TargetGroupArn: !Ref NetworkLoadBalancerTargetGroup Type: forward LoadBalancerArn: !Ref NetworkLoadBalancer Port: Fn::ImportValue: !Sub ${NetworkStackName}-AppIngressPort Protocol: TCP Outputs: Name: Description: Fargate Stack Name Value: !Ref AWS::StackName Export: Name: !Sub ${AWS::StackName}-Name EnvironmentName: Description: Environment Name Value: !Ref EnvironmentName Export: Name: !Sub ${AWS::StackName}-EnvironmentName EcrDockerRepositoryName: Value: !Ref EcrDockerRepository Export: Name: !Sub ${AWS::StackName}-EcrDockerRepositoryName EcrDockerRepositoryArn: Value: !Sub arn:aws:ecr:${AWS::Region}:${AWS::AccountId}:repository/${EcrDockerRepository} Export: Name: !Sub ${AWS::StackName}-EcrDockerRepositoryArn EcrDockerRepositoryUri: Value: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${EcrDockerRepository} Export: Name: !Sub ${AWS::StackName}-EcrDockerRepositoryUri FargateEcsClusterName: Value: !Ref FargateEcsCluster Export: Name: !Sub ${AWS::StackName}-FargateEcsClusterName FargateEcsClusterArn: Value: !GetAtt FargateEcsCluster.Arn Export: Name: !Sub ${AWS::StackName}-FargateEcsClusterArn DefaultFargateServiceArn: Value: !Ref DefaultFargateService Export: Name: !Sub ${AWS::StackName}-DefaultFargateServiceArn DefaultFargateServiceName: Value: !GetAtt DefaultFargateService.Name Export: Name: !Sub ${AWS::StackName}-DefaultFargateServiceName CodePipelineArtifactBucketName: Value: !Ref CodePipelineArtifactBucket Export: Name: !Sub ${AWS::StackName}-CodePipelineArtifactBucket CodePipelineArtifactBucketArn: Value: !GetAtt CodePipelineArtifactBucket.Arn Export: Name: !Sub ${AWS::StackName}-CodePipelineArtifactBucketArn StackName: Value: !Ref AWS::StackName Export: Name: !Sub "${AWS::StackName}-Stackname" APIGatewayEndpoint: Description: "API Gateway endpoint" Value: !Sub "https://${RestApi}.execute-api.${AWS::Region}.amazonaws.com/${StageNameAPIGateway}/" CreateUrl: Description: "Create Pin Url" Value: !Sub "https://${RestApi}.execute-api.${AWS::Region}.amazonaws.com/${StageNameAPIGateway}/create" AuthenticateDataUrl: Description: "Verify Pin Url" Value: !Sub "https://${RestApi}.execute-api.${AWS::Region}.amazonaws.com/${StageNameAPIGateway}/authenticate"