Containers

Multi-account infrastructure provisioning with AWS Control Tower and AWS Proton

Introduction

The majority of the enterprise customers tend to establish centralize control and well-architected organization-wide policies when it comes to distribution of cloud resources in multiple teams. These teams are primarily divided into three categories: IT operations, Enterprise Security, and Application (App)-development. While delivery of business value from application standpoint falls under the purview of the App-development teams, the IT operations teams’ control the cloud resource provisioning and security teams ensures the delivery and coordination between these teams happens at scale.

Within AWS, AWS Control Tower offers the easiest way to set up and govern a secure, multi-account environment. It establishes a landing zone based on best-practices blueprints, and it enables governance using guardrails you can choose from a pre-packaged list. The landing zone is a well-architected, multi-account baseline that follows AWS best practices. First, it’s good to know that AWS Control Tower shares a lot of terminology with the AWS Organizations service, including the terms organization and organizational unit (OU). While Organization refers to an entity that you create to consolidate your AWS accounts for administration as a single unit, Organization unit acts as a container for Accounts within a root and provides necessary hierarchy.

Often there is a need for securing infrastructure in a consistent and compliant fashion, which requires a decoupling of the infrastructure management from the business application delivery that results in undifferentiated heavy lifting by teams.

The pattern discussed in this post addresses this challenge by using a combination of AWS Control Tower to set up a well-architected, multi-account environment and AWS Proton to simplify multi-account continuous integration and continuous delivery (CI/CD) Deployments for application deployment and management.

Solution overview

Multi-account deployment using AWS Proton

AWS Proton service is a two-pronged automation framework. As a platform team administrator, you create environment infrastructure as code template that defines shared infrastructure used by multiple applications and service templates that define deployment tooling for serverless and/or container-based applications. As an application developer, AWS Proton enables you to select desired service from the available service templates to automate your application deployments.

For platform teams to improve visibility and efficiency at scale, AWS Proton offers a capability called Environment Account Connections. Environment account connections help platform teams to establish secure bi-directional connections between a single management account and multiple development team accounts, also referred to as environment accounts and is described in the following figure.

This picture describes a typical Multi-account deployment architecture using AWS Proton, where AWS Proton's management account been used to vend infrastructure in multiple AWS accounts used in this blog.

Walkthrough

The solution described in this post assumes that you are using AWS Control Tower to create OUs and accounts. To know more on how to create an OU in the AWS Control Tower from AWS Management Console, refer to the AWS Documentation here.

Prerequisites

We used an AWS Cloud9 instance to run this tutorial and if you want to create a Cloud9 instance in your account, refer to the AWS Documentation here. If you are not using AWS Cloud9 you need to install the latest version of the AWS CLI.

Step 1: Create service control policy for OUs

For this solution, we created two OUs to demonstrate a typical customer use case. The first one is the Management OU for the AWS Proton Management Account, where platform teams can maintain the AWS Proton environment templates and service templates. The second one is the Development OU, which is used to create the AWS Proton Environment Account, where developer teams host their business applications.

Service control policies (SCPs) are a type of organization policy that you can use to manage permissions in your OUs. Here, we have created a simple SCP AWS-Proton-Blocker and associated that with our Development OU. This SCP prevents any developer environment account from using AWS Proton to provision any resources while ensuring platform teams have full control on Infrastructure provisioning.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Statement1",
      "Effect": "Deny",
      "Action": [
        "proton:*"
      ],
      "Resource": [
        "*"
      ]
    }
  ]
}

Note: This policy can be scoped i.e., by providing fine-grained access control relevant for a particular team as per the needs of your organization.

To learn more about how to create SCP, refer to AWS documentation here.

To learn more about how to attach SCP to OU, refer to AWS documentation here.

Step 2: Testing the SCP

  1. Log in to the AWS Account created under Development OU from the login link provided to you by AWS at the time of creating AWS Account. You’ll find log in details in the welcome email. Alternatively, you can also find the account login URL on the AWS Service Catalog dashboard under Provisioned Product.
  2. Search for AWS Proton from the AWS Management Console.
  3. Create an Environment template in AWS Proton as mentioned here.
  4. The Environment template creation fails due to the explicit deny at the OU level with the following error.
