AWS CloudFormation IaC files - AWS Proton

AWS CloudFormation IaC files

Learn how to use AWS CloudFormation infrastructure as code files with AWS Proton. AWS CloudFormation is an infrastructure as code (IaC) service that helps you model and set up your AWS resources. You define your infrastructure resources in templates, using Jinja on top of the CloudFormation template file format for parametrization. AWS Proton expands parameters and renders the full CloudFormation template. CloudFormation provisions the defined resources as CloudFormation stack. For more information, see What is AWS CloudFormation in the AWS CloudFormation User Guide.

AWS Proton supports AWS-managed provisioning for CloudFormation IaC.

Start with your own existing infrastructure as code files

You can adapt your own existing infrastructure as code (IaC) files for use with AWS Proton.

The following AWS CloudFormation examples, Example 1, and Example 2, represent your own existing CloudFormation IaC files. CloudFormation can use these files to create two different CloudFormation stacks.

In Example 1, the CloudFormation IaC file is configured to provision infrastructure to be shared among container applications. In this example, input parameters are added so that you can use the same IaC file to create multiple sets of provisioned infrastructure. Each set can have different names along with a different set of VPC and subnet CIDR values. As either an administrator or a developer, you provide values for these parameters when you use an IaC file to provision infrastructure resources with CloudFormation. For your convenience, these input parameters are marked with comments and referenced multiple times in the example. The outputs are defined at the end of the template. They can be referenced in other CloudFormation IaC files.

In Example 2, the CloudFormation IaC file is configured to deploy an application to the infrastructure that's provisioned from Example 1. The parameters are commented for your convenience.

AWSTemplateFormatVersion: '2010-09-09' Description: AWS Fargate cluster running containers in a public subnet. Only supports public facing load balancer, and public service discovery namespaces. Parameters: VpcCIDR: # input parameter Description: CIDR for VPC Type: String Default: "10.0.0.0/16" SubnetOneCIDR: # input parameter Description: CIDR for SubnetOne Type: String Default: "10.0.0.0/24" SubnetTwoCIDR: # input parameters Description: CIDR for SubnetTwo Type: String Default: "10.0.1.0/24" Resources: VPC: Type: AWS::EC2::VPC Properties: EnableDnsSupport: true EnableDnsHostnames: true CidrBlock: Ref: 'VpcCIDR' # Two public subnets, where containers will have public IP addresses PublicSubnetOne: Type: AWS::EC2::Subnet Properties: AvailabilityZone: Fn::Select: - 0 - Fn::GetAZs: {Ref: 'AWS::Region'} VpcId: !Ref 'VPC' CidrBlock: Ref: 'SubnetOneCIDR' MapPublicIpOnLaunch: true PublicSubnetTwo: Type: AWS::EC2::Subnet Properties: AvailabilityZone: Fn::Select: - 1 - Fn::GetAZs: {Ref: 'AWS::Region'} VpcId: !Ref 'VPC' CidrBlock: Ref: 'SubnetTwoCIDR' MapPublicIpOnLaunch: true # Setup networking resources for the public subnets. Containers # in the public subnets have public IP addresses and the routing table # sends network traffic via the internet gateway. InternetGateway: Type: AWS::EC2::InternetGateway GatewayAttachement: Type: AWS::EC2::VPCGatewayAttachment Properties: VpcId: !Ref 'VPC' InternetGatewayId: !Ref 'InternetGateway' PublicRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref 'VPC' PublicRoute: Type: AWS::EC2::Route DependsOn: GatewayAttachement Properties: RouteTableId: !Ref 'PublicRouteTable' DestinationCidrBlock: '0.0.0.0/0' GatewayId: !Ref 'InternetGateway' PublicSubnetOneRouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnetOne RouteTableId: !Ref PublicRouteTable PublicSubnetTwoRouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnetTwo RouteTableId: !Ref PublicRouteTable # ECS Resources ECSCluster: Type: AWS::ECS::Cluster # A security group for the containers we will run in Fargate. # Rules are added to this security group based on what ingress you # add for the cluster. ContainerSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Access to the Fargate containers VpcId: !Ref 'VPC' # This is a role which is used by the ECS tasks themselves. ECSTaskExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: [ecs-tasks.amazonaws.com] Action: ['sts:AssumeRole'] Path: / ManagedPolicyArns: - 'arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy' # These output values will be available to other templates to use. Outputs: ClusterName: # output Description: The name of the ECS cluster Value: !Ref 'ECSCluster' Export: Name: Fn::Sub: "${AWS::StackName}-ECSCluster" ECSTaskExecutionRole: # output Description: The ARN of the ECS role Value: !GetAtt 'ECSTaskExecutionRole.Arn' Export: Name: Fn::Sub: "${AWS::StackName}-ECSTaskExecutionRole" VpcId: # output Description: The ID of the VPC that this stack is deployed in Value: !Ref 'VPC' Export: Name: Fn::Sub: "${AWS::StackName}-VPC" PublicSubnetOne: # output Description: Public subnet one Value: !Ref 'PublicSubnetOne' Export: Name: Fn::Sub: "${AWS::StackName}-PublicSubnetOne" PublicSubnetTwo: # output Description: Public subnet two Value: !Ref 'PublicSubnetTwo' Export: Name: Fn::Sub: "${AWS::StackName}-PublicSubnetTwo" ContainerSecurityGroup: # output Description: A security group used to allow Fargate containers to receive traffic Value: !Ref 'ContainerSecurityGroup' Export: Name: Fn::Sub: "${AWS::StackName}-ContainerSecurityGroup"
AWSTemplateFormatVersion: '2010-09-09' Description: Deploy a service on AWS Fargate, hosted in a public subnet, and accessible via a public load balancer. Parameters: ContainerPortInput: # input parameter Description: The port to route traffic to Type: Number Default: 80 TaskCountInput: # input parameter Description: The default number of Fargate tasks you want running Type: Number Default: 1 TaskSizeInput: # input parameter Description: The size of the task you want to run Type: String Default: x-small ContainerImageInput: # input parameter Description: The name/url of the container image Type: String Default: "public.ecr.aws/z9d2n7e1/nginx:1.19.5" TaskNameInput: # input parameter Description: Name for your task Type: String Default: "my-fargate-instance" StackName: # input parameter Description: Name of the environment stack to deploy to Type: String Default: "my-fargate-environment" Mappings: TaskSizeMap: x-small: cpu: 256 memory: 512 small: cpu: 512 memory: 1024 medium: cpu: 1024 memory: 2048 large: cpu: 2048 memory: 4096 x-large: cpu: 4096 memory: 8192 Resources: # A log group for storing the stdout logs from this service's containers LogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: Ref: 'TaskNameInput' # input parameter # The task definition. This is a simple metadata description of what # container to run, and what resource requirements it has. TaskDefinition: Type: AWS::ECS::TaskDefinition Properties: Family: !Ref 'TaskNameInput' Cpu: !FindInMap [TaskSizeMap, !Ref 'TaskSizeInput', cpu] Memory: !FindInMap [TaskSizeMap, !Ref 'TaskSizeInput', memory] NetworkMode: awsvpc RequiresCompatibilities: - FARGATE ExecutionRoleArn: Fn::ImportValue: !Sub "${StackName}-ECSTaskExecutionRole" # output parameter from another CloudFormation template awslogs-region: !Ref 'AWS::Region' awslogs-stream-prefix: !Ref 'TaskNameInput' # The service_instance. The service is a resource which allows you to run multiple # copies of a type of task, and gather up their logs and metrics, as well # as monitor the number of running tasks and replace any that have crashed Service: Type: AWS::ECS::Service DependsOn: LoadBalancerRule Properties: ServiceName: !Ref 'TaskNameInput' Cluster: Fn::ImportValue: !Sub "${StackName}-ECSCluster" # output parameter from another CloudFormation template LaunchType: FARGATE DeploymentConfiguration: MaximumPercent: 200 MinimumHealthyPercent: 75 DesiredCount: !Ref 'TaskCountInput' NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: ENABLED SecurityGroups: - Fn::ImportValue: !Sub "${StackName}-ContainerSecurityGroup" # output parameter from another CloudFormation template Subnets: - Fn::ImportValue:r CloudFormation template TaskRoleArn: !Ref "AWS::NoValue" ContainerDefinitions: - Name: !Ref 'TaskNameInput' Cpu: !FindInMap [TaskSizeMap, !Ref 'TaskSizeInput', cpu] Memory: !FindInMap [TaskSizeMap, !Ref 'TaskSizeInput', memory] Image: !Ref 'ContainerImageInput' # input parameter PortMappings: - ContainerPort: !Ref 'ContainerPortInput' # input parameter LogConfiguration: LogDriver: 'awslogs' Options: awslogs-group: !Ref 'TaskNameInput' !Sub "${StackName}-PublicSubnetOne" # output parameter from another CloudFormation template - Fn::ImportValue: !Sub "${StackName}-PublicSubnetTwo" # output parameter from another CloudFormation template TaskDefinition: !Ref 'TaskDefinition' LoadBalancers: - ContainerName: !Ref 'TaskNameInput' ContainerPort: !Ref 'ContainerPortInput' # input parameter TargetGroupArn: !Ref 'TargetGroup' # A target group. This is used for keeping track of all the tasks, and # what IP addresses / port numbers they have. You can query it yourself, # to use the addresses yourself, but most often this target group is just # connected to an application load balancer, or network load balancer, so # it can automatically distribute traffic across all the targets. TargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: HealthCheckIntervalSeconds: 6 HealthCheckPath: / HealthCheckProtocol: HTTP HealthCheckTimeoutSeconds: 5 HealthyThresholdCount: 2 TargetType: ip Name: !Ref 'TaskNameInput' Port: !Ref 'ContainerPortInput' Protocol: HTTP UnhealthyThresholdCount: 2 VpcId: Fn::ImportValue: !Sub "${StackName}-VPC" # output parameter from another CloudFormation template # Create a rule on the load balancer for routing traffic to the target group LoadBalancerRule: Type: AWS::ElasticLoadBalancingV2::ListenerRule Properties: Actions: - TargetGroupArn: !Ref 'TargetGroup' Type: 'forward' Conditions: - Field: path-pattern Values: - '*' ListenerArn: !Ref PublicLoadBalancerListener Priority: 1 # Enable autoscaling for this service ScalableTarget: Type: AWS::ApplicationAutoScaling::ScalableTarget DependsOn: Service Properties: ServiceNamespace: 'ecs' ScalableDimension: 'ecs:service:DesiredCount' ResourceId: Fn::Join: - '/' - - service - Fn::ImportValue: !Sub "${StackName}-ECSCluster" - !Ref 'TaskNameInput' MinCapacity: 1 MaxCapacity: 10 RoleARN: !Sub arn:aws:iam::${AWS::AccountId}:role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService # Create scaling policies for the service ScaleDownPolicy: Type: AWS::ApplicationAutoScaling::ScalingPolicy DependsOn: ScalableTarget Properties: PolicyName: Fn::Join: - '/' - - scale - !Ref 'TaskNameInput' - down PolicyType: StepScaling ResourceId: Fn::Join: - '/' - - service - Fn::ImportValue: !Sub "${StackName}-ECSCluster" # output parameter from another CloudFormation template - !Ref 'TaskNameInput' ScalableDimension: 'ecs:service:DesiredCount' ServiceNamespace: 'ecs' StepScalingPolicyConfiguration: AdjustmentType: 'ChangeInCapacity' StepAdjustments: - MetricIntervalUpperBound: 0 ScalingAdjustment: -1 MetricAggregationType: 'Average' Cooldown: 60 ScaleUpPolicy: Type: AWS::ApplicationAutoScaling::ScalingPolicy DependsOn: ScalableTarget Properties: PolicyName: Fn::Join: - '/' - - scale - !Ref 'TaskNameInput' - up PolicyType: StepScaling ResourceId: Fn::Join: - '/' - - service - Fn::ImportValue: !Sub "${StackName}-ECSCluster" - !Ref 'TaskNameInput' ScalableDimension: 'ecs:service:DesiredCount' ServiceNamespace: 'ecs' StepScalingPolicyConfiguration: AdjustmentType: 'ChangeInCapacity' StepAdjustments: - MetricIntervalLowerBound: 0 MetricIntervalUpperBound: 15 ScalingAdjustment: 1 - MetricIntervalLowerBound: 15 MetricIntervalUpperBound: 25 ScalingAdjustment: 2 - MetricIntervalLowerBound: 25 ScalingAdjustment: 3 MetricAggregationType: 'Average' Cooldown: 60 # Create alarms to trigger these policies LowCpuUsageAlarm: Type: AWS::CloudWatch::Alarm Properties: AlarmName: Fn::Join: - '-' - - low-cpu - !Ref 'TaskNameInput' AlarmDescription: Fn::Join: - ' ' - - "Low CPU utilization for service" - !Ref 'TaskNameInput' MetricName: CPUUtilization Namespace: AWS/ECS Dimensions: - Name: ServiceName Value: !Ref 'TaskNameInput' - Name: ClusterName Value: Fn::ImportValue: !Sub "${StackName}-ECSCluster" Statistic: Average Period: 60 EvaluationPeriods: 1 Threshold: 20 ComparisonOperator: LessThanOrEqualToThreshold AlarmActions: - !Ref ScaleDownPolicy HighCpuUsageAlarm: Type: AWS::CloudWatch::Alarm Properties: AlarmName: Fn::Join: - '-' - - high-cpu - !Ref 'TaskNameInput' AlarmDescription: Fn::Join: - ' ' - - "High CPU utilization for service" - !Ref 'TaskNameInput' MetricName: CPUUtilization Namespace: AWS/ECS Dimensions: - Name: ServiceName Value: !Ref 'TaskNameInput' - Name: ClusterName Value: Fn::ImportValue: !Sub "${StackName}-ECSCluster" Statistic: Average Period: 60 EvaluationPeriods: 1 Threshold: 70 ComparisonOperator: GreaterThanOrEqualToThreshold AlarmActions: - !Ref ScaleUpPolicy EcsSecurityGroupIngressFromPublicALB: Type: AWS::EC2::SecurityGroupIngress Properties: Description: Ingress from the public ALB GroupId: Fn::ImportValue: !Sub "${StackName}-ContainerSecurityGroup" IpProtocol: -1 SourceSecurityGroupId: !Ref 'PublicLoadBalancerSG' # Public load balancer, hosted in public subnets that is accessible # to the public, and is intended to route traffic to one or more public # facing services. This is used for accepting traffic from the public # internet and directing it to public facing microservices PublicLoadBalancerSG: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Access to the public facing load balancer VpcId: Fn::ImportValue: !Sub "${StackName}-VPC" SecurityGroupIngress: # Allow access to ALB from anywhere on the internet - CidrIp: 0.0.0.0/0 IpProtocol: -1 PublicLoadBalancer: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Scheme: internet-facing LoadBalancerAttributes: - Key: idle_timeout.timeout_seconds Value: '30' Subnets: # The load balancer is placed into the public subnets, so that traffic # from the internet can reach the load balancer directly via the internet gateway - Fn::ImportValue: !Sub "${StackName}-PublicSubnetOne" - Fn::ImportValue: !Sub "${StackName}-PublicSubnetTwo" SecurityGroups: [!Ref 'PublicLoadBalancerSG'] PublicLoadBalancerListener: Type: AWS::ElasticLoadBalancingV2::Listener DependsOn: - PublicLoadBalancer Properties: DefaultActions: - TargetGroupArn: !Ref 'TargetGroup' Type: 'forward' LoadBalancerArn: !Ref 'PublicLoadBalancer' Port: 80 Protocol: HTTP # These output values will be available to other templates to use. Outputs: ServiceEndpoint: # output Description: The URL to access the service Value: !Sub "http://${PublicLoadBalancer.DNSName}"

