Modeling Additional Environment 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 environment-level addons. For workload-level addons, visit Modeling Additional Workload 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/environments/addons
directory. - When running
copilot env deploy
, the custom addons template will be deployed along with your environment stack.
Sample workspace layout with environment addons
.
└── copilot
└── environments
├── addons # Store environment addons.
│ └── mys3.yaml
├── dev
└── prod
What does an addon template look like?
An environment addon template can be any valid CloudFormation template that satisfies the following:
- Includes at least one
Resource
. - The
Parameters
section includesApp
,Env
.
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
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 environment stack.
Examples: Customize addon parameters
# In "environments/addons/my-addon.yml"
Parameters:
# Required parameters by AWS Copilot.
App:
Type: String
Env:
Type: String
# Additional parameters defined in addons.parameters.yml
ClusterName:
Type: String
# In "environments/addons/addons.parameters.yml"
Parameters:
ClusterName: !Ref Cluster
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.
Environment addon: Connecting to your workloads
A value from an environment addon can be referenced by a workload addon or a workload manifest.
To do so, you should first export the value from the environment addon using the Outputs
section.
Example: Export values from environment addons
Outputs:
MyTableARN:
Value: !GetAtt ServiceTable.Arn
Export:
Name: !Sub ${App}-${Env}-MyTableARN # This value can be consumed by a workload manifest or a workload addon.
MyTableName:
Value: !Ref ServiceTable
Export:
Name: !Sub ${App}-${Env}-MyTableName
It is important that you add the Export
block.
Otherwise, your workload stack or your workload addons won't be able to access the value.
You will use Export.Name
to reference the value from your workload-level resources.
Consideration: Namespace your Export.Name
You can specify any name you like for Export.Name
.
That is, it doesn't have to be prefixed with !Sub ${App}-${Env}
; it can simply be MyTableName
.
However, within an AWS region, the Export.Name
must be unique.
That is, you can't have two exports named MyTableName
in us-east-1
.
Therefore, we recommend you to namespace your exports with ${App}
and ${Env}
to decrease the chance of name collision.
In addition, this makes it clear which application and environment the value is managed under.
With the namespace, for example, say your application's name is "my-app"
,
and you deployed the addons with environment test
, then the final export name would be rendered to my-app-test-MyTableName
.
Referencing from a workload addon
In your workload addons, you can reference a value from your environment addons, as long as that value is exported.
To do so, use the Fn::ImportValue
function with that value's export name to import it from an environment addon.
Example: An IAM policy to access an environment-level DynamoDB table
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:
MyTableAccessPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
Description: Grants CRUD access to the Dynamo DB table
PolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: DDBActions
Effect: Allow
Action:
- dynamodb:* # NOTE: Scope down the permissions in your real application. This is done so that this example isn't too long!
Resource:
Fn::ImportValue: # <- We import the table ARN from the environment addons.
!Sub ${App}-${Env}-MyTableARN # <- The export name that we used.
Referencing from a workload manifest
You can also reference a value from your environment addons in a workload manifest for
variables
,
secrets
and
security_groups
,
as long as that value is exported. To do so, use from_cfn
fields in workload manifests with that value's export name.
Examples: using from_cfn
name: db-front
type: Backend Service
variables:
MY_TABLE_NAME:
from_cfn: ${COPILOT_APPLICATION_NAME}-${COPILOT_ENVIRONMENT_NAME}-MyTableName
name: db-front
type: Backend Service
secrets:
MY_CLUSTER_CREDS:
from_cfn: ${COPILOT_APPLICATION_NAME}-${COPILOT_ENVIRONMENT_NAME}-MyClusterSecret
name: db-front
type: Backend Service
security_groups:
- from_cfn: ${COPILOT_APPLICATION_NAME}-${COPILOT_ENVIRONMENT_NAME}-MyClusterAllowedSecurityGroup
Examples
Environment Addons Walk-through
See our v1.25.0 blog post for a detailed walk-through!