User: arn:aws:sts:[aws-account-number]:assumed-role/AWSReservedSSO_AWSAdministratorAccess_12345678abcdef/developeruser@amazon.com is not authorized to perform proton:GetTemplateSyncConfig on resource arn:aws:proton:us-east-1:[aws-account-number]:environment-template/example-environment with an explicit deny in a service control policy 

By using the SCP at the OU level, we ensure that the Platform Engineering team can enforce the organizational guardrails between the service teams and departments within an organization.

Step 3: Create environment template in the AWS Proton management account

To run AWS Command Line Interface (AWS CLI) commands in the provisioned AWS accounts, we created AWS Cloud9 workspaces and attached an AWS Identity and Access Management (AWS IAM) role with AdministratorAccess policy to the AWS Cloud9 instances in accounts created under Management and Development OUs. Please follow these instructions to attach the AWS IAM role to an Amazon Elastic Compute Cloud (Amazon EC2) instances.

For this post, we forked this GitHub repository and created a AWS CodeStar connection. Please find the steps to Set up an AWS CodeStar connection in the AWS Documentation. AWS Proton uses a source connection to trigger template updates or new application deploys whenever a new change is introduced. For the scope of this post, the connection is managed through the AWS CodeStar connections using GitHub as a provider. To read more on Service Sync configuration, please refer to this documentation.

  1. Create a new environment template (multi-svc-env) based on the templates located under multi-svc-env/v1 and published it to a major version. This structure holds the AWS CloudFormation template that we’ll use to provision the environment’s infrastructure.
aws proton create-environment-template \
--region ${AWS_REGION} \
--name "multi-svc-env" \
--display-name "Multi Service Environment" \
--description "Environment with VPC and public subnets"

Next, create a template sync configuration to register new environment template versions automatically.

