AWS Cloud Operations Blog
Automating shared VPC deployments with AWS CloudFormation
VPC sharing allows customers to share subnets from a central AWS account with other AWS accounts in the same organization created in AWS Organizations. Centralized control of your virtual private cloud (VPC) structure allows you to maintain separation of duties through AWS account boundaries. A best practice for creating VPCs and other resources in the AWS Cloud is to develop your infrastructure as code (IaC). You can use AWS CloudFormation for this purpose because it offers an easy way to model, provision, and manage your resources through reusable templates.
In this post, I’ll show you how to create shared VPCs using AWS CloudFormation to support agility and the reusability of your workload resources. I’ll also share some considerations for when you combine the centralized network management capabilities of VPC sharing with teams building application workloads in AWS CloudFormation.
Solution implementation
To build the components of this solution, you will be working with AWS Organizations, AWS CloudFormation, AWS Resource Access Manager (AWS RAM), and AWS Systems Manager (SSM) Parameter Store. You will deploy and share network components from an AWS account you designate for network management using AWS CloudFormation and the AWS::CloudFormation::StackSet resource type.
Figure 1: Shared VPC Solution Diagram
Prerequisites
- An organization created in AWS Organizations with a management account and at least two member accounts. One member account will be your network account and the other is designated for workload resources.
- AWS Command Line Interface (AWS CLI) installed and configured for access to all organization accounts.
- A text editor for updating YAML files.
- An Amazon Simple Storage Service (Amazon S3) bucket accessible from your organization’s accounts. For an example of how to define an S3 bucket policy, see the An easier way to control access to AWS resources by using the AWS organization of IAM principals blog post.
- The AWS CloudFormation template examples on GitHub.
Step 1: Set up IAM roles for cross-account access
To get started, create an AWS Identity and Access Management (IAM) role in the central network account and in each of member accounts that will be accessing the shared VPC components. You will use AWS CloudFormation StackSets to automate the deployment of the following roles from the management account of the organization.
- NetworkParameterExecutionRole: This role will be created in the workload accounts to allow for the execution of AWS CloudFormation stacks initiated from the network account.
- NetworkParameterAdminRole: This role will be created in the network account. It allows AWS CloudFormation to assume the NetworkParameterExecutionRole in the workload accounts.
The network-role-stackset.yaml
template defines the resources for the two roles. It takes two parameter values: networkAccountId
, which is used to set the AWS account that will be defined as the central network account, and organizationId
. The template also uses the CloudFormation Conditions section to determine which role should be deployed based on whether the target account ID matches the networkAccountId
value.
You can deploy the network-role-stackset.yaml
template by setting your AWS CLI profile to your organization’s management account and running the following commands. Be sure to replace the region ID and account IDs with values from your environment.
Step 2: Deploy the shared VPC
Again, you will use AWS CloudFormation to deploy your VPC and related resources from the network account. The shared-vpc.yaml
template will:
- Create a VPC with public, private, and database subnets across two Availability Zones.
- Share the public, private, and database subnet tiers to the workload accounts you specify.
- Create and share a prefix list to organization member accounts for use in security groups.
- Create Parameter Store parameters with the shared configuration information in the workload accounts.
To deploy the shared VPC
- Upload the
ssm-parameter-stackset.yaml
to your S3 bucket. - Edit the
shared-vpc-input.json
and provide the parameter values for your organization. - From the network account, use the following CLI command to create the stack.
Let’s take a closer look at how the template provisions and shares the VPC resources.
VPC sharing uses AWS RAM to share subnets with other member accounts in the organization. In the template, the AWS::RAM::ResourceShare resource type is used to create a RAM share for each of the three subnet tiers. AWS CloudFormation parameters are defined at the beginning of the template to capture comma-delimited lists of the AWS account IDs to share the subnet resources with. Using AWS CloudFormation parameters simplifies updates in the event you need to give access to other accounts in the future.
A prefix list is a set of one or more Classless Inter-Domain Routing (CIDR) blocks that can be referenced by other AWS resources, such as subnet route tables and VPC security groups. You can use AWS RAM to share prefix lists, which is useful in shared VPC environments. For example, a prefix list can be referenced in security groups for EC2 resources to allow access from trusted on-premises networks. Network teams can manage the prefix lists and application teams that use the shared subnets can reference the prefix lists rather than specifying the CIDRs directly in their templates. The Principals
attribute of this RAM resource share differs from the VPC and subnet shares definitions. In this example, you are sharing the prefix list with the entire organization rather than just the workload accounts.
AWS CloudFormation stacks created in one account cannot export stack output values to another account. This means that if your teams are building resources in the workload accounts, they cannot use Fn::ImportValue to reference shared resource attributes such as a SubnetId
. Manually coding or entering parameter values for these values is less efficient and prone to error. To automate the sharing of these values, you can define a naming standard to reference the resource IDs and publish them as a key-value pairs in the Parameter Store in the target account.
The AWS::CloudFormation::StackSet resource type is used to handle the cross account deployment of the parameters through the IAM roles you created earlier. Application teams can then reference the Parameter Store values using an environment naming convention when they define their templates. This method reduces human error and helps to promote reuse of the workload templates throughout the application lifecycle.
The StackSet resources use a common template, ssm-parameter-stackset.yaml
, for defining the AWS::SSM::Parameter
resources in the workload accounts you specify.
Step 3: Deploy workload resources
Now that you’ve successfully deployed the shared-vpc stack, you will find a collection of parameters in the Parameter Store of your workload accounts. The list in each account will be based on the components you assigned through the template parameters.
Figure 2: AWS Systems Manager Parameter Store
You can use these parameters as inputs to your workload templates to deploy resources into the shared subnets. In this case, you will use the workload-instance.yaml
template to create an EC2 instance in one of the private subnets. This instance will also be configured with a security group that allows SSH access from the IP address ranges specified in the shared prefix list.
To deploy the workload instance
- Edit the
workload-instance-input.json
and provide the parameter values for your application account. - Use the following CLI command to create the stack.
After your stack is created, use the CloudFormation console or the following CLI command to confirm your instance details.
Let’s take a closer look at how the template uses the shared resources to provision EC2 resources.
The shared-vpc.yaml
template you deployed earlier created Parameter Store parameters for the VPC ID, subnet IDs, and the prefix list ID. The workload-instance.yaml
template retrieves this information from the Parameter Store in the Parameter
section of the template. The AWS::SSM::Parameter::Value<String> parameter type enables this functionality.
These parameter values are then referenced by the resources in the template as needed.
Cleanup
Set your CLI profile to the application account and use the following commands to delete the resources deployed to this account.
Then, switch your CLI profile to the network account and use the following commands to delete the resources deployed to this account.
Then, switch your CLI profile to the organization’s management account and use the following commands to delete the resources deployed to this account. Update the account ID and region ID values to match those you used during your deployment.
Conclusion
In this post, I shared an example of how to use AWS CloudFormation to provision and share VPC resources between teams in a multi-account model. I showed you how to create the IAM roles and deployment framework required to support a centralized networking model that follows the best practices. Through upfront planning and the use of AWS CloudFormation StackSets and AWS Systems Manager Parameter Store, workload teams can remain agile in a centralized environment.