Modeling Additional Workload Resources with AWS CloudFormation
Additional AWS resources, referred to as "addons" in the CLI, are any additional AWS services that a service or environment manifest does not integrate by default. For example, an addon can be a DynamoDB table, an S3 bucket, or an RDS Aurora Serverless cluster that your service needs to read or write to.
You can define additional resources for a workload (such as a Load Balanced Web Service or a Scheduled Job). The lifecycle of workload addons will be managed by the workload and will be deleted once the workload is deleted.
Alternatively, you can define additional shareable resource for an environment. Environment addons won't be deleted unless the environment is deleted.
This page documents how to create workload-level addons. For environment-level addons, visit Modeling Additional Environment Resources with AWS CloudFormation.
How do I add an S3 bucket, a DDB Table, or an Aurora Serverless cluster?
Copilot provides the following commands to help you create certain kinds of addons:
storage init
will create a DynamoDB table, an S3 bucket, or an Aurora Serverless cluster.
You can run copilot storage init
from your workspace and be guided through some questions to help you set up these resources.
How to add other resources?
For other types of addons, you can add your own custom CloudFormation templates:
- You can store the custom templates in your workspace under
copilot/<workload>/addons
directory. - When running
copilot [svc/job] deploy
, the custom addons template will be deployed along with your workload stack.
Sample workspace layout with workload addons
.
└── copilot
└── webhook
├── addons # Store addons associated with the service "webhook".
│ └── mytable-ddb.yaml
└── manifest.yaml
What does an addon template look like?
A workload addon template can be any valid CloudFormation template that satisfies the following:
- Include at least one
Resource
. - The
Parameters
section must includeApp
,Env
,Name
.
you can customize your resource properties with Conditions or Mappings.
We recommend following Amazon IAM best practices while defining AWS Managed Policies for the additional resources, including:
- Grant least privilege to the policies defined in your
addons/
directory. - Use policy conditions for extra security to restrict your policies to access only the resources defined in your
addons/
directory.
Writing the Parameters
section
There are a few parameters that Copilot requires you to define in your templates.
Parameters:
App:
Type: String
Env:
Type: String
Name:
Type: String
Customizing the Parameters
section
If you'd like to define parameters in addition to the ones required by Copilot, you can do so with a
addons.parameters.yml
file.
.
└── addons/
├── template.yml
└── addons.parameters.yml # Add this file under your addons/ directory.
- In your template file, add the additional parameters under the
Parameters
section. - In your
addons.parameters.yml
, define the values of those additional parameters. They can refer to values from your workload stack.
Examples: Customize addon parameters
# In "webhook/addons/my-addon.yml"
Parameters:
# Required parameters by AWS Copilot.
App:
Type: String
Env:
Type: String
Name:
Type: String
# Additional parameters defined in addons.parameters.yml
ServiceName:
Type: String
# In "webhook/addons/addons.parameters.yml"
Parameters:
ServiceName: !GetAtt Service.Name
Writing the Conditions
and the Mappings
sections
Often, you want to configure your addon resources differently depending on certain conditions.
For example, you could conditionally configure your DB resource's capacity depending on whether it is deploying to a
production or a test environment. To do so, you can use the Conditions
section and the Mappings
section.
Examples: Configure addons conditionally
Mappings:
MyAuroraServerlessEnvScalingConfigurationMap:
dev:
"DBMinCapacity": 0.5
"DBMaxCapacity": 8
test:
"DBMinCapacity": 1
"DBMaxCapacity": 32
prod:
"DBMinCapacity": 1
"DBMaxCapacity": 64
Resources:
MyCluster:
Type: AWS::RDS::DBCluster
Properties:
ScalingConfiguration:
MinCapacity: !FindInMap
- MyAuroraServerlessEnvScalingConfigurationMap
- !Ref Env
- DBMinCapacity
MaxCapacity: !FindInMap
- MyAuroraServerlessEnvScalingConfigurationMap
- !Ref Env
- DBMaxCapacity
Conditions:
IsProd: !Equals [!Ref Env, "prod"]
Resources:
MyCluster:
Type: AWS::RDS::DBCluster
Properties:
ScalingConfiguration:
MinCapacity: !If [IsProd, 1, 0.5]
MaxCapacity: !If [IsProd, 8, 64]
Writing the Outputs
section
You can use the Outputs
section to define any values that can be consumed by other resources; for example, a service,
a CloudFormation stack, etc.
Workload addons: Connecting to your workloads
Here are several possible ways to access addon Resources
from your ECS task or App Runner instance:
- If you need to add additional policies to your ECS task role or App Runner instance role, you can define an IAM ManagedPolicy addon resource in your template that holds the additional permissions, and then output it. The permission will be injected into your task or instance role.
- If you need to add a security group to your ECS service, you can define a Security Group in your template, and then add it as an Output. The security group will be automatically attached to your ECS service.
- If you'd like to inject a secret to your ECS task, you can define a Secret in your template, and then add it as an Output. The secret will be injected into your container and can be accessed as an environment variable in capital SNAKE_CASE.
- If you'd like to inject any resource value as an environment variable, you can create an Output to your ECS tasks. It will be injected into your container and may be accessed as an environment variable in capital SNAKE_CASE.
Examples
A Workload Addon Template For A DynamoDB Table
Here is an example template for a workload-level DynamoDB table addon:
# You can use any of these parameters to create conditions or mappings in your template.
Parameters:
App:
Type: String
Description: Your application's name.
Env:
Type: String
Description: The environment name your service, job, or workflow is being deployed to.
Name:
Type: String
Description: Your workload's name.
Resources:
# Create your resource here, such as an AWS::DynamoDB::Table:
# MyTable:
# Type: AWS::DynamoDB::Table
# Properties:
# ...
# 1. In addition to your resource, if you need to access the resource from your ECS task
# then you need to create an AWS::IAM::ManagedPolicy that holds the permissions for your resource.
#
# For example, below is a sample policy for MyTable:
MyTableAccessPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
PolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: DDBActions
Effect: Allow
Action:
- dynamodb:BatchGet*
- dynamodb:DescribeStream
- dynamodb:DescribeTable
- dynamodb:Get*
- dynamodb:Query
- dynamodb:Scan
- dynamodb:BatchWrite*
- dynamodb:Create*
- dynamodb:Delete*
- dynamodb:Update*
- dynamodb:PutItem
Resource: !Sub ${ MyTable.Arn}
Outputs:
# 1. You need to output the IAM ManagedPolicy so that Copilot can add it as a managed policy to your ECS task role.
MyTableAccessPolicyArn:
Description: "The ARN of the ManagedPolicy to attach to the task role."
Value: !Ref MyTableAccessPolicy
# 2. If you want to inject a property of your resource as an environment variable to your ECS task,
# then you need to define an output for it.
#
# For example, the output MyTableName will be injected in capital snake case, MY_TABLE_NAME, to your task.
MyTableName:
Description: "The name of this DynamoDB."
Value: !Ref MyTable