REPOSITORY_ARN=$(aws proton list-repositories | \
jq -r '.repositories[] | select( .name | endswith("aws-proton-workshop-code")) | .arn');
REPOSITORY_NAME=$(echo $REPOSITORY_ARN | cut -d':' -f7);
REPOSITORY_PROVIDER=$(echo $REPOSITORY_ARN | cut -d':' -f6 | tr a-z A-Z);
aws proton create-template-sync-config \
--region ${AWS_REGION} \
--repository-name $REPOSITORY_NAME \
--repository-provider ${REPOSITORY_PROVIDER#"REPOSITORY/"} \
--branch main \
--subdirectory "aws-managed/multi-svc-env" \
--template-name "multi-svc-env" \
--template-type "ENVIRONMENT"

To publish it, we need to run the following command:

aws proton update-environment-template-version \
--region ${AWS_REGION} \
--template-name "multi-svc-env" \
--major-version "1" \
--minor-version "0" \
--status "PUBLISHED"

Step 4: Create environment account connection from management account in AWS Proton

AWS Proton alleviates complicated cross-account policies by using a secure environment account connection feature. With environment account connections, platform engineers can give AWS Proton permissions to provision infrastructure in other accounts. To create and provision an environment from AWS Proton management account, log into the AWS Account created by AWS Control Tower under the Management OU. You’ll find log in details in the welcome email accordingly.

  1. Create a scoped AWS IAM role in the AWS Proton management account
wget -O ~/environment/proton-account-connection-roles.yaml \
"https://static.us-east-1.prod.workshops.aws/public/84bb5775-ab15-4f18-8daf-2f4674e84233/static/cf-templates/proton-account-connection-roles.yaml"

cd ~/environment

aws cloudformation deploy \
--template-file proton-account-connection-roles.yaml \
--stack-name AWSProtonWorkshop-AccountConnectionRoles \
--parameter-overrides "EnvironmentAccountId=${SECONDARY_ENV_ACCOUNT_ID}" \
--capabilities "CAPABILITY_IAM" "CAPABILITY_NAMED_IAM"</code></pre></div>
  1. Now log in to the AWS Account and navigate to the AWS Proton’s Console created under the Development OU, or copy and paste the output of AWSProtonWorkshop-AccountConnectionRoles stack in your browser to login to the Development AWS Account. Choose Environment Account Connections from the navigation pane. Then select Request to Connect in Sent requests to connect to a management account. (For the Management account ID use the Proton Management Account).

  1. Switch back or log in again to the management account and you should have a new environment account connection request now in the AWS Proton Console. Go ahead and accept it!

Step 5: Create environment in Developer Team account

After defining the environment template, service template in the AWS Proton Management account and establishing the Environment Account Connections to the development account, we’re ready to provision the environment in the development account using AWS Proton.

First, we define the specification, which is a YAML-formatted string that provides inputs defined in the environment template bundle schema file. A sample can be found here.

SPEC=$(cat <<-EOF
proton: EnvironmentSpec
spec:
  vpc_cidr: 172.16.0.0/16
  dns_hostname: [name-of-your-app].dev.local
EOF
);

[[name-of-your-app] is a  place-holder, replace that with the name of your app]

The create-environment command creates the environment with the infrastructure needed for the App-Development teams to deploy micro-services. The template used below, deploys an Amazon Virtual Private Cloud (VPC) to secure networking boundary, an Amazon ECS cluster with optional configuration inputs like Amazon EC2 capacity, Container Insights, and Amazon ECS Executive logging for the application deployment.

MAJOR_VERSION=$(aws proton list-environment-template-versions \
--template-name "multi-svc-env" --region=${AWS_REGION} | \
  jq -r ' .templateVersions[] | select( .status=="PUBLISHED") | .majorVersion' | tail -1 \
); \
ACCOUNT_CONNECTION_ID=$(aws proton list-environment-account-connections \
--requested-by "MANAGEMENT_ACCOUNT" --statuses "CONNECTED" --region=${AWS_REGION} | \
  jq -r ' .environmentAccountConnections[] | select( .environmentName | startswith("multi-svc")) | .id' \
); \
aws proton create-environment \
  --region ${AWS_REGION} \
  --name "multi-svc-${AWS_ACCOUNT_ID}" \
  --template-name "multi-svc-env" \
  --template-major-version "$MAJOR_VERSION" \
  --environment-account-connection-id "$ACCOUNT_CONNECTION_ID" \
  --spec "$SPEC"

In the Developer account (i.e., environment account), you can view and access the provisioned infrastructure resources. You can now use this environment to deploy application as AWS Proton Service. Please review the documentation to learn more about the service deployment in an AWS Proton environment.

Cleaning up

You continue to incur cost until deleting the infrastructure that you created for this post. Use the below instructions to delete AWS resources in the blog.

Delete the environment:

aws proton delete-environment --name multi-svc-${AWS_ACCOUNT_ID}
# Wait for above to complete before proceeding next steps. It takes ~3 minutes.

Delete the environment template:

aws proton delete-environment-template --name multi-svc-env

Delete the template sync config:

aws proton delete-template-sync-config --template-name multi-svc-env --template-type ENVIRONMENT

Once you have deleted your AWS Proton resources, please follow AWS Documentation here to delete your AWS Control Tower resources.

Conclusion

In this post, we showed you how customers improved the security posture of multi-account infrastructure deployments by using AWS Control Tower to provision and organize AWS accounts that adhere to best-practices. We used AWS Proton to amplify platform engineering impacts and improve developer productivity. This established workflow allowed Platform teams to have a unified view of all the AWS Proton managed resources from management account using the AWS Proton dashboard.

To get started with AWS Proton, head over to our sample repository for examples and our documentation for a deeper dive into its full functionality.

Pratip Bagchi

Pratip Bagchi

Pratip Bagchi is a Sr. Solutions Architect with Amazon Web Services. He specializes in application modernization. He works with enterprise customers and partners to modernize their legacy applications, workloads and helps them to build reliable, secured and maintainable enterprise architecture on the AWS platform. Pratip spends his free-time in running, camping and gardening.

Sai Charan Teja Gopaluni

Sai Charan Teja Gopaluni

Sai Charan Teja Gopaluni is a Sr.Solutions Architect at Amazon Web Services. In his role as a subject matter expert, he enjoys helping customers design modern, scalable and secure container based applications. Outside of the work, he enjoys playing Tennis and watching Soccer.