You can adapt these files for use with AWS Proton.

Bring your infrastructure as code to AWS Proton

With slight modifications, you can use Example 1 as an infrastructure as code (IaC) file for an environment template bundle that AWS Proton uses to deploy an environment (as shown in Example 3).

Instead of using the CloudFormation parameters, you use Jinja syntax to reference parameters that you have defined in an Open API based schema file. These input parameters are commented for your convenience and referenced multiple times in the IaC file. This way, AWS Proton can audit and check parameter values. It can also match and insert output parameter values in one IaC file to parameters in another IaC file.

As administrator, you can add the AWS Proton environment.inputs. namespace to the input parameters. When you reference environment IaC file outputs in a service IaC file, you can add the environment.outputs. namespace to the outputs (for example, environment.outputs.ClusterName). Last, you surround them with curly braces and quotation marks.

With these modifications, your CloudFormation IaC files can be used by AWS Proton.

AWSTemplateFormatVersion: '2010-09-09' Description: AWS Fargate cluster running containers in a public subnet. Only supports public facing load balancer, and public service discovery prefixes. Mappings: # The VPC and subnet configuration is passed in via the environment spec. SubnetConfig: VPC: CIDR: '{{ environment.inputs.vpc_cidr}}' # input parameter PublicOne: CIDR: '{{ environment.inputs.subnet_one_cidr}}' # input parameter PublicTwo: CIDR: '{{ environment.inputs.subnet_two_cidr}}' # input parameter Resources: VPC: Type: AWS::EC2::VPC Properties: EnableDnsSupport: true EnableDnsHostnames: true CidrBlock: !FindInMap ['SubnetConfig', 'VPC', 'CIDR'] # Two public subnets, where containers will have public IP addresses PublicSubnetOne: Type: AWS::EC2::Subnet Properties: AvailabilityZone: Fn::Select: - 0 - Fn::GetAZs: {Ref: 'AWS::Region'} VpcId: !Ref 'VPC' CidrBlock: !FindInMap ['SubnetConfig', 'PublicOne', 'CIDR'] MapPublicIpOnLaunch: true PublicSubnetTwo: Type: AWS::EC2::Subnet Properties: AvailabilityZone: Fn::Select: - 1 - Fn::GetAZs: {Ref: 'AWS::Region'} VpcId: !Ref 'VPC' CidrBlock: !FindInMap ['SubnetConfig', 'PublicTwo', 'CIDR'] MapPublicIpOnLaunch: true # Setup networking resources for the public subnets. Containers # in the public subnets have public IP addresses and the routing table # sends network traffic via the internet gateway. InternetGateway: Type: AWS::EC2::InternetGateway GatewayAttachement: Type: AWS::EC2::VPCGatewayAttachment Properties: VpcId: !Ref 'VPC' InternetGatewayId: !Ref 'InternetGateway' PublicRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref 'VPC' PublicRoute: Type: AWS::EC2::Route DependsOn: GatewayAttachement Properties: RouteTableId: !Ref 'PublicRouteTable' DestinationCidrBlock: '0.0.0.0/0' GatewayId: !Ref 'InternetGateway' PublicSubnetOneRouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnetOne RouteTableId: !Ref PublicRouteTable PublicSubnetTwoRouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnetTwo RouteTableId: !Ref PublicRouteTable # ECS Resources ECSCluster: Type: AWS::ECS::Cluster # A security group for the containers we will run in Fargate. # Rules are added to this security group based on what ingress you # add for the cluster. ContainerSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Access to the Fargate containers VpcId: !Ref 'VPC' # This is a role which is used by the ECS tasks themselves. ECSTaskExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: [ecs-tasks.amazonaws.com] Action: ['sts:AssumeRole'] Path: / ManagedPolicyArns: - 'arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy' # These output values are available to service infrastructure as code files as outputs, when given the # the 'service_instance.environment.outputs.' namespace, for example, service_instance.environment.outputs.ClusterName. Outputs: ClusterName: # output Description: The name of the ECS cluster Value: !Ref 'ECSCluster' ECSTaskExecutionRole: # output Description: The ARN of the ECS role Value: !GetAtt 'ECSTaskExecutionRole.Arn' VpcId: # output Description: The ID of the VPC that this stack is deployed in Value: !Ref 'VPC' PublicSubnetOne: # output Description: Public subnet one Value: !Ref 'PublicSubnetOne' PublicSubnetTwo: # output Description: Public subnet two Value: !Ref 'PublicSubnetTwo' ContainerSecurityGroup: # output Description: A security group used to allow Fargate containers to receive traffic Value: !Ref 'ContainerSecurityGroup'

The IaC files in Example 1 and Example 3 produce slightly different CloudFormation stacks. Parameters are displayed differently in the stack template files. The Example 1 CloudFormation stack template file displays the parameter labels (keys) in the stack template view. The Example 3 AWS Proton CloudFormation infrastructure stack template file displays the parameter values. AWS Proton input parameters don’t appear in the console CloudFormation stack parameters view.

In Example 4, the AWS Proton service IaC file corresponds with Example 2.

AWSTemplateFormatVersion: '2010-09-09' Description: Deploy a service on AWS Fargate, hosted in a public subnet, and accessible via a public load balancer. Mappings: TaskSize: x-small: cpu: 256 memory: 512 small: cpu: 512 memory: 1024 medium: cpu: 1024 memory: 2048 large: cpu: 2048 memory: 4096 x-large: cpu: 4096 memory: 8192 Resources: # A log group for storing the stdout logs from this service's containers LogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: '{{service_instance.name}}' # resource parameter # The task definition. This is a simple metadata description of what # container to run, and what resource requirements it has. TaskDefinition: Type: AWS::ECS::TaskDefinition Properties: Family: '{{service_instance.name}}' Cpu: !FindInMap [TaskSize, {{service_instance.inputs.task_size}}, cpu] # input parameter Memory: !FindInMap [TaskSize, {{service_instance.inputs.task_size}}, memory] NetworkMode: awsvpc RequiresCompatibilities: - FARGATE ExecutionRoleArn: '{{environment.outputs.ECSTaskExecutionRole}}' # output from an environment infrastructure as code file TaskRoleArn: !Ref "AWS::NoValue" ContainerDefinitions: - Name: '{{service_instance.name}}' Cpu: !FindInMap [TaskSize, {{service_instance.inputs.task_size}}, cpu] Memory: !FindInMap [TaskSize, {{service_instance.inputs.task_size}}, memory] Image: '{{service_instance.inputs.image}}' PortMappings: - ContainerPort: '{{service_instance.inputs.port}}' # input parameter LogConfiguration: LogDriver: 'awslogs' Options: awslogs-group: '{{service_instance.name}}' awslogs-region: !Ref 'AWS::Region' awslogs-stream-prefix: '{{service_instance.name}}' # The service_instance. The service is a resource which allows you to run multiple # copies of a type of task, and gather up their logs and metrics, as well # as monitor the number of running tasks and replace any that have crashed Service: Type: AWS::ECS::Service DependsOn: LoadBalancerRule Properties: ServiceName: '{{service_instance.name}}' Cluster: '{{environment.outputs.ClusterName}}' # output from an environment infrastructure as code file LaunchType: FARGATE DeploymentConfiguration: MaximumPercent: 200 MinimumHealthyPercent: 75 DesiredCount: '{{service_instance.inputs.desired_count}}' # input parameter NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: ENABLED SecurityGroups: - '{{environment.outputs.ContainerSecurityGroup}}' # output from an environment infrastructure as code file Subnets: - '{{environment.outputs.PublicSubnetOne}}' # output from an environment infrastructure as code file - '{{environment.outputs.PublicSubnetTwo}}' TaskDefinition: !Ref 'TaskDefinition' LoadBalancers: - ContainerName: '{{service_instance.name}}' ContainerPort: '{{service_instance.inputs.port}}' TargetGroupArn: !Ref 'TargetGroup' # A target group. This is used for keeping track of all the tasks, and # what IP addresses / port numbers they have. You can query it yourself, # to use the addresses yourself, but most often this target group is just # connected to an application load balancer, or network load balancer, so # it can automatically distribute traffic across all the targets. TargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: HealthCheckIntervalSeconds: 6 HealthCheckPath: / HealthCheckProtocol: HTTP HealthCheckTimeoutSeconds: 5 HealthyThresholdCount: 2 TargetType: ip Name: '{{service_instance.name}}' Port: '{{service_instance.inputs.port}}' Protocol: HTTP UnhealthyThresholdCount: 2 VpcId: '{{environment.outputs.VpcId}}' # output from an environment infrastructure as code file # Create a rule on the load balancer for routing traffic to the target group LoadBalancerRule: Type: AWS::ElasticLoadBalancingV2::ListenerRule Properties: Actions: - TargetGroupArn: !Ref 'TargetGroup' Type: 'forward' Conditions: - Field: path-pattern Values: - '*' ListenerArn: !Ref PublicLoadBalancerListener Priority: 1 # Enable autoscaling for this service ScalableTarget: Type: AWS::ApplicationAutoScaling::ScalableTarget DependsOn: Service Properties: ServiceNamespace: 'ecs' ScalableDimension: 'ecs:service:DesiredCount' ResourceId: Fn::Join: - '/' - - service - '{{environment.outputs.ClusterName}}' # output from an environment infrastructure as code file - '{{service_instance.name}}' MinCapacity: 1 MaxCapacity: 10 RoleARN: !Sub arn:aws:iam::${AWS::AccountId}:role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService # Create scaling policies for the service ScaleDownPolicy: Type: AWS::ApplicationAutoScaling::ScalingPolicy DependsOn: ScalableTarget Properties: PolicyName: Fn::Join: - '/' - - scale - '{{service_instance.name}}' - down PolicyType: StepScaling ResourceId: Fn::Join: - '/' - - service - '{{environment.outputs.ClusterName}}' - '{{service_instance.name}}' ScalableDimension: 'ecs:service:DesiredCount' ServiceNamespace: 'ecs' StepScalingPolicyConfiguration: AdjustmentType: 'ChangeInCapacity' StepAdjustments: - MetricIntervalUpperBound: 0 ScalingAdjustment: -1 MetricAggregationType: 'Average' Cooldown: 60 ScaleUpPolicy: Type: AWS::ApplicationAutoScaling::ScalingPolicy DependsOn: ScalableTarget Properties: PolicyName: Fn::Join: - '/' - - scale - '{{service_instance.name}}' - up PolicyType: StepScaling ResourceId: Fn::Join: - '/' - - service - '{{environment.outputs.ClusterName}}' - '{{service_instance.name}}' ScalableDimension: 'ecs:service:DesiredCount' ServiceNamespace: 'ecs' StepScalingPolicyConfiguration: AdjustmentType: 'ChangeInCapacity' StepAdjustments: - MetricIntervalLowerBound: 0 MetricIntervalUpperBound: 15 ScalingAdjustment: 1 - MetricIntervalLowerBound: 15 MetricIntervalUpperBound: 25 ScalingAdjustment: 2 - MetricIntervalLowerBound: 25 ScalingAdjustment: 3 MetricAggregationType: 'Average' Cooldown: 60 # Create alarms to trigger these policies LowCpuUsageAlarm: Type: AWS::CloudWatch::Alarm Properties: AlarmName: Fn::Join: - '-' - - low-cpu - '{{service_instance.name}}' AlarmDescription: Fn::Join: - ' ' - - "Low CPU utilization for service" - '{{service_instance.name}}' MetricName: CPUUtilization Namespace: AWS/ECS Dimensions: - Name: ServiceName Value: '{{service_instance.name}}' - Name: ClusterName Value: '{{environment.outputs.ClusterName}}' Statistic: Average Period: 60 EvaluationPeriods: 1 Threshold: 20 ComparisonOperator: LessThanOrEqualToThreshold AlarmActions: - !Ref ScaleDownPolicy HighCpuUsageAlarm: Type: AWS::CloudWatch::Alarm Properties: AlarmName: Fn::Join: - '-' - - high-cpu - '{{service_instance.name}}' AlarmDescription: Fn::Join: - ' ' - - "High CPU utilization for service" - '{{service_instance.name}}' MetricName: CPUUtilization Namespace: AWS/ECS Dimensions: - Name: ServiceName Value: '{{service_instance.name}}' - Name: ClusterName Value: '{{environment.outputs.ClusterName}}' Statistic: Average Period: 60 EvaluationPeriods: 1 Threshold: 70 ComparisonOperator: GreaterThanOrEqualToThreshold AlarmActions: - !Ref ScaleUpPolicy EcsSecurityGroupIngressFromPublicALB: Type: AWS::EC2::SecurityGroupIngress Properties: Description: Ingress from the public ALB GroupId: '{{environment.outputs.ContainerSecurityGroup}}' IpProtocol: -1 SourceSecurityGroupId: !Ref 'PublicLoadBalancerSG' # Public load balancer, hosted in public subnets that is accessible # to the public, and is intended to route traffic to one or more public # facing services. This is used for accepting traffic from the public # internet and directing it to public facing microservices PublicLoadBalancerSG: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Access to the public facing load balancer VpcId: '{{environment.outputs.VpcId}}' SecurityGroupIngress: # Allow access to ALB from anywhere on the internet - CidrIp: 0.0.0.0/0 IpProtocol: -1 PublicLoadBalancer: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Scheme: internet-facing LoadBalancerAttributes: - Key: idle_timeout.timeout_seconds Value: '30' Subnets: # The load balancer is placed into the public subnets, so that traffic # from the internet can reach the load balancer directly via the internet gateway - '{{environment.outputs.PublicSubnetOne}}' - '{{environment.outputs.PublicSubnetTwo}}' SecurityGroups: [!Ref 'PublicLoadBalancerSG'] PublicLoadBalancerListener: Type: AWS::ElasticLoadBalancingV2::Listener DependsOn: - PublicLoadBalancer Properties: DefaultActions: - TargetGroupArn: !Ref 'TargetGroup' Type: 'forward' LoadBalancerArn: !Ref 'PublicLoadBalancer' Port: 80 Protocol: HTTP Outputs: ServiceEndpoint: # output Description: The URL to access the service Value: !Sub "http://${PublicLoadBalancer.DNSName}"

