

End of support notice: On October 7, 2026, AWS will end support for AWS Proton. After October 7, 2026, you will no longer be able to access the AWS Proton console or AWS Proton resources. Your deployed infrastructure will remain intact. For more information, see [AWS Proton Service Deprecation and Migration Guide](https://docs.aws.amazon.com/proton/latest/userguide/proton-end-of-support.html).

# Authoring templates and creating bundles for AWS Proton
<a name="ag-template-authoring"></a>

AWS Proton provisions resources for you based on infrastructure as code (IaC) files. You describe infrastructure in reusable IaC files. To make the files reusable for different environments and applications, you author them as *templates*, define input parameters, and use these parameters in IaC definitions. When you later create a provisioning resource (environment, service instance, or component), AWS Proton uses a rendering engine, which combines input values with a template to create an IaC file that is ready to provision.

Administrators author most templates as *template bundles*, and then upload and register them into AWS Proton. The remainder of this page discusses these AWS Proton template bundles. *Directly defined components* are an exception—developers create them and provide IaC template files directly. For more information about components, see [AWS Proton components](ag-components.md).

**Topics**
+ [Template bundles](#ag-template-bundles)
+ [AWS Proton parameters](parameters.md)
+ [AWS Proton infrastructure as code files](ag-infrastructure-tmp-files.md)
+ [Schema file](ag-schema.md)
+ [Wrap up template files for AWS Proton](ag-wrap-up.md)
+ [Template bundle considerations](template-considerations.md)

## Template bundles
<a name="ag-template-bundles"></a>

As an administrator, you [create and register templates](template-create.md) with AWS Proton. You use these templates to create environments and services. When you create a service, AWS Proton provisions and deploys service instances to selected environments. For more information, see [AWS Proton for platform teams](Welcome.md#ag-admin).

To create and register a template in AWS Proton, you upload a template bundle that contains the infrastructure as code (IaC) files that AWS Proton needs to provision and environment or service.

A *template bundle* contains the following:
+ An [Infrastructure as code (IaC) file](ag-infrastructure-tmp-files.md) with a [manifest YAML file](ag-wrap-up.md) that lists the *IaC file*.
+ A [schema YAML file](ag-schema.md) for your IaC file input parameter definitions.

A CloudFormation environment template bundle contains one IaC file.

A CloudFormation service template bundle contains one IaC file for service instance definitions and another optional IaC file for a pipeline definition.

Terraform environment and service template bundles can contain multiple IaC files each.

AWS Proton requires an input parameter schema file. When you use AWS CloudFormation to create your IaC files, you use [Jinja](https://jinja.palletsprojects.com/en/2.11.x/) syntax to reference your input parameters. AWS Proton provides parameter namespaces that you can use to reference [parameters](parameters.md) in your IaC files.

The following diagram shows an example of steps that you can take to create a *template* for AWS Proton.

![\[A diagram that describes a process of how to create a template bundle for a set of AWS Proton infrastructure resources.\]](http://docs.aws.amazon.com/proton/latest/userguide/images/bundles.png)


 ![\[Red circle with the number 1 inside, typically used as a notification icon.\]](http://docs.aws.amazon.com/proton/latest/userguide/images/label-one.png) Identify [input parameters](parameters.md).

 ![\[Number 2 icon in a pink circle.\]](http://docs.aws.amazon.com/proton/latest/userguide/images/label-two.png) Create a [schema file](ag-schema.md) to define your input parameters.

 ![\[Pink square icon with a white exclamation mark inside a circle.\]](http://docs.aws.amazon.com/proton/latest/userguide/images/label-three.png) Create [IaC files](ag-infrastructure-tmp-files.md) that reference your input parameters. You can reference environment IaC file *outputs* as *inputs* for your service IaC files.

 ![\[Number 4 in a red circle icon, commonly used to indicate a notification count.\]](http://docs.aws.amazon.com/proton/latest/userguide/images/label-four.png) [Register a template version](template-create.md) with AWS Proton and upload your template bundle.

# AWS Proton parameters
<a name="parameters"></a>

You can define and use parameters in your infrastructure as code (IaC) files to make them flexible and re-usable. You read a parameter value in your IaC files by referring to the parameter's name in the AWS Proton *parameter namespace*. AWS Proton injects parameter values into the rendered IaC files that it generates during resource provisioning. To process AWS CloudFormation IaC parameters, AWS Proton uses [Jinja](https://jinja.palletsprojects.com/en/2.11.x/). To process Terraform IaC parameters, AWS Proton generates a Terraform parameter value file and relies on the parametrization ability built into HCL.

With [CodeBuild provisioning](ag-works-prov-methods.md#ag-works-prov-methods-codebuild), AWS Proton generates an input file that your code can import. The file is a JSON or HCL file, depending on a property in your template's manifest. For more information, see [CodeBuild provisioning parameter details and examples](parameters-codebuild.md).

You can refer to parameters in your environment, service, and component IaC files or provisioning code with the following requirements:
+ The length of each parameter name doesn't exceed 100 characters.
+ The length of the parameter namespace and resource name combined doesn't exceed the character limit for the resource name.

AWS Proton provisioning fails if these quotas are exceeded.

## Parameter types
<a name="param-name-types"></a>

The following parameter types are available to you for reference in AWS Proton IaC files:

**Input parameter**  
Environments and service instances can take input parameters that you define in a [schema file](ag-schema.md) that you associate with the environment or service template. You can refer to a resource's input parameters in the resource's IaC file. Component IaC files can refer to input parameters of the service instance that the component is attached to.  
AWS Proton checks input parameter names against your schema file, and matches them with the parameters that are referenced in your IaC files to inject the input values that you provide in a spec file during resource provisioning.

**Output parameter**  
You can define outputs in any of your IaC files. An output can be, for example, a name, ID, or ARN of one of the resources that the template provisions, or it can be a way to pass through one of the template's inputs. You can refer to these outputs in IaC files of other resources.  
In CloudFormation IaC files,define output parameters in the `Outputs:` block. In a Terraform IaC file, define each output parameter using an `output` statement.

**Resource parameter**  
AWS Proton automatically creates AWS Proton resource parameters. These parameters expose properties of the AWS Proton resource object. An example of a resource parameter is `environment.name`.

## Using AWS Proton parameters in your IaC files
<a name="param-name-spaces"></a>

To read a parameter value in an IaC file, you refer to the parameter's name in the AWS Proton parameter namespace. For AWS CloudFormation IaC files, you use *Jinja* syntax and surround the parameter with pairs of curly braces and quotation marks.

The following table shows the reference syntax for each supported template language, with an example.


| Template language | Syntax | Example: environment input named "VPC" | 
| --- | --- | --- | 
|  CloudFormation  |  `"{{ parameter-name }}"`  |  `"{{ environment.inputs.VPC }}"`  | 
|  Terraform  |  `var.parameter-name`  |  `var.environment.inputs.VPC` [Generated Terraform variable definitions](ag-infrastructure-tmp-files-terraform.md#compiled-tform)  | 

**Note**  
If you use [CloudFormation dynamic parameters](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html) in your IaC file, you must [escape them](https://jinja.palletsprojects.com/en/2.11.x/templates/#escaping) to prevent Jinja misinterpretation errors. For more information, see [Troubleshooting AWS Proton](ag-troubleshooting.md)

The following table lists namespace names for all AWS Proton resource parameters. Each template file type can use a different subset of the parameter namespace.

[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/proton/latest/userguide/parameters.html)

For more information and examples, see the subtopics about parameters in IaC template files for different resource types and template languages.

**Topics**
+ [Parameter types](#param-name-types)
+ [Using AWS Proton parameters in your IaC files](#param-name-spaces)
+ [Environment CloudFormation IaC file parameter details and examples](env-parameters.md)
+ [Service CloudFormation IaC file parameter details and examples](svc-parameters.md)
+ [Component CloudFormation IaC file parameter details and examples](comp-parameters.md)
+ [Parameter filters for CloudFormation IaC files](parameter-filters.md)
+ [CodeBuild provisioning parameter details and examples](parameters-codebuild.md)
+ [Terraform infrastructure as code (IaC) file parameter details and examples](env-parameters-tform.md)

# Environment CloudFormation IaC file parameter details and examples
<a name="env-parameters"></a>

You can define and reference parameters in your environment infrastructure as code (IaC) files. For a detailed description of AWS Proton parameters, parameter types, the parameter namespace, and how to use parameters in your IaC files, see [AWS Proton parameters](parameters.md).

## Define environment parameters
<a name="env-parameters.define"></a>

You can define both input and output parameters for environment IaC files.
+ **Input parameters** – Define environment input parameters in your [schema file](ag-schema.md).

  The following list includes examples of environment input parameters for typical use cases.
  + VPC CIDR values
  + Load balancer settings
  + Database settings
  + A health check timeout

  As an administrator, you can provide values for input parameters when you [create an environment](ag-create-env.md):
  + Use the console to fill out a schema-based form that AWS Proton provides.
  + Use the CLI to provide a spec that includes the values.
+ **Output parameters** – Define environment outputs in your environment IaC files. You can then refer to these outputs in IaC files of other resources.

## Read parameter values in environment IaC files
<a name="env-parameters.refer"></a>

You can read parameters related to the environment in environment IaC files. You read a parameter value by referencing the parameter's name in the AWS Proton parameter namespace.
+ **Input parameters** – Read an environment input value by referencing `environment.inputs.input-name`.
+ **Resource parameters** – Read AWS Proton resource parameters by referencing names such as `environment.name`.

**Note**  
No output parameters of other resources are available to environment IaC files.

## Example environment and service IaC files with parameters
<a name="env-parameters.example"></a>

The following example demonstrates parameter definition and reference in an environment IaC file. The example then shows how environment output parameters defined in the environment IaC file can be referenced in a service IaC file.

**Example Environment CloudFormation IaC file**  
Note the following in this example:  
+ The `environment.inputs.` namespace refers to environment input parameters.
+ The Amazon EC2 Systems Manager (SSM) parameter `StoreInputValue` concatenates the environment inputs.
+ The `MyEnvParameterValue` output exposes the same input parameter concatenation as an output parameter. Three additional output parameters also expose the input parameters individually.
+ Six additional output parameters expose resources that the environment provisions.

```
Resources:
  StoreInputValue:
    Type: AWS::SSM::Parameter
    Properties:
      Type: String
      Value: "{{ environment.inputs.my_sample_input }} {{ environment.inputs.my_other_sample_input}} {{ environment.inputs.another_optional_input }}"
              # input parameter references

# These output values are available to service infrastructure as code files as outputs, when given the 
# the 'environment.outputs' namespace, for example, service_instance.environment.outputs.ClusterName.
Outputs:
  MyEnvParameterValue:                                        # output definition
    Value: !GetAtt StoreInputValue.Value
  MySampleInputValue:                                         # output definition
    Value: "{{ environment.inputs.my_sample_input }}"         #   input parameter reference
  MyOtherSampleInputValue:                                    # output definition
    Value: "{{ environment.inputs.my_other_sample_input }}"   #   input parameter reference
  AnotherOptionalInputValue:                                  # output definition
    Value: "{{ environment.inputs.another_optional_input }}"  #   input parameter reference
  ClusterName:                                                # output definition
    Description: The name of the ECS cluster
    Value: !Ref 'ECSCluster'                                  #   provisioned resource
  ECSTaskExecutionRole:                                       # output definition
    Description: The ARN of the ECS role
    Value: !GetAtt 'ECSTaskExecutionRole.Arn'                 #   provisioned resource
  VpcId:                                                      # output definition
    Description: The ID of the VPC that this stack is deployed in
    Value: !Ref 'VPC'                                         #   provisioned resource
  PublicSubnetOne:                                            # output definition
    Description: Public subnet one
    Value: !Ref 'PublicSubnetOne'                             #   provisioned resource
  PublicSubnetTwo:                                            # output definition
    Description: Public subnet two
    Value: !Ref 'PublicSubnetTwo'                             #   provisioned resource
  ContainerSecurityGroup:                                     # output definition
    Description: A security group used to allow Fargate containers to receive traffic
    Value: !Ref 'ContainerSecurityGroup'                      #   provisioned resource
```

**Example Service CloudFormation IaC file**  
The `environment.outputs.` namespace refers to environment outputs from an environment IaC file. For example, the name `environment.outputs.ClusterName` reads the value of the `ClusterName` environment output parameter.  

```
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}}' # resource parameter
      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 reference to an environment infrastructure code file
      TaskRoleArn: !Ref "AWS::NoValue"
      ContainerDefinitions:
        - Name: '{{service_instance.name}}'  # resource parameter
          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}}' # resource parameter
              awslogs-region: !Ref 'AWS::Region'
              awslogs-stream-prefix: '{{service_instance.name}}' # resource parameter

  # 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}}'  # resource parameter
      Cluster: '{{environment.outputs.ClusterName}}' # output reference to 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 reference to an environment infrastructure as code file
          Subnets:
            - '{{environment.outputs.PublicSubnetOne}}' # output reference to an environment infrastructure as code file
            - '{{environment.outputs.PublicSubnetTwo}}' # output reference to an environment infrastructure as code file
      TaskDefinition: !Ref 'TaskDefinition'
      LoadBalancers:
        - ContainerName: '{{service_instance.name}}'  # resource parameter
          ContainerPort: '{{service_instance.inputs.port}}' # input parameter
          TargetGroupArn: !Ref 'TargetGroup'
[...]
```

# Service CloudFormation IaC file parameter details and examples
<a name="svc-parameters"></a>

You can define and reference parameters in your service and pipeline infrastructure as code (IaC) files. For a detailed description of AWS Proton parameters, parameter types, the parameter namespace, and how to use parameters in your IaC files, see [AWS Proton parameters](parameters.md).

## Define service parameters
<a name="svc-parameters.define"></a>

You can define both input and output parameters for service IaC files.
+ **Input parameters** – Define service instance input parameters in your [schema file](ag-schema.md).

  The following list includes examples of service input parameters for typical use cases.
  + Port
  + Task size
  + Image
  + Desired count
  + Docker file
  + Unit test command

  You provide values for input parameters when you [create a service](ag-create-svc.md):
  + Use the console to fill out a schema-based form that AWS Proton provides.
  + Use the CLI to provide a spec that includes the values.
+ **Output parameters** – Define service instance outputs in your service IaC files. You can then refer to these outputs in IaC files of other resources.

## Read parameter values in service IaC files
<a name="svc-parameters.refer"></a>

You can read parameters related to the service and to other resources in service IaC files. You read a parameter value by referencing the parameter's name in the AWS Proton parameter namespace.
+ **Input parameters** – Read a service instance input value by referencing `service_instance.inputs.input-name`.
+ **Resource parameters** – Read AWS Proton resource parameters by referencing names such as `service.name`, `service_instance.name`, and `environment.name`.
+ **Output parameters** – Read outputs of other resources by referencing `environment.outputs.output-name` or `service_instance.components.default.outputs.output-name`.

## Example service IaC file with parameters
<a name="svc-parameters.example"></a>

The following example is a snippet from a service CloudFormation IaC file. The `environment.outputs.` namespace refers to outputs from the environment IaC file. The `service_instance.inputs.` namespace refers to service instance input parameters. The `service_instance.name` property refers to an AWS Proton resource parameter.

```
Resources:
  StoreServiceInstanceInputValue:
    Type: AWS::SSM::Parameter
    Properties:
      Type: String
      Value: "{{ service.name }} {{ service_instance.name }} {{ service_instance.inputs.my_sample_service_instance_required_input }} {{ service_instance.inputs.my_sample_service_instance_optional_input }} {{ environment.outputs.MySampleInputValue }} {{ environment.outputs.MyOtherSampleInputValue }}"
              #  resource parameter references               # input parameter references                                                                                                                    # output references to an environment infrastructure as code file
Outputs:
  MyServiceInstanceParameter:                                                         # output definition
    Value: !Ref StoreServiceInstanceInputValue 
  MyServiceInstanceRequiredInputValue:                                                # output definition
    Value: "{{ service_instance.inputs.my_sample_service_instance_required_input }}"  # input parameter reference
  MyServiceInstanceOptionalInputValue:                                                # output definition
    Value: "{{ service_instance.inputs.my_sample_service_instance_optional_input }}"  # input parameter reference
  MyServiceInstancesEnvironmentSampleOutputValue:                                     # output definition
    Value: "{{ environment.outputs.MySampleInputValue }}"                             # output reference to an environment IaC file
  MyServiceInstancesEnvironmentOtherSampleOutputValue:                                # output definition
    Value: "{{ environment.outputs.MyOtherSampleInputValue }}"                        # output reference to an environment IaC file
```

# Component CloudFormation IaC file parameter details and examples
<a name="comp-parameters"></a>

You can define and reference parameters in your component infrastructure as code (IaC) files. For a detailed description of AWS Proton parameters, parameter types, the parameter namespace, and how to use parameters in your IaC files, see [AWS Proton parameters](parameters.md). For more information about components, see [AWS Proton components](ag-components.md).

## Define component output parameters
<a name="comp-parameters.define"></a>

You can define output parameters in your component IaC files. You can then refer to these outputs in service IaC files.

**Note**  
You can't define inputs for component IaC files. Attached components can get inputs from the service instance that they are attached to. Detached components don't have inputs.

## Read parameter values in component IaC files
<a name="comp-parameters.refer"></a>

You can read parameters related to the component and to other resources in component IaC files. You read a parameter value by referencing the parameter's name in the AWS Proton parameter namespace.
+ **Input parameters** – Read an attached service instance input value by referencing `service_instance.inputs.input-name`.
+ **Resource parameters** – Read AWS Proton resource parameters by referencing names such as `component.name`, `service.name`, `service_instance.name`, and `environment.name`.
+ **Output parameters** – Read environment outputs by referencing `environment.outputs.output-name`.

## Example component and service IaC files with parameters
<a name="comp-parameters.example"></a>

The following example shows a component that provisions an Amazon Simple Storage Service (Amazon S3) bucket and related access policy and exposes the Amazon Resource Names (ARNs) of both resources as component outputs. A service IaC template adds the component outputs as container environment variables of an Amazon Elastic Container Service (Amazon ECS) task to make the outputs available to code running in the container, and adds the bucket access policy to the task's role. The bucket name is based on the names of the environment, service, service instance, and component, meaning that the bucket is coupled with a specific instance of the component template extending a specific service instance. Developers can create multiple custom components based on this component template, to provision Amazon S3 buckets for different service instances and functional needs.

The example shows how you use Jinja `{{ ... }}` syntax to refer to component and other resource parameters in your service IaC file. You can use `{% if ... %}` statements to add blocks of statements only when a component is attached to the service instance. The `proton_cfn_*` keywords are *filters* that you can use to sanitize and format output parameter values. For more information about filters, see [Parameter filters for CloudFormation IaC files](parameter-filters.md).

 As an administrator, you author the service IaC template file.

**Example service CloudFormation IaC file using a component**  

```
# service/instance_infrastructure/cloudformation.yaml

Resources: 
  TaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      TaskRoleArn: !Ref TaskRole
      ContainerDefinitions:
        - Name: '{{service_instance.name}}'
          # ...
          {% if service_instance.components.default.outputs | length > 0 %}
          Environment:
            {{ service_instance.components.default.outputs |
                proton_cfn_ecs_task_definition_formatted_env_vars }}
          {% endif %}

  # ...

  TaskRole:
    Type: AWS::IAM::Role
    Properties:
      # ...
      ManagedPolicyArns:
        - !Ref BaseTaskRoleManagedPolicy
        {{ service_instance.components.default.outputs
            | proton_cfn_iam_policy_arns }}

  # Basic permissions for the task
  BaseTaskRoleManagedPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      # ...
```

As a developer, you author the component IaC template file.

**Example component CloudFormation IaC file**  

```
# cloudformation.yaml

# A component that defines an S3 bucket and a policy for accessing the bucket.
Resources:
  S3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: '{{environment.name}}-{{service.name}}-{{service_instance.name}}-{{component.name}}'
  S3BucketAccessPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      PolicyDocument:
        Version: "2012-10-17"		 	 	 
        Statement:
          - Effect: Allow
            Action:
              - 's3:Get*'
              - 's3:List*'
              - 's3:PutObject'
            Resource: !GetAtt S3Bucket.Arn
Outputs:
  BucketName:
    Description: "Bucket to access"
    Value: !GetAtt S3Bucket.Arn
  BucketAccessPolicyArn:
    Value: !Ref S3BucketAccessPolicy
```

When AWS Proton renders an CloudFormation template for your service instance and replaces all parameters with actual values, the template might look like the following file.

**Example service instance CloudFormation rendered IaC file**  

```
Resources: 
  TaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      TaskRoleArn: !Ref TaskRole
      ContainerDefinitions:
        - Name: '{{service_instance.name}}'
          # ...
          Environment:
            - Name: BucketName
              Value: arn:aws:s3:us-east-1:123456789012:environment_name-service_name-service_instance_name-component_name
            - Name: BucketAccessPolicyArn
              Value: arn:aws:iam::123456789012:policy/cfn-generated-policy-name
  # ...

  TaskRole:
    Type: AWS::IAM::Role
    Properties:
      # ...
      ManagedPolicyArns:
        - !Ref BaseTaskRoleManagedPolicy
        - arn:aws:iam::123456789012:policy/cfn-generated-policy-name

  # Basic permissions for the task
  BaseTaskRoleManagedPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      # ...
```

# Parameter filters for CloudFormation IaC files
<a name="parameter-filters"></a>

When you make references to [AWS Proton parameters](parameters.md) in your AWS CloudFormation IaC files, you can use Jinja modifiers known as *filters* to validate, filter, and format parameter values before they get inserted into the rendered template. Filter validations are particularly useful when referring to [component](ag-components.md) output parameters, because component creation and attachment are done by developers, and an administrator using component outputs in a service instance template might want to verify their existence and validity. However, you can use filters in any Jinja IaC file.

The following sections describe and define the available parameter filters, and provide examples. AWS Proton defines most of these filters. The `default` filter is a Jinja built-in filter.

## Format environment properties for Amazon ECS tasks
<a name="parameter-filters.proton.cfn-ecs"></a>

**Declaration**

```
dict → proton_cfn_ecs_task_definition_formatted_env_vars (raw: boolean = True) → YAML list of dicts
```

**Description**

This filter formats a list of outputs to be used in an [Environment property](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-containerdefinitions.html#cfn-ecs-taskdefinition-containerdefinition-environment) in the `ContainerDefinition` section of an Amazon Elastic Container Service (Amazon ECS) task definition.

Set `raw` to `False` to also validate the parameter value. In this case, the value is required to match the regular expression `^[a-zA-Z0-9_-]*$`. If the value fails this validation, template rendering fails.

### Example
<a name="parameter-filters.proton.cfn-ecs.example"></a>

With the following custom component template:

```
Resources:
  # ...
Outputs:
  Output1:
    Description: "Example component output 1"
    Value: hello
  Output2:
    Description: "Example component output 2"
    Value: world
```

And the following service template:

```
Resources:
  TaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      # ...
      ContainerDefinitions:
        - Name: MyServiceName
          # ...
          Environment:
            {{ service_instance.components.default.outputs
              | proton_cfn_ecs_task_definition_formatted_env_vars }}
```

The rendered service template is as follows:

```
Resources:
  TaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      # ...
      ContainerDefinitions:
        - Name: MyServiceName
          # ...
          Environment:
            - Name: Output1
              Value: hello
            - Name: Output2
              Value: world
```

## Format environment properties for Lambda functions
<a name="parameter-filters.proton.cfn-lambda"></a>

**Declaration**

```
dict → proton_cfn_lambda_function_formatted_env_vars (raw: boolean = True) → YAML dict
```

**Description**

This filter formats a list of outputs to be used in an [Environment property](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-environment) in the `Properties` section of an AWS Lambda function definition.

Set `raw` to `False` to also validate the parameter value. In this case, the value is required to match the regular expression `^[a-zA-Z0-9_-]*$`. If the value fails this validation, template rendering fails.

### Example
<a name="parameter-filters.proton.cfn-lambda.example"></a>

With the following custom component template:

```
Resources:
  # ...
Outputs:
  Output1:
    Description: "Example component output 1"
    Value: hello
  Output2:
    Description: "Example component output 2"
    Value: world
```

And the following service template:

```
Resources:
  Lambda:
    Type: AWS::Lambda::Function
    Properties:
      Environment:
        Variables:
          {{ service_instance.components.default.outputs
            | proton_cfn_lambda_function_formatted_env_vars }}
```

The rendered service template is as follows:

```
Resources:
  Lambda:
    Type: AWS::Lambda::Function
    Properties:
      Environment:
        Variables:
          Output1: hello
          Output2: world
```

## Extract IAM policy ARNs to include in IAM roles
<a name="parameter-filters.proton.cfn-policy-arns"></a>

**Declaration**

```
dict → proton_cfn_iam_policy_arns → YAML list
```

**Description**

This filter formats a list of outputs to be used in a [ManagedPolicyArns property](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html#cfn-iam-role-managepolicyarns) in the `Properties` section of an AWS Identity and Access Management (IAM) role definition. The filter uses the regular expression `^arn:[a-zA-Z-]+:iam::\d{12}:policy/` to extract valid IAM policy ARNs from the list of output parameters. You can use this filter to append policies in output parameter values to an IAM role definition in a service template.

### Example
<a name="parameter-filters.proton.cfn-policy-arns.example"></a>

With the following custom component template:

```
Resources:
  # ...
  ExamplePolicy1:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      # ...
  ExamplePolicy2:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      # ...

  # ...

Outputs:
  Output1:
    Description: "Example component output 1"
    Value: hello
  Output2:
    Description: "Example component output 2"
    Value: world
  PolicyArn1:
    Description: "ARN of policy 1"
    Value: !Ref ExamplePolicy1
  PolicyArn2:
    Description: "ARN of policy 2"
    Value: !Ref ExamplePolicy2
```

And the following service template:

```
Resources: 

  # ...

  TaskRole:
    Type: AWS::IAM::Role
    Properties:
      # ...
      ManagedPolicyArns:
        - !Ref BaseTaskRoleManagedPolicy
        {{ service_instance.components.default.outputs
            | proton_cfn_iam_policy_arns }}

  # Basic permissions for the task
  BaseTaskRoleManagedPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      # ...
```

The rendered service template is as follows:

```
Resources: 

  # ...

  TaskRole:
    Type: AWS::IAM::Role
    Properties:
      # ...
      ManagedPolicyArns:
        - !Ref BaseTaskRoleManagedPolicy
        - arn:aws:iam::123456789012:policy/cfn-generated-policy-name-1
        - arn:aws:iam::123456789012:policy/cfn-generated-policy-name-2

  # Basic permissions for the task
  BaseTaskRoleManagedPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      # ...
```

## Sanitize property values
<a name="parameter-filters.proton.cfn-sanitize"></a>

**Declaration**

```
string → proton_cfn_sanitize → string
```

**Description**

This is a general purpose filter. Use it to validate the safety of a parameter value. The filter validates that the value either matches the regular expression `^[a-zA-Z0-9_-]*$` or is a valid Amazon Resource Name (ARN). If the value fails this validation, template rendering fails.

### Example
<a name="parameter-filters.proton.cfn-sanitize.example"></a>

With the following custom component template:

```
Resources:
  # ...
Outputs:
  Output1:
    Description: "Example of valid output"
    Value: "This-is_valid_37"
  Output2:
    Description: "Example incorrect output"
    Value: "this::is::incorrect"
  SomeArn:
    Description: "Example ARN"
    Value: arn:aws:some-service::123456789012:some-resource/resource-name
```
+ The following reference in a service template:

  ```
  # ...
    {{ service_instance.components.default.outputs.Output1
      | proton_cfn_sanitize }}
  ```

  Renders as follows:

  ```
  # ...
    This-is_valid_37
  ```
+ The following reference in a service template:

  ```
  # ...
    {{ service_instance.components.default.outputs.Output2
      | proton_cfn_sanitize }}
  ```

  Results with the following rendering error:

  ```
  Illegal character(s) detected in "this::is::incorrect". Must match regex ^[a-zA-Z0-9_-]*$ or be a valid ARN
  ```
+ The following reference in a service template:

  ```
  # ...
    {{ service_instance.components.default.outputs.SomeArn
      | proton_cfn_sanitize }}
  ```

  Renders as follows:

  ```
  # ...
    arn:aws:some-service::123456789012:some-resource/resource-name
  ```

## Provide default values for nonexistent references
<a name="parameter-filters.proton.default"></a>

**Description**

The `default` filter provides a default value when a namespace reference doesn't exist. Use it to write robust templates that can render without failure even when the parameter you refer to is missing.

### Example
<a name="parameter-filters.default.example"></a>

The following reference in a service template causes template rendering to fail if the service instance doesn't have an attached directly defined (default) component, or if the attached component doesn't have an output named `test`.

```
# ...
  {{ service_instance.components.default.outputs.test }}
```

To avoid this issue, add the `default` filter.

```
# ...
  {{ service_instance.components.default.outputs.test | default("[optional-value]") }}
```

# CodeBuild provisioning parameter details and examples
<a name="parameters-codebuild"></a>

You can define parameters in your templates for CodeBuild-based AWS Proton resources and reference these parameters in your provisioning code. For a detailed description of AWS Proton parameters, parameter types, the parameter namespace, and how to use parameters in your IaC files, see [AWS Proton parameters](parameters.md).

**Note**  
You can use CodeBuild provisioning with environments and services. At this time you can't provision components this way.

## Input parameters
<a name="parameters-codebuild.input"></a>

When you create an AWS Proton resource, like an environment or a service, you provide values for input parameters that are defined in your template's [schema file](ag-schema.md). When the resource that you create uses [CodeBuild provisioning](ag-works-prov-methods.md#ag-works-prov-methods-codebuild), AWS Proton renders these input values into an input file. Your provisioning code can import and get parameter values from this file.

For an example of a CodeBuild templates, see [CodeBuild provisioning template bundle](ag-infrastructure-tmp-files-codebuild.md). For more information about manifest files, see [Wrap up template files for AWS Proton](ag-wrap-up.md).

The following example is a JSON input file generated during CodeBuild-based provisioning of a service instance.

### Example: using the AWS CDK with CodeBuild provisioning
<a name="parameters-codebuild.example"></a>

```
{
  "service_instance": {
    "name": "my-service-staging",
    "inputs": {
      "port": "8080",
      "task_size": "medium"
    }
  },
  "service": {
    "name": "my-service"
  },
  "environment": {
    "account_id": "123456789012",
    "name": "my-env-staging",
    "outputs": {
      "vpc-id": "hdh2323423"
    }
  }
}
```

## Output parameters
<a name="parameters-codebuild.output"></a>

To communicate resource provisioning outputs back to AWS Proton, your provisioning code can generate a JSON file named `proton-outputs.json` with values for output parameters defined in your template's [schema file](ag-schema.md). For example, the `cdk deploy` command has the `--outputs-file` argument that instructs the AWS CDK to generate a JSON file with provisioning outputs. If your resource uses the AWS CDK, specify the following command in your CodeBuild template manifest:

```
aws proton notify-resource-deployment-status-change
```

AWS Proton looks for this JSON file. If the file exists after your provisioning code successfully completes, AWS Proton reads output parameter values from it.

# Terraform infrastructure as code (IaC) file parameter details and examples
<a name="env-parameters-tform"></a>

You can include Terraform input variables in `variable.tf` files in your template bundle. You can also create a schema to create AWS Proton managed variables. AWS Proton creates variable `.tf files` from your schema file. For more information, see [Terraform IaC files](ag-infrastructure-tmp-files-terraform.md).

To reference your schema defined AWS Proton variables in your infrastructure `.tf files`, you use the AWS Proton namespaces shown in the *Parameters and namespaces for Terraform IaC* table. For example, you can use `var.environment.inputs.vpc_cidr`. Inside quotation marks, surround these variables with single brackets and add a dollar sign in front of the first brace (for example, `“${var.environment.inputs.vpc_cidr}”`).

The following example shows how to use namespaces to include AWS Proton parameters in an environment `.tf file`.

```
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.0"
    }
  }
  // This tells terraform to store the state file in s3 at the location
  // s3://terraform-state-bucket/tf-os-sample/terraform.tfstate
  backend "s3" {
    bucket = "terraform-state-bucket"
    key    = "tf-os-sample/terraform.tfstate"
    region = "us-east-1"
  }
}

// Configure the AWS Provider
provider "aws" {
  region = "us-east-1"
  default_tags {
    tags = var.proton_tags
  }
}

resource "aws_ssm_parameter" "my_ssm_parameter" {
  name  = "my_ssm_parameter"
  type  = "String"
  // Use the Proton environment.inputs. namespace
  value = var.environment.inputs.ssm_parameter_value
}
```

# AWS Proton infrastructure as code files
<a name="ag-infrastructure-tmp-files"></a>

The primary parts of the template bundle are *infrastructure as code (IaC) files* that define the infrastructure resources and properties that you want to provision. AWS CloudFormation and other infrastructure as code engines use these types of files to provision infrastructure resources.

**Note**  
An IaC file can also be used independently of template bundles, as a direct input to *directly defined components*. For more information about components, see [AWS Proton components](ag-components.md).

AWS Proton currently supports two types of IaC files:
+ *[CloudFormation](ag-infrastructure-tmp-files-cloudformation.md) files* – Used for *AWS-managed provisioning*. AWS Proton uses Jinja on top of the CloudFormation template file format for parametrization.
+ *[Terraform HCL](ag-infrastructure-tmp-files-terraform.md) files* – Used for *Self-managed provisioning*. HCL natively supports parametrization.

You can’t provision AWS Proton resources using a combination of provisioning methods. You must use one or the other. You can’t deploy an AWS-managed provisioning service to a self-managed provisioning environment, or vice versa.

For more information, see [How AWS Proton provisions infrastructure](ag-works-prov-methods.md), [AWS Proton environments](ag-environments.md), [AWS Proton services](ag-services.md), and [AWS Proton components](ag-components.md).

# CloudFormation IaC files
<a name="ag-infrastructure-tmp-files-cloudformation"></a>

Learn how to use AWS CloudFormation infrastructure as code files with AWS Proton. 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 CloudFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html) in *the CloudFormation User Guide*.

AWS Proton supports [AWS-managed provisioning](ag-works-prov-methods.md#ag-works-prov-methods-direct) for CloudFormation IaC.

## Start with your own existing infrastructure as code files
<a name="iac-tmp-files"></a>

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

The following CloudFormation examples, [Example 1](#ag-env-cfn-example), and [Example 2](#ag-svc-cfn-example), represent *your own existing* CloudFormation IaC files. CloudFormation can use these files to create two different CloudFormation stacks.

In [Example 1](#ag-env-cfn-example), 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](#ag-svc-cfn-example), 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.

### Example 1: CloudFormation IaC file
<a name="ag-env-cfn-example"></a>

```
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"
```

### Example 2: CloudFormation IaC file
<a name="ag-svc-cfn-example"></a>

```
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
<a name="proton-tmp-files"></a>

With slight modifications, you can use [Example 1](#ag-env-cfn-example) 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](#ag-proton-env-cfn-example)).

Instead of using the CloudFormation parameters, you use [Jinja](https://jinja.palletsprojects.com/en/2.11.x/templates/) syntax to reference parameters that you have defined in an [Open API](https://swagger.io/docs/specification/data-models/) based [schema file](ag-schema.md). 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.

### Example 3: AWS Proton environment infrastructure as code file
<a name="ag-proton-env-cfn-example"></a>

```
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](#ag-env-cfn-example) and [Example 3](#ag-proton-env-cfn-example) 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](#ag-proton-svc-cfn-example), the AWS Proton service IaC file corresponds with [Example 2](#ag-svc-cfn-example).

### Example 4: AWS Proton service instance IaC file
<a name="ag-proton-svc-cfn-example"></a>

```
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](#ag-proton-pipeline-cfn-example), the AWS Proton pipeline IaC file provisions the pipeline infrastructure to support the service instances provisioned by [Example 4](#ag-proton-svc-cfn-example).

### Example 5: AWS Proton service pipeline IaC file
<a name="ag-proton-pipeline-cfn-example"></a>

```
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}"
```

# CodeBuild provisioning template bundle
<a name="ag-infrastructure-tmp-files-codebuild"></a>

With CodeBuild provisioning, instead of using IaC templates to render IaC files and run them using an IaC provisioning engine, AWS Proton simply runs your shell commands. To do that, AWS Proton creates an AWS CodeBuild project for the environment, in the environment account, and starts a job to run your commands for each AWS Proton resource creation or update. When you author a template bundle, you provide a manifest that specifies infrastructure provisioning and deprovisioning commands, and any programs, scripts, and other files that these commands may need. Your commands can read inputs that AWS Proton provides, and are responsible for provisioning or deprovisioning infrastructure and generating output values.

The manifest also specifies how AWS Proton should render the input file that your code can input and get input values from. It can be rendered into JSON or HCL. For more information about input parameters, see [CodeBuild provisioning parameter details and examples](parameters-codebuild.md). For more information about manifest files, see [Wrap up template files for AWS Proton](ag-wrap-up.md).

**Note**  
You can use CodeBuild provisioning with environments and services. At this time you can't provision components this way.

## Example: using the AWS CDK with CodeBuild provisioning
<a name="ag-infrastructure-tmp-files-codebuild.example"></a>

As an example to using CodeBuild provisioning, you can include code that uses the AWS Cloud Development Kit (AWS CDK) to provision (*deploy*) and deprovision (*destroy*) AWS resources, and a manifest that installs the CDK and runs your CDK code.

The following sections list example files you can include in a CodeBuild provisioning template bundle that provisions an environment using the AWS CDK.

### Manifest
<a name="ag-infrastructure-tmp-files-codebuild.example.manifest"></a>

The following manifest file specifies CodeBuild provisioning, and includes the commands necessary to install and use the AWS CDK, output file processing, and reporting outputs back to AWS Proton.

**Example infrastructure/manifest.yaml**  

```
infrastructure:
  templates:
    - rendering_engine: codebuild
      settings:
        image: aws/codebuild/amazonlinux2-x86_64-standard:4.0
        runtimes:
          nodejs: 16
        provision:
          - npm install
          - npm run build
          - npm run cdk bootstrap
          - npm run cdk deploy -- --require-approval never --outputs-file proton-outputs.json
          - jq 'to_entries | map_values(.value) | add | to_entries | map({key:.key, valueString:.value})' < proton-outputs.json > outputs.json
          - aws proton notify-resource-deployment-status-change --resource-arn $RESOURCE_ARN --status IN_PROGRESS --outputs file://./outputs.json
        deprovision:
          - npm install
          - npm run build
          - npm run cdk destroy
        project_properties:
          VpcConfig:
            VpcId: "{{ environment.inputs.codebuild_vpc_id }}"
            Subnets: "{{ environment.inputs.codebuild_subnets }}"
            SecurityGroupIds: "{{ environment.inputs.codebuild_security_groups }}"
```

### Schema
<a name="ag-infrastructure-tmp-files-codebuild.example.schema"></a>

The following schema file defines parameters for the environment. Your AWS CDK code can refer to values of these parameters during deployment.

**Example schema/schema.yaml**  

```
schema:
  format:
    openapi: "3.0.0"
  environment_input_type: "MyEnvironmentInputType"
  types:
    MyEnvironmentInputType:
      type: object
      description: "Input properties for my environment"
      properties:
        my_sample_input:
          type: string
          description: "This is a sample input"
          default: "hello world"
        my_other_sample_input:
          type: string
          description: "Another sample input"
      required:
        - my_other_sample_input
```

### AWS CDK files
<a name="ag-infrastructure-tmp-files-codebuild.example.cdkcode"></a>

The following files are an example to a Node.js CDK project.

**Example infrastructure/package.json**  

```
{
  "name": "ProtonEnvironment",
  "version": "0.1.0",
  "bin": {
    "ProtonEnvironmente": "bin/ProtonEnvironment.js"
  },
  "scripts": {
    "build": "tsc",
    "watch": "tsc -w",
    "test": "jest",
    "cdk": "cdk"
  },
  "devDependencies": {
    "@types/jest": "^28.1.7",
    "@types/node": "18.7.6",
    "jest": "^28.1.3",
    "ts-jest": "^28.0.8",
    "aws-cdk": "2.37.1",
    "ts-node": "^10.9.1",
    "typescript": "~4.7.4"
  },
  "dependencies": {
    "aws-cdk-lib": "2.37.1",
    "constructs": "^10.1.77",
    "source-map-support": "^0.5.21"
  }
}
```

**Example infrastructure/tsconfig.json**  

```
{
  "compilerOptions": {
    "target": "ES2018",
    "module": "commonjs",
    "lib": [
      "es2018"
    ],
    "declaration": true,
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "noImplicitThis": true,
    "alwaysStrict": true,
    "noUnusedLocals": false,
    "noUnusedParameters": false,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": false,
    "inlineSourceMap": true,
    "inlineSources": true,
    "experimentalDecorators": true,
    "strictPropertyInitialization": false,
    "resolveJsonModule": true,
    "esModuleInterop": true,
    "typeRoots": [
      "./node_modules/@types"
    ]
  },
  "exclude": [
    "node_modules",
    "cdk.out"
  ]
}
```

**Example infrastructure/cdk.json**  

```
{
  "app": "npx ts-node --prefer-ts-exts bin/ProtonEnvironment.ts",
  "outputsFile": "proton-outputs.json",
  "watch": {
    "include": [
      "**"
    ],
    "exclude": [
      "README.md",
      "cdk*.json",
      "**/*.d.ts",
      "**/*.js",
      "tsconfig.json",
      "package*.json",
      "yarn.lock",
      "node_modules",
      "test"
    ]
  },
  "context": {
    "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true,
    "@aws-cdk/core:stackRelativeExports": true,
    "@aws-cdk/aws-rds:lowercaseDbIdentifier": true,
    "@aws-cdk/aws-lambda:recognizeVersionProps": true,
    "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true,
    "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
    "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
    "@aws-cdk/core:target-partitions": [
      "aws",
      "aws-cn"
    ]
  }
}
```

**Example infrastructure/bin/ProtonEnvironment.ts**  

```
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { ProtonEnvironmentStack } from '../lib/ProtonEnvironmentStack';

const app = new cdk.App();
new ProtonEnvironmentStack(app, 'ProtonEnvironmentStack', {});
```

**Example infrastructure/lib/ProtonEnvironmentStack.ts**  

```
import { Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as cdk from 'aws-cdk-lib';
import * as ssm from 'aws-cdk-lib/aws-ssm';
import input from '../proton-inputs.json';

export class ProtonEnvironmentStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, { ...props, stackName: process.env.STACK_NAME });

    const ssmParam = new ssm.StringParameter(this, "ssmParam", {
      stringValue: input.environment.inputs.my_sample_input,
      parameterName: `${process.env.STACK_NAME}-Param`,
      tier: ssm.ParameterTier.STANDARD
    })

    new cdk.CfnOutput(this, 'ssmParamOutput', {
      value: ssmParam.parameterName,
      description: 'The name of the ssm parameter',
      exportName: `${process.env.STACK_NAME}-Param`
    });
  }
}
```

### Rendered input file
<a name="ag-infrastructure-tmp-files-codebuild.example.manifest"></a>

When you create an environment using a CodeBuild-based provisioning template, AWS Proton renders an input file with [input parameter values](https://docs.aws.amazon.com/proton/latest/userguide/parameters.html) that you provided. Your code can refer to these values. The following file is an example to a rendered input file.

**Example infrastructure/proton-inputs.json**  

```
{
  "environment": {
    "name": "myenv",
    "inputs": {
      "my_sample_input": "10.0.0.0/16",
      "my_other_sample_input": "11.0.0.0/16"
    }
  }
}
```

# Terraform IaC files
<a name="ag-infrastructure-tmp-files-terraform"></a>

Learn how to use Terraform infrastructure as code (IaC) files with AWS Proton. [Terraform](https://www.terraform.io/) is a widely used open-source IaC engine that was developed by [HashiCorp](https://www.hashicorp.com/). Terraform modules are developed in HashiCorp's HCL language, and support several backend infrastructures providers, including Amazon Web Services.

AWS Proton supports [self-managed provisioning](ag-works-prov-methods.md#ag-works-prov-methods-self) for Terraform IaC.

For a complete example of a provisioning repository that responds to pull requests and implements infrastructure provisioning, see [Terraform OpenSource GitHub Actions automation template for AWS Proton](https://github.com/aws-samples/aws-proton-terraform-github-actions-sample) on GitHub.

**How self-managed provisioning works with Terraform IaC template bundle files:**

1. When you [create an environment](ag-create-env.md) from Terraform template bundles, AWS Proton compiles your `.tf` files with console or `spec file` input parameters.

1. It makes a pull request to merge the compiled IaC files to [repository that you have registered with AWS Proton](ag-create-repo.md).

1. If the request is approved, AWS Proton waits on provisioning status that you provide.

1. If the request is rejected, the environment creation is cancelled.

1. If the pull request times out, environment creation *isn't* complete.

**AWS Proton with Terraform IaC considerations:**
+ AWS Proton doesn’t manage your Terraform provisioning.
+ You must [register a provisioning repository](ag-create-repo.md) with AWS Proton. AWS Proton makes pull requests on this repository.
+ You must [create a CodeStar connection](setting-up-for-service.md#setting-up-vcontrol) to connect AWS Proton with your provisioning repository.
+ To provision from AWS Proton compiled IaC files, you must respond to AWS Proton pull requests. AWS Proton makes pull requests after environment and service create and update actions. For more information, see [AWS Proton environments](ag-environments.md) and [AWS Proton services](ag-services.md).
+ To provision a pipeline from AWS Proton compiled IaC files, you must [create a CI/CD pipeline repository](setting-up-for-service.md#setting-up-pr-repo).
+ Your pull request based provisioning automation must include steps to notify AWS Proton of any provisioned AWS Proton resource status changes. You can use the AWS Proton [NotifyResourceDeploymentStatusChange API](https://docs.aws.amazon.com/proton/latest/APIReference/API_NotifyResourceDeploymentStatusChange.html).
+ You can’t deploy services, pipelines, and components created from CloudFormation IaC files to environments created from Terraform IaC files.
+ You can’t deploy services, pipelines, and components created from Terraform IaC files to environments created from CloudFormation IaC files.

When preparing your Terraform IaC files for AWS Proton, you attach namespaces to your input variables, as shown in the following examples. For more information, see [Parameters](parameters.md).

## Example 1: AWS Proton environment Terraform IaC file
<a name="ag-env-tform-example"></a>

```
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.0"
    }
  }
  // This tells terraform to store the state file in s3 at the location
  // s3://terraform-state-bucket/tf-os-sample/terraform.tfstate
  backend "s3" {
    bucket = "terraform-state-bucket"
    key    = "tf-os-sample/terraform.tfstate"
    region = "us-east-1"
  }
}

// Configure the AWS Provider
provider "aws" {
  region = "us-east-1"
  default_tags {
    tags = var.proton_tags
  }
}

resource "aws_ssm_parameter" "my_ssm_parameter" {
  name  = "my_ssm_parameter"
  type  = "String"
  // Use the Proton environment.inputs. namespace
  value = var.environment.inputs.ssm_parameter_value
}
```

## Compiled infrastructure as code
<a name="compiled-tform"></a>

When you create an environment or service, AWS Proton compiles your infrastructure as code files with console or `spec file` inputs. It creates `proton.resource-type.variables.tf` and `proton.auto.tfvars.json` files for your inputs that can be used by Terraform, as shown in the following examples. These files are located in a specified repository in a folder that matches the environment or service instance name.

The example shows how AWS Proton includes tags in the variable definition and variable values, and how you can propagate these AWS Proton tags to provisioned resources. For more information, see [Tag propagation to provisioned resources](resources.md#auto-tags-prop).

### Example 2: compiled IaC files for an environment named "dev".
<a name="ag-compiled-example"></a>

**dev/environment.tf:**

```
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.0"
    }
  }
  // This tells terraform to store the state file in s3 at the location
  // s3://terraform-state-bucket/tf-os-sample/terraform.tfstate
  backend "s3" {
    bucket = "terraform-state-bucket"
    key    = "tf-os-sample/terraform.tfstate"
    region = "us-east-1"
  }
}

// Configure the AWS Provider
provider "aws" {
  region = "us-east-1"
  default_tags {
    tags = var.proton_tags
  }
}

resource "aws_ssm_parameter" "my_ssm_parameter" {
  name  = "my_ssm_parameter"
  type  = "String"
  // Use the Proton environment.inputs. namespace
  value = var.environment.inputs.ssm_parameter_value
}
```

**dev/proton.environment.variables.tf:**

```
variable "environment" {
  type = object({
    inputs = map(string)
    name = string
  })
}

variable "proton_tags" {
  type = map(string)
  default = null
}
```

**dev/proton.auto.tfvars.json:**

```
{
  "environment": {
    "name": "dev",
    "inputs": {
      "ssm_parameter_value": "MyNewParamValue"
    }
  }

  "proton_tags" : {
    "proton:account" : "123456789012",
    "proton:template" : "arn:aws:proton:us-east-1:123456789012:environment-template/fargate-env",
    "proton:environment" : "arn:aws:proton:us-east-1:123456789012:environment/dev"
  }
}
```

## Repository paths
<a name="repo-dir"></a>

AWS Proton uses console or spec inputs from environment or service create actions to find the repository and path where it is to locate the compiled IaC files. The input values are passed to [namespaced input parameters](parameters.md).

AWS Proton supports two repository path layouts. In the following examples, the paths are named by the namespaced resource parameters from two environments. Each environment has service instances of two services, and the service instances of one of the services have directly defined components.

<a name="limits-table"></a>[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/proton/latest/userguide/ag-infrastructure-tmp-files-terraform.html)

------
#### [ Layout 1 ]

If AWS Proton finds the specified repository with an `environments` folder, it creates a folder that includes the compiled IaC files and is named with the `environment.name`.

If AWS Proton finds the specified repository with an `environments` folder that contains a folder name that matches a service instance compatible environment name, it creates a folder that includes the compiled instance IaC files and is named with the `service_instance.name`.

```
/repo
    /environments
        /env-prod                             # environment folder
            main.tf
            proton.environment.variables.tf
            proton.auto.tfvars.json
          
            /service-one-instance-one-prod    # instance folder
                main.tf
                proton.service_instance.variables.tf
                proton.auto.tfvars.json
              
            /service-two-instance-two-prod    # instance folder
                main.tf
                proton.service_instance.variables.tf
                proton.auto.tfvars.json
              
            /component-prod                   # component folder
                main.tf
                proton.component.variables.tf
                proton.auto.tfvars.json
              
        /env-staged                           # environment folder
            main.tf
            proton.variables.tf
            proton.auto.tfvars.json         
          
            /service-one-instance-one-staged  # instance folder
                main.tf
                proton.service_instance.variables.tf
                proton.auto.tfvars.json
              
            /service-two-instance-two-staged  # instance folder
                main.tf
                proton.service_instance.variables.tf
                proton.auto.tfvars.json
              
            /component-staged                 # component folder
                main.tf
                proton.component.variables.tf
                proton.auto.tfvars.json
```

------
#### [ Layout 2 ]

If AWS Proton finds the specified repository without an `environments` folder, it creates an `environment.name` folder where it locates the compiled environment IaC files.

If AWS Proton finds the specified repository with a folder name that matches a service instance compatible environment name, it creates a `service_instance.name` folder where it locates the compiled instance IaC files.

```
/repo
    /env-prod                             # environment folder
        main.tf
        proton.environment.variables.tf
        proton.auto.tfvars.json
      
        /service-one-instance-one-prod    # instance folder
            main.tf
            proton.service_instance.variables.tf
            proton.auto.tfvars.json
          
        /service-two-instance-two-prod    # instance folder
            main.tf
            proton.service_instance.variables.tf
            proton.auto.tfvars.json
          
        /component-prod                   # component folder
            main.tf
            proton.component.variables.tf
            proton.auto.tfvars.json
          
    /env-staged                           # environment folder
        main.tf
        proton.variables.tf
        proton.auto.tfvars.json         
      
        /service-one-instance-one-staged  # instance folder
            main.tf
            proton.service_instance.variables.tf
            proton.auto.tfvars.json
          
        /service-two-instance-two-staged  # instance folder
            main.tf
            proton.service_instance.variables.tf
            proton.auto.tfvars.json
          
        /component-staged                 # component folder
            main.tf
            proton.component.variables.tf
            proton.auto.tfvars.json
```

------

# Schema file
<a name="ag-schema"></a>

As an administrator, when you use the Open API [Data Models (schemas) section](https://swagger.io/docs/specification/data-models/) to define a parameter schema YAML file for your template bundle, AWS Proton can validate parameter value inputs against the requirements that you defined in your schema.

For more information about formats and available keywords, see the [Schema object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.3.md#schemaObject) section of the OpenAPI.

## Schema requirements for environment template bundles
<a name="schema-req-env"></a>

Your schema must follow the [Data Models (schemas) section](https://swagger.io/docs/specification/data-models/) of the OpenAPI in the YAML format. It must also be a part of your environment template bundle.

For your environment schema, you must include the formatted headers to establish that you're using the Data Models (schemas) section of the Open API. In the following environment schema examples, these headers appear in the first three lines.

An `environment_input_type` must be included and defined with a name that you provide. In the following examples, this is defined on line 5. By defining this parameter, you associate it with an AWS Proton environment resource. 

To follow the Open API schema model, you must include `types`. In the following example, this is line 6.

Following `types`, you must define an `environment_input_type` type. You define the input parameters for your environment as properties of the `environment_input_type`. You must include at least one property with a name that matches at least one parameter that's listed in the environment infrastructure as code (IaC) file that's associated with schema.

When you create an environment and provide customized parameter values, AWS Proton uses the schema file to match, validate, and inject them into the curly braced parameters in the associated CloudFormation IaC file. For each property (parameter), provide a `name` and `type`. Optionally, also provide a `description`, `default`,and `pattern`.

The defined parameters for the following example *standard* environment template schema include `vpc_cidr`, `subnet_one_cidr`, and `subnet_two_cidr` with the `default` keyword and default values. When you create an environment with this environment template bundle schema, you can accept the default values or provide your own. If a parameter *doesn't* have a default value and is listed as a `required` property (parameter), you must provide values for it when you create an environment.

The second example *standard* environment template schema lists the `required` parameter `my_other_sample_input`.

You can create a schema for two types of environment templates. For more information, see [Register and publish templates](template-create.md).
+ ***Standard* environment templates**

  In the following example, an environment input type is defined with a description and input properties. This schema example can be used with the AWS Proton CloudFormation IaC file shown in [Example 3](ag-infrastructure-tmp-files-cloudformation.md#ag-proton-env-cfn-example).

  Example schema for a *standard* environment template:

  ```
  schema:                            # required
    format:                          # required
      openapi: "3.0.0"               # required
    # required              defined by administrator
    environment_input_type: "PublicEnvironmentInput"
    types:                           # required
      # defined by administrator
      PublicEnvironmentInput:
        type: object
        description: "Input properties for my environment"
        properties:
          vpc_cidr:                   # parameter
            type: string
            description: "This CIDR range for your VPC"
            default: 10.0.0.0/16
            pattern: ([0-9]{1,3}\.){3}[0-9]{1,3}($|/(16|24))
          subnet_one_cidr:            # parameter
            type: string
            description: "The CIDR range for subnet one"
            default: 10.0.0.0/24
            pattern: ([0-9]{1,3}\.){3}[0-9]{1,3}($|/(16|24))
          subnet_two_cidr:            # parameter
            type: string
            description: "The CIDR range for subnet one"
            default: 10.0.1.0/24
            pattern: ([0-9]{1,3}\.){3}[0-9]{1,3}($|/(16|24))
  ```

  Example schema for a *standard* environment template that includes a `required` parameter:

  ```
  schema:                            # required
    format:                          # required
      openapi: "3.0.0"               # required
    # required              defined by administrator
    environment_input_type: "MyEnvironmentInputType"
    types:                           # required
      # defined by administrator
      MyEnvironmentInputType:
        type: object
        description: "Input properties for my environment"
        properties:
          my_sample_input:           # parameter
            type: string
            description: "This is a sample input"
            default: "hello world"
          my_other_sample_input:     # parameter
            type: string
            description: "Another sample input"
          another_optional_input:    # parameter
            type: string
            description: "Another optional input"
            default: "!"
        required:
          - my_other_sample_input
  ```
+ ***Customer managed* environment templates**

  In the following example, the schema only includes a list of outputs that replicate the outputs from the IaC that you used to provision your *customer managed* infrastructure. You need to define output value types as *strings only* (*not* lists, arrays or other types). For example, the next code snippet shows the outputs section of an external CloudFormation template. This is from the template shown in [Example 1](ag-infrastructure-tmp-files-cloudformation.md#ag-env-cfn-example). It can be used to create external *customer managed* infrastructure for an AWS Proton Fargate service created from [Example 4](ag-infrastructure-tmp-files-cloudformation.md#ag-proton-svc-cfn-example).
**Important**  
As an administrator, you must ensure that your provisioned and managed infrastructure and all output parameters are compatible with the associated *customer managed* environment templates. AWS Proton can't account for changes on your behalf because these changes aren't visible to AWS Proton. Inconsistencies result in failures.

  Example CloudFormation IaC file outputs for a *customer managed* environment template:

  ```
  // Cloudformation Template Outputs
  [...]
  Outputs:
    ClusterName:
      Description: The name of the ECS cluster
      Value: !Ref 'ECSCluster'
    ECSTaskExecutionRole:
      Description: The ARN of the ECS role
      Value: !GetAtt 'ECSTaskExecutionRole.Arn'
    VpcId:
      Description: The ID of the VPC that this stack is deployed in
      Value: !Ref 'VPC'
  [...]
  ```

  The schema for the corresponding AWS Proton *customer managed* environment template bundle is shown in the following example. Each output value is defined as a string.

  Example schema for a *customer managed* environment template:

  ```
  schema:                            # required
    format:                          # required
      openapi: "3.0.0"               # required
    # required              defined by administrator
    environment_input_type: "EnvironmentOutput"
    types:                           # required
      # defined by administrator
      EnvironmentOutput:
        type: object
        description: "Outputs of the environment"
        properties:
          ClusterName:               # parameter
            type: string
            description: "The name of the ECS cluster"
          ECSTaskExecutionRole:      # parameter
            type: string
            description: "The ARN of the ECS role"
          VpcId:                     # parameter
            type: string
            description: "The ID of the VPC that this stack is deployed in"
  [...]
  ```

## Schema requirements for service template bundles
<a name="schema-req-svc"></a>

Your schema must follow the [Data Models (schemas) section](https://swagger.io/docs/specification/data-models/) of the OpenAPI in YAML format as shown in the following examples. You must provide a schema file in your service template bundle.

In the following service schema examples, you must include the formatted headers. In the following example, this is in the first three lines. This is to establish that you're using the Data Models (schemas) section of the Open API.

A `service_input_type` must be included and defined with a name that you provide. In the following example, this is in line 5. This associates the parameters with an AWS Proton service resource.

An AWS Proton service pipeline is included by default when you use the console or the CLI to create a service. When you include a service pipeline for your service, you must include `pipeline_input_type` with a name that you provide. In the following example, this is in line 7. *Don’t* include this parameter if you *aren’t* including an AWS Proton service pipeline. For more information, see [Register and publish templates](template-create.md).

To follow the Open API schema model, you must include `types` In the following example, this is in line 9.

Following `types`, you must define a `service_input_type` type. You define the input parameters for your service as properties of the `service_input_type`. You must include at least one property with a name that matches at least one parameter listed in the service infrastructure as code (IaC) file that is associated with schema.

To define a service pipeline, below your `service_input_type` definition, you must define a `pipeline_input_type`. As above, you must include at least one property with a name that matches at least one parameter listed in a pipeline IaC file that is associated with schema. *Don’t* include this definition if you *aren’t* including an AWS Proton service pipeline.

When you, as an administrator or developer, create a service and provide customized parameter values, AWS Proton uses the schema file to match, validate, and inject them into the associated CloudFormation IaC file’s curly braced parameters. For each property (parameter), provide a `name` and a `type`. Optionally, also provide a `description`, `default`, and `pattern`.

The defined parameters for the example schema include `port`, `desired_count`, `task_size` and `image` with the `default` keyword and default values. When you create a service with this service template bundle schema, you can accept the default values or provide your own. The parameter `unique_name` is also included in the example and *doesn't* have a default value. It is listed as a `required` property (parameter). You, as administrator or developer, must provide values for `required` parameters when you create services.

If you want to create a service template with a service pipeline, include the `pipeline_input_type` in your schema.

**Example service schema file for a service that includes an AWS Proton service pipeline.**

 This schema example can be used with the AWS Proton IaC files shown in [Example 4](ag-infrastructure-tmp-files-cloudformation.md#ag-proton-svc-cfn-example) and [Example 5](ag-infrastructure-tmp-files-cloudformation.md#ag-proton-pipeline-cfn-example). A service pipeline is included.

```
schema:                            # required
  format:                          # required
    openapi: "3.0.0"               # required
  # required           defined by administrator
  service_input_type: "LoadBalancedServiceInput"
  # only include if including AWS Proton service pipeline, defined by administrator
  pipeline_input_type: "PipelineInputs"

  types:                           # required
    # defined by administrator
    LoadBalancedServiceInput:
      type: object
      description: "Input properties for a loadbalanced Fargate service"
      properties:
        port:                      # parameter
          type: number
          description: "The port to route traffic to"
          default: 80
          minimum: 0
          maximum: 65535
        desired_count:             # parameter
          type: number
          description: "The default number of Fargate tasks you want running"
          default: 1
          minimum: 1
        task_size:                 # parameter
          type: string
          description: "The size of the task you want to run"
          enum: ["x-small", "small", "medium", "large", "x-large"]
          default: "x-small"
        image:                     # parameter
          type: string
          description: "The name/url of the container image"
          default: "public.ecr.aws/z9d2n7e1/nginx:1.19.5"
          minLength: 1
          maxLength: 200
        unique_name:               # parameter
          type: string
          description: "The unique name of your service identifier. This will be used to name your log group, task definition and ECS service"
          minLength: 1
          maxLength: 100
      required:
        - unique_name
    # defined by administrator
    PipelineInputs:
      type: object
      description: "Pipeline input properties"
      properties:
        dockerfile:                # parameter
          type: string
          description: "The location of the Dockerfile to build"
          default: "Dockerfile"
          minLength: 1
          maxLength: 100
        unit_test_command:         # parameter
          type: string
          description: "The command to run to unit test the application code"
          default: "echo 'add your unit test command here'"
          minLength: 1
          maxLength: 200
```

If you want to create a service template without a service pipeline, *don't* include the `pipeline_input_type` in your schema, as shown in the following example.

**Example service schema file for a service that *doesn't* include an AWS Proton service pipeline**

```
schema:                            # required
  format:                          # required
    openapi: "3.0.0"               # required
  # required            defined by administrator  
  service_input_type: "MyServiceInstanceInputType"

  types:                           # required
    # defined by administrator
    MyServiceInstanceInputType:
      type: object
      description: "Service instance input properties"
      required:
        - my_sample_service_instance_required_input
      properties:
        my_sample_service_instance_optional_input:   # parameter
          type: string
          description: "This is a sample input"
          default: "hello world"
        my_sample_service_instance_required_input:   # parameter
          type: string
          description: "Another sample input"
```

# Wrap up template files for AWS Proton
<a name="ag-wrap-up"></a>

After preparing your environment and service infrastructure as code (IaC) files and their respective schema files, you must organize them in directories. You must also create a manifest YAML file. The manifest file lists the IaC files in a directory, the rendering engine, and the template language used to develop the IaC in this template.

**Note**  
A manifest file can also be used independently of template bundles, as a direct input to *directly defined components*. In this case, it always specifies a single IaC template file, for both CloudFormation and Terraform. For more information about components, see [AWS Proton components](ag-components.md).

The manifest file needs to adhere to the format and content shown in the following example.

**CloudFormation manifest file format:**

With CloudFormation, you list a single file.

```
infrastructure:
  templates:
    - file: "cloudformation.yaml"
      rendering_engine: jinja
      template_language: cloudformation
```

**Terraform manifest file format:**

With terraform, you can explicitly list a single file or use the wildcard `*` to list each of the files in a directory.

**Note**  
The wildcard only includes files whose names end with `.tf`. Other files are ignored.

```
infrastructure:
  templates:
    - file: "*"
      rendering_engine: hcl
      template_language: terraform
```

**CodeBuild-based provisioning manifest file format:**

With CodeBuild-based provisioning, you specify provisioning and deprovisioning shell commands.

**Note**  
In addition to the manifest, your bundle should include any files that your commands depend on.

The following example manifest uses CodeBuild-based provisioning to provision (*deploy*) and deprovision (*destroy*) resources using the AWS Cloud Development Kit (AWS CDK) (AWS CDK). The template bundle should also include the CDK code.

During provisioning, AWS Proton creates an input file with values for input parameters that you defined in the template's schema with the name `proton-input.json`.

```
infrastructure:
  templates:
    - rendering_engine: codebuild
      settings:
        image: aws/codebuild/amazonlinux2-x86_64-standard:4.0
        runtimes:
          nodejs: 16
        provision:
          - npm install
          - npm run build
          - npm run cdk bootstrap
          - npm run cdk deploy -- --require-approval never --outputs-file proton-outputs.json
          - jq 'to_entries | map_values(.value) | add | to_entries | map({key:.key, valueString:.value})' < proton-outputs.json > outputs.json
          - aws proton notify-resource-deployment-status-change --resource-arn $RESOURCE_ARN --status IN_PROGRESS --outputs file://./outputs.json
        deprovision:
          - npm install
          - npm run build
          - npm run cdk destroy
        project_properties:
          VpcConfig:
            VpcId: "{{ environment.inputs.codebuild_vpc_id }}"
            Subnets: "{{ environment.inputs.codebuild_subnets }}"
            SecurityGroupIds: "{{ environment.inputs.codebuild_security_groups }}"
```

After you set up the directories and manifest files for your environment or service template bundle, you gzip the directories into a tar ball and upload them to an Amazon Simple Storage Service (Amazon S3) bucket where AWS Proton can retrieve them, or to a [template sync Git repository](ag-template-sync-configs.md).

When you create a minor version of an environment or a service template that you registered with AWS Proton, you provide the path to your environment or service template bundle tar ball that's located in your S3 bucket. AWS Proton saves it with the new template minor version. You can select the new template minor version to create or update environments or services with AWS Proton.

## Environment template bundle wrap up
<a name="environment-wrap-up"></a>

There are two types of environment template bundles that you create for AWS Proton.
+ To create an environment template bundle for a *standard* environment template, organize the schema, infrastructure as code (IaC) files and manifest file in directories as shown in the following environment template bundle directory structure.
+ To create an environment template bundle for a *customer managed* environment template, provide only the schema file and directory. *Don't* include the infrastructure directory and files. AWS Proton throws an error if the infrastructure directory and files are included.

For more information, see [Register and publish templates](template-create.md).

CloudFormation environment template bundle directory structure:

```
 /schema
   schema.yaml
 /infrastructure
   manifest.yaml
   cloudformation.yaml
```

Terraform environment template bundle directory structure:

```
 /schema
   schema.yaml
 /infrastructure
   manifest.yaml
   environment.tf
```

## Service template bundle wrap up
<a name="service-wrap-up"></a>

To create a service template bundle, you must organize the schema, infrastructure as code (IaC) files, and manifest files into directories as shown in the service template bundle directory structure example.

If you *don’t* include a service pipeline in your template bundle, *don't* include the pipeline directory and files and set `"pipelineProvisioning": "CUSTOMER_MANAGED"` when you create the service template that is to be associated with this template bundle.

**Note**  
You can't modify `pipelineProvisioning` after the service template is created.

For more information, see [Register and publish templates](template-create.md).

CloudFormation service template bundle directory structure:

```
 /schema
   schema.yaml
 /instance_infrastructure
   manifest.yaml
   cloudformation.yaml
 /pipeline_infrastructure
   manifest.yaml
   cloudformation.yaml
```

Terraform service template bundle directory structure:

```
 /schema
   schema.yaml
 /instance_infrastructure
   manifest.yaml
   instance.tf
 /pipeline_infrastructure
   manifest.yaml
   pipeline.tf
```

# Template bundle considerations
<a name="template-considerations"></a>


+ **Infrastructure as code (IaC) files**

  AWS Proton audits templates for the correct file format. However, AWS Proton doesn't check for template development, dependency, and logic errors. For example, assume that you specified the creation of an Amazon S3 bucket in your CloudFormation IaC file as part of your service or environment template. A service is created based on those templates. Now, suppose at some point you want to delete the service. If the specified S3 bucket *isn't* empty and the CloudFormation IaC file *doesn't* mark it as `Retain` in the `DeletionPolicy`, AWS Proton fails on the service delete operation.
+ **Bundle file size limits and format**
  + Bundle file size, count, and name size limits can be found at [AWS Proton quotas](ag-limits.md).
  + The template bundle directories of files are gzipped into a tar ball and located in an Amazon Simple Storage Service (Amazon S3) bucket.
  + Each file in the bundle must be a valid formatted YAML file.
+ **S3 bucket template bundle encryption**

  If you want to encrypt sensitive data in your template bundles at rest in your S3 bucket, use SSE-S3 or SSE-KMS keys to allow AWS Proton to retrieve them.