In Example 5, the AWS Proton pipeline IaC file provisions the pipeline infrastructure to support the service instances provisioned by Example 4.

Resources: ECRRepo: Type: AWS::ECR::Repository DeletionPolicy: Retain BuildProject: Type: AWS::CodeBuild::Project Properties: Artifacts: Type: CODEPIPELINE Environment: ComputeType: BUILD_GENERAL1_SMALL Image: aws/codebuild/amazonlinux2-x86_64-standard:3.0 PrivilegedMode: true Type: LINUX_CONTAINER EnvironmentVariables: - Name: repo_name Type: PLAINTEXT Value: !Ref ECRRepo - Name: service_name Type: PLAINTEXT Value: '{{ service.name }}' # resource parameter ServiceRole: Fn::GetAtt: - PublishRole - Arn Source: BuildSpec: Fn::Join: - "" - - >- { "version": "0.2", "phases": { "install": { "runtime-versions": { "docker": 18 }, "commands": [ "pip3 install --upgrade --user awscli", "echo 'f6bd1536a743ab170b35c94ed4c7c4479763356bd543af5d391122f4af852460 yq_linux_amd64' > yq_linux_amd64.sha", "wget https://github.com/mikefarah/yq/releases/download/3.4.0/yq_linux_amd64", "sha256sum -c yq_linux_amd64.sha", "mv yq_linux_amd64 /usr/bin/yq", "chmod +x /usr/bin/yq" ] }, "pre_build": { "commands": [ "cd $CODEBUILD_SRC_DIR", "$(aws ecr get-login --no-include-email --region $AWS_DEFAULT_REGION)", "{{ pipeline.inputs.unit_test_command }}", # input parameter ] }, "build": { "commands": [ "IMAGE_REPO_NAME=$repo_name", "IMAGE_TAG=$CODEBUILD_BUILD_NUMBER", "IMAGE_ID= - Ref: AWS::AccountId - >- .dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG", "docker build -t $IMAGE_REPO_NAME:$IMAGE_TAG -f {{ pipeline.inputs.dockerfile }} .", # input parameter "docker tag $IMAGE_REPO_NAME:$IMAGE_TAG $IMAGE_ID;", "docker push $IMAGE_ID" ] }, "post_build": { "commands": [ "aws proton --region $AWS_DEFAULT_REGION get-service --name $service_name | jq -r .service.spec > service.yaml", "yq w service.yaml 'instances[*].spec.image' \"$IMAGE_ID\" > rendered_service.yaml" ] } }, "artifacts": { "files": [ "rendered_service.yaml" ] } } Type: CODEPIPELINE EncryptionKey: Fn::GetAtt: - PipelineArtifactsBucketEncryptionKey - Arn {% for service_instance in service_instances %} Deploy{{loop.index}}Project: Type: AWS::CodeBuild::Project Properties: Artifacts: Type: CODEPIPELINE Environment: ComputeType: BUILD_GENERAL1_SMALL Image: aws/codebuild/amazonlinux2-x86_64-standard:3.0 PrivilegedMode: false Type: LINUX_CONTAINER EnvironmentVariables: - Name: service_name Type: PLAINTEXT Value: '{{service.name}}' # resource parameter - Name: service_instance_name Type: PLAINTEXT Value: '{{service_instance.name}}' # resource parameter ServiceRole: Fn::GetAtt: - DeploymentRole - Arn Source: BuildSpec: >- { "version": "0.2", "phases": { "build": { "commands": [ "pip3 install --upgrade --user awscli", "aws proton --region $AWS_DEFAULT_REGION update-service-instance --deployment-type CURRENT_VERSION --name $service_instance_name --service-name $service_name --spec file://rendered_service.yaml", "aws proton --region $AWS_DEFAULT_REGION wait service-instance-deployed --name $service_instance_name --service-name $service_name" ] } } } Type: CODEPIPELINE EncryptionKey: Fn::GetAtt: - PipelineArtifactsBucketEncryptionKey - Arn {% endfor %} # This role is used to build and publish an image to ECR PublishRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Action: sts:AssumeRole Effect: Allow Principal: Service: codebuild.amazonaws.com Version: "2012-10-17" PublishRoleDefaultPolicy: Type: AWS::IAM::Policy Properties: PolicyDocument: Statement: - Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents Effect: Allow Resource: - Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":logs:" - Ref: AWS::Region - ":" - Ref: AWS::AccountId - :log-group:/aws/codebuild/ - Ref: BuildProject - Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":logs:" - Ref: AWS::Region - ":" - Ref: AWS::AccountId - :log-group:/aws/codebuild/ - Ref: BuildProject - :* - Action: - codebuild:CreateReportGroup - codebuild:CreateReport - codebuild:UpdateReport - codebuild:BatchPutTestCases Effect: Allow Resource: Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":codebuild:" - Ref: AWS::Region - ":" - Ref: AWS::AccountId - :report-group/ - Ref: BuildProject - -* - Action: - ecr:GetAuthorizationToken Effect: Allow Resource: "*" - Action: - ecr:BatchCheckLayerAvailability - ecr:CompleteLayerUpload - ecr:GetAuthorizationToken - ecr:InitiateLayerUpload - ecr:PutImage - ecr:UploadLayerPart Effect: Allow Resource: Fn::GetAtt: - ECRRepo - Arn - Action: - proton:GetService Effect: Allow Resource: "*" - Action: - s3:GetObject* - s3:GetBucket* - s3:List* - s3:DeleteObject* - s3:PutObject* - s3:Abort* Effect: Allow Resource: - Fn::GetAtt: - PipelineArtifactsBucket - Arn - Fn::Join: - "" - - Fn::GetAtt: - PipelineArtifactsBucket - Arn - /* - Action: - kms:Decrypt - kms:DescribeKey - kms:Encrypt - kms:ReEncrypt* - kms:GenerateDataKey* Effect: Allow Resource: Fn::GetAtt: - PipelineArtifactsBucketEncryptionKey - Arn - Action: - kms:Decrypt - kms:Encrypt - kms:ReEncrypt* - kms:GenerateDataKey* Effect: Allow Resource: Fn::GetAtt: - PipelineArtifactsBucketEncryptionKey - Arn Version: "2012-10-17" PolicyName: PublishRoleDefaultPolicy Roles: - Ref: PublishRole DeploymentRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Action: sts:AssumeRole Effect: Allow Principal: Service: codebuild.amazonaws.com Version: "2012-10-17" DeploymentRoleDefaultPolicy: Type: AWS::IAM::Policy Properties: PolicyDocument: Statement: - Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents Effect: Allow Resource: - Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":logs:" - Ref: AWS::Region - ":" - Ref: AWS::AccountId - :log-group:/aws/codebuild/Deploy*Project* - Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":logs:" - Ref: AWS::Region - ":" - Ref: AWS::AccountId - :log-group:/aws/codebuild/Deploy*Project:* - Action: - codebuild:CreateReportGroup - codebuild:CreateReport - codebuild:UpdateReport - codebuild:BatchPutTestCases Effect: Allow Resource: Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":codebuild:" - Ref: AWS::Region - ":" - Ref: AWS::AccountId - :report-group/Deploy*Project - -* - Action: - proton:UpdateServiceInstance - proton:GetServiceInstance Effect: Allow Resource: "*" - Action: - s3:GetObject* - s3:GetBucket* - s3:List* Effect: Allow Resource: - Fn::GetAtt: - PipelineArtifactsBucket - Arn - Fn::Join: - "" - - Fn::GetAtt: - PipelineArtifactsBucket - Arn - /* - Action: - kms:Decrypt - kms:DescribeKey Effect: Allow Resource: Fn::GetAtt: - PipelineArtifactsBucketEncryptionKey - Arn - Action: - kms:Decrypt - kms:Encrypt - kms:ReEncrypt* - kms:GenerateDataKey* Effect: Allow Resource: Fn::GetAtt: - PipelineArtifactsBucketEncryptionKey - Arn Version: "2012-10-17" PolicyName: DeploymentRoleDefaultPolicy Roles: - Ref: DeploymentRole PipelineArtifactsBucketEncryptionKey: Type: AWS::KMS::Key Properties: KeyPolicy: Statement: - Action: - kms:Create* - kms:Describe* - kms:Enable* - kms:List* - kms:Put* - kms:Update* - kms:Revoke* - kms:Disable* - kms:Get* - kms:Delete* - kms:ScheduleKeyDeletion - kms:CancelKeyDeletion - kms:GenerateDataKey - kms:TagResource - kms:UntagResource Effect: Allow Principal: AWS: Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":iam::" - Ref: AWS::AccountId - :root Resource: "*" - Action: - kms:Decrypt - kms:DescribeKey - kms:Encrypt - kms:ReEncrypt* - kms:GenerateDataKey* Effect: Allow Principal: AWS: Fn::GetAtt: - PipelineRole - Arn Resource: "*" - Action: - kms:Decrypt - kms:DescribeKey - kms:Encrypt - kms:ReEncrypt* - kms:GenerateDataKey* Effect: Allow Principal: AWS: Fn::GetAtt: - PublishRole - Arn Resource: "*" - Action: - kms:Decrypt - kms:Encrypt - kms:ReEncrypt* - kms:GenerateDataKey* Effect: Allow Principal: AWS: Fn::GetAtt: - PublishRole - Arn Resource: "*" - Action: - kms:Decrypt - kms:DescribeKey Effect: Allow Principal: AWS: Fn::GetAtt: - DeploymentRole - Arn Resource: "*" - Action: - kms:Decrypt - kms:Encrypt - kms:ReEncrypt* - kms:GenerateDataKey* Effect: Allow Principal: AWS: Fn::GetAtt: - DeploymentRole - Arn Resource: "*" Version: "2012-10-17" UpdateReplacePolicy: Delete DeletionPolicy: Delete PipelineArtifactsBucket: Type: AWS::S3::Bucket Properties: VersioningConfiguration: Status: Enabled BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: KMSMasterKeyID: Fn::GetAtt: - PipelineArtifactsBucketEncryptionKey - Arn SSEAlgorithm: aws:kms PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true UpdateReplacePolicy: Retain DeletionPolicy: Retain PipelineArtifactsBucketEncryptionKeyAlias: Type: AWS::KMS::Alias Properties: AliasName: 'alias/codepipeline-encryption-key-{{ service.name }}' TargetKeyId: Fn::GetAtt: - PipelineArtifactsBucketEncryptionKey - Arn UpdateReplacePolicy: Delete DeletionPolicy: Delete PipelineRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Action: sts:AssumeRole Effect: Allow Principal: Service: codepipeline.amazonaws.com Version: "2012-10-17" PipelineRoleDefaultPolicy: Type: AWS::IAM::Policy Properties: PolicyDocument: Statement: - Action: - s3:GetObject* - s3:GetBucket* - s3:List* - s3:DeleteObject* - s3:PutObject* - s3:Abort* Effect: Allow Resource: - Fn::GetAtt: - PipelineArtifactsBucket - Arn - Fn::Join: - "" - - Fn::GetAtt: - PipelineArtifactsBucket - Arn - /* - Action: - kms:Decrypt - kms:DescribeKey - kms:Encrypt - kms:ReEncrypt* - kms:GenerateDataKey* Effect: Allow Resource: Fn::GetAtt: - PipelineArtifactsBucketEncryptionKey - Arn - Action: codestar-connections:* Effect: Allow Resource: "*" - Action: sts:AssumeRole Effect: Allow Resource: Fn::GetAtt: - PipelineBuildCodePipelineActionRole - Arn - Action: sts:AssumeRole Effect: Allow Resource: Fn::GetAtt: - PipelineDeployCodePipelineActionRole - Arn Version: "2012-10-17" PolicyName: PipelineRoleDefaultPolicy Roles: - Ref: PipelineRole Pipeline: Type: AWS::CodePipeline::Pipeline Properties: RoleArn: Fn::GetAtt: - PipelineRole - Arn Stages: - Actions: - ActionTypeId: Category: Source Owner: AWS Provider: CodeStarSourceConnection Version: "1" Configuration: ConnectionArn: '{{ service.repository_connection_arn }}' FullRepositoryId: '{{ service.repository_id }}' BranchName: '{{ service.branch_name }}' Name: Checkout OutputArtifacts: - Name: Artifact_Source_Checkout RunOrder: 1 Name: Source - Actions: - ActionTypeId: Category: Build Owner: AWS Provider: CodeBuild Version: "1" Configuration: ProjectName: Ref: BuildProject InputArtifacts: - Name: Artifact_Source_Checkout Name: Build OutputArtifacts: - Name: BuildOutput RoleArn: Fn::GetAtt: - PipelineBuildCodePipelineActionRole - Arn RunOrder: 1 Name: Build {%- for service_instance in service_instances %} - Actions: - ActionTypeId: Category: Build Owner: AWS Provider: CodeBuild Version: "1" Configuration: ProjectName: Ref: Deploy{{loop.index}}Project InputArtifacts: - Name: BuildOutput Name: Deploy RoleArn: Fn::GetAtt: - PipelineDeployCodePipelineActionRole - Arn RunOrder: 1 Name: 'Deploy{{service_instance.name}}' {%- endfor %} ArtifactStore: EncryptionKey: Id: Fn::GetAtt: - PipelineArtifactsBucketEncryptionKey - Arn Type: KMS Location: Ref: PipelineArtifactsBucket Type: S3 DependsOn: - PipelineRoleDefaultPolicy - PipelineRole PipelineBuildCodePipelineActionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Action: sts:AssumeRole Effect: Allow Principal: AWS: Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":iam::" - Ref: AWS::AccountId - :root Version: "2012-10-17" PipelineBuildCodePipelineActionRoleDefaultPolicy: Type: AWS::IAM::Policy Properties: PolicyDocument: Statement: - Action: - codebuild:BatchGetBuilds - codebuild:StartBuild - codebuild:StopBuild Effect: Allow Resource: Fn::GetAtt: - BuildProject - Arn Version: "2012-10-17" PolicyName: PipelineBuildCodePipelineActionRoleDefaultPolicy Roles: - Ref: PipelineBuildCodePipelineActionRole PipelineDeployCodePipelineActionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Action: sts:AssumeRole Effect: Allow Principal: AWS: Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":iam::" - Ref: AWS::AccountId - :root Version: "2012-10-17" PipelineDeployCodePipelineActionRoleDefaultPolicy: Type: AWS::IAM::Policy Properties: PolicyDocument: Statement: - Action: - codebuild:BatchGetBuilds - codebuild:StartBuild - codebuild:StopBuild Effect: Allow Resource: Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":codebuild:" - Ref: AWS::Region - ":" - Ref: AWS::AccountId - ":project/Deploy*" Version: "2012-10-17" PolicyName: PipelineDeployCodePipelineActionRoleDefaultPolicy Roles: - Ref: PipelineDeployCodePipelineActionRole Outputs: PipelineEndpoint: Description: The URL to access the pipeline Value: !Sub "https://${AWS::Region}.console.aws.amazon.com/codesuite/codepipeline/pipelines/${Pipeline}/view?region=${AWS::Region}" ] } } } Type: CODEPIPELINE EncryptionKey: Fn::GetAtt: - PipelineArtifactsBucketEncryptionKey - Arn {% endfor %} # This role is used to build and publish an image to ECR PublishRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Action: sts:AssumeRole Effect: Allow Principal: Service: codebuild.amazonaws.com Version: "2012-10-17" PublishRoleDefaultPolicy: Type: AWS::IAM::Policy Properties: PolicyDocument: Statement: - Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents Effect: Allow Resource: - Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":logs:" - Ref: AWS::Region - ":" - Ref: AWS::AccountId - :log-group:/aws/codebuild/ - Ref: BuildProject - Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":logs:" - Ref: AWS::Region - ":" - Ref: AWS::AccountId - :log-group:/aws/codebuild/ - Ref: BuildProject - :* - Action: - codebuild:CreateReportGroup - codebuild:CreateReport - codebuild:UpdateReport - codebuild:BatchPutTestCases Effect: Allow Resource: Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":codebuild:" - Ref: AWS::Region - ":" - Ref: AWS::AccountId - :report-group/ - Ref: BuildProject - -* - Action: - ecr:GetAuthorizationToken Effect: Allow Resource: "*" - Action: - ecr:BatchCheckLayerAvailability - ecr:CompleteLayerUpload - ecr:GetAuthorizationToken - ecr:InitiateLayerUpload - ecr:PutImage - ecr:UploadLayerPart Effect: Allow Resource: Fn::GetAtt: - ECRRepo - Arn - Action: - proton:GetService Effect: Allow Resource: "*" - Action: - s3:GetObject* - s3:GetBucket* - s3:List* - s3:DeleteObject* - s3:PutObject* - s3:Abort* Effect: Allow Resource: - Fn::GetAtt: - PipelineArtifactsBucket - Arn - Fn::Join: - "" - - Fn::GetAtt: - PipelineArtifactsBucket - Arn - /* - Action: - kms:Decrypt - kms:DescribeKey - kms:Encrypt - kms:ReEncrypt* - kms:GenerateDataKey* Effect: Allow Resource: Fn::GetAtt: - PipelineArtifactsBucketEncryptionKey - Arn - Action: - kms:Decrypt - kms:Encrypt - kms:ReEncrypt* - kms:GenerateDataKey* Effect: Allow Resource: Fn::GetAtt: - PipelineArtifactsBucketEncryptionKey - Arn Version: "2012-10-17" PolicyName: PublishRoleDefaultPolicy Roles: - Ref: PublishRole DeploymentRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Action: sts:AssumeRole Effect: Allow Principal: Service: codebuild.amazonaws.com Version: "2012-10-17" DeploymentRoleDefaultPolicy: Type: AWS::IAM::Policy Properties: PolicyDocument: Statement: - Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents Effect: Allow Resource: - Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":logs:" - Ref: AWS::Region - ":" - Ref: AWS::AccountId - :log-group:/aws/codebuild/Deploy*Project* - Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":logs:" - Ref: AWS::Region - ":" - Ref: AWS::AccountId - :log-group:/aws/codebuild/Deploy*Project:* - Action: - codebuild:CreateReportGroup - codebuild:CreateReport - codebuild:UpdateReport - codebuild:BatchPutTestCases Effect: Allow Resource: Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":codebuild:" - Ref: AWS::Region - ":" - Ref: AWS::AccountId - :report-group/Deploy*Project - -* - Action: - proton:UpdateServiceInstance - proton:GetServiceInstance Effect: Allow Resource: "*" - Action: - s3:GetObject* - s3:GetBucket* - s3:List* Effect: Allow Resource: - Fn::GetAtt: - PipelineArtifactsBucket - Arn - Fn::Join: - "" - - Fn::GetAtt: - PipelineArtifactsBucket - Arn - /* - Action: - kms:Decrypt - kms:DescribeKey Effect: Allow Resource: Fn::GetAtt: - PipelineArtifactsBucketEncryptionKey - Arn - Action: - kms:Decrypt - kms:Encrypt - kms:ReEncrypt* - kms:GenerateDataKey* Effect: Allow Resource: Fn::GetAtt: - PipelineArtifactsBucketEncryptionKey - Arn Version: "2012-10-17" PolicyName: DeploymentRoleDefaultPolicy Roles: - Ref: DeploymentRole PipelineArtifactsBucketEncryptionKey: Type: AWS::KMS::Key Properties: KeyPolicy: Statement: - Action: - kms:Create* - kms:Describe* - kms:Enable* - kms:List* - kms:Put* - kms:Update* - kms:Revoke* - kms:Disable* - kms:Get* - kms:Delete* - kms:ScheduleKeyDeletion - kms:CancelKeyDeletion - kms:GenerateDataKey - kms:TagResource - kms:UntagResource Effect: Allow Principal: AWS: Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":iam::" - Ref: AWS::AccountId - :root Resource: "*" - Action: - kms:Decrypt - kms:DescribeKey - kms:Encrypt - kms:ReEncrypt* - kms:GenerateDataKey* Effect: Allow Principal: AWS: Fn::GetAtt: - PipelineRole - Arn Resource: "*" - Action: - kms:Decrypt - kms:DescribeKey - kms:Encrypt - kms:ReEncrypt* - kms:GenerateDataKey* Effect: Allow Principal: AWS: Fn::GetAtt: - PublishRole - Arn Resource: "*" - Action: - kms:Decrypt - kms:Encrypt - kms:ReEncrypt* - kms:GenerateDataKey* Effect: Allow Principal: AWS: Fn::GetAtt: - PublishRole - Arn Resource: "*" - Action: - kms:Decrypt - kms:DescribeKey Effect: Allow Principal: AWS: Fn::GetAtt: - DeploymentRole - Arn Resource: "*" - Action: - kms:Decrypt - kms:Encrypt - kms:ReEncrypt* - kms:GenerateDataKey* Effect: Allow Principal: AWS: Fn::GetAtt: - DeploymentRole - Arn Resource: "*" Version: "2012-10-17" UpdateReplacePolicy: Delete DeletionPolicy: Delete PipelineArtifactsBucket: Type: AWS::S3::Bucket Properties: BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: KMSMasterKeyID: Fn::GetAtt: - PipelineArtifactsBucketEncryptionKey - Arn SSEAlgorithm: aws:kms PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true UpdateReplacePolicy: Retain DeletionPolicy: Retain PipelineArtifactsBucketEncryptionKeyAlias: Type: AWS::KMS::Alias Properties: AliasName: 'alias/codepipeline-encryption-key-{{ service.name }}' # resource parameter TargetKeyId: Fn::GetAtt: - PipelineArtifactsBucketEncryptionKey - Arn UpdateReplacePolicy: Delete DeletionPolicy: Delete PipelineRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Action: sts:AssumeRole Effect: Allow Principal: Service: codepipeline.amazonaws.com Version: "2012-10-17" PipelineRoleDefaultPolicy: Type: AWS::IAM::Policy Properties: PolicyDocument: Statement: - Action: - s3:GetObject* - s3:GetBucket* - s3:List* - s3:DeleteObject* - s3:PutObject* - s3:Abort* Effect: Allow Resource: - Fn::GetAtt: - PipelineArtifactsBucket - Arn - Fn::Join: - "" - - Fn::GetAtt: - PipelineArtifactsBucket - Arn - /* - Action: - kms:Decrypt - kms:DescribeKey - kms:Encrypt - kms:ReEncrypt* - kms:GenerateDataKey* Effect: Allow Resource: Fn::GetAtt: - PipelineArtifactsBucketEncryptionKey - Arn - Action: codestar-connections:* Effect: Allow Resource: "*" - Action: sts:AssumeRole Effect: Allow Resource: Fn::GetAtt: - PipelineBuildCodePipelineActionRole - Arn - Action: sts:AssumeRole Effect: Allow Resource: Fn::GetAtt: - PipelineDeployCodePipelineActionRole - Arn Version: "2012-10-17" PolicyName: PipelineRoleDefaultPolicy Roles: - Ref: PipelineRole Pipeline: Type: AWS::CodePipeline::Pipeline Properties: RoleArn: Fn::GetAtt: - PipelineRole - Arn Stages: - Actions: - ActionTypeId: Category: Source Owner: AWS Provider: CodeStarSourceConnection Version: "1" Configuration: ConnectionArn: '{{ service.repository_connection_arn }}' # resource parameter FullRepositoryId: '{{ service.repository_id }}' # resource parameter BranchName: '{{ service.branch_name }}' # resource parameter Name: Checkout OutputArtifacts: - Name: Artifact_Source_Checkout RunOrder: 1 Name: Source - Actions: - ActionTypeId: Category: Build Owner: AWS Provider: CodeBuild Version: "1" Configuration: ProjectName: Ref: BuildProject InputArtifacts: - Name: Artifact_Source_Checkout Name: Build OutputArtifacts: - Name: BuildOutput RoleArn: Fn::GetAtt: - PipelineBuildCodePipelineActionRole - Arn RunOrder: 1 Name: Build {%- for service_instance in service_instances %} - Actions: - ActionTypeId: Category: Build Owner: AWS Provider: CodeBuild Version: "1" Configuration: ProjectName: Ref: Deploy{{loop.index}}Project InputArtifacts: - Name: BuildOutput Name: Deploy RoleArn: Fn::GetAtt: - PipelineDeployCodePipelineActionRole - Arn RunOrder: 1 Name: 'Deploy{{service_instance.name}}' # resource parameter {%- endfor %} ArtifactStore: EncryptionKey: Id: Fn::GetAtt: - PipelineArtifactsBucketEncryptionKey - Arn Type: KMS Location: Ref: PipelineArtifactsBucket Type: S3 DependsOn: - PipelineRoleDefaultPolicy - PipelineRole PipelineBuildCodePipelineActionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Action: sts:AssumeRole Effect: Allow Principal: AWS: Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":iam::" - Ref: AWS::AccountId - :root Version: "2012-10-17" PipelineBuildCodePipelineActionRoleDefaultPolicy: Type: AWS::IAM::Policy Properties: PolicyDocument: Statement: - Action: - codebuild:BatchGetBuilds - codebuild:StartBuild - codebuild:StopBuild Effect: Allow Resource: Fn::GetAtt: - BuildProject - Arn Version: "2012-10-17" PolicyName: PipelineBuildCodePipelineActionRoleDefaultPolicy Roles: - Ref: PipelineBuildCodePipelineActionRole PipelineDeployCodePipelineActionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Action: sts:AssumeRole Effect: Allow Principal: AWS: Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":iam::" - Ref: AWS::AccountId - :root Version: "2012-10-17" PipelineDeployCodePipelineActionRoleDefaultPolicy: Type: AWS::IAM::Policy Properties: PolicyDocument: Statement: - Action: - codebuild:BatchGetBuilds - codebuild:StartBuild - codebuild:StopBuild Effect: Allow Resource: Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":codebuild:" - Ref: AWS::Region - ":" - Ref: AWS::AccountId - ":project/Deploy*" Version: "2012-10-17" PolicyName: PipelineDeployCodePipelineActionRoleDefaultPolicy Roles: - Ref: PipelineDeployCodePipelineActionRole Outputs: PipelineEndpoint: Description: The URL to access the pipeline Value: !Sub "https://${AWS::Region}.console.aws.amazon.com/codesuite/codepipeline/pipelines/${Pipeline}/view?region=${AWS::Region}"