Email Address
chris@expertcloud.co
Contact Number
+61417725999
Work Hours
Monday to Friday: 7AM - 5PM
Weekend: Closed
As organizations scale their AWS presence, the single-account approach quickly becomes impractical and risky. The multi-account strategy has emerged as a best practice for enterprise AWS implementations, despite its perceived complexity. This approach creates clear boundaries between workloads, teams, and environments, enabling organizations to enforce strict security controls, manage costs effectively, and grant appropriate levels of autonomy to development teams.
Enterprise environments benefit from multi-account architectures in several critical ways:
Despite these advantages, organizations often face resistance when implementing multi-account patterns:
A key challenge in adopting multi-account strategies is engaging operations teams who may be comfortable with their existing single-account workflows. These teams legitimately worry about:
The solution lies in automation. By implementing infrastructure as code patterns that work seamlessly across account boundaries, organizations can maintain operational efficiency while gaining the security and governance benefits of multi-account architectures. This article examines one such pattern that effectively addresses these challenges.
In the realm of AWS infrastructure management, organizations often face challenges when deploying serverless applications across multiple accounts. This article examines an innovative approach that combines AWS CloudFormation StackSets with AWS Serverless Application Model (SAM) to streamline multi-account deployments.
When deploying serverless applications across an AWS organization with multiple accounts, teams encounter several obstacles:
The solution examined here leverages a “two-tier” StackSet approach that elegantly addresses these challenges.
The architecture uses two different types of CloudFormation StackSets:
This approach provides several advantages:
The codebase implements this architecture with several critical components:
The first deployment tier uses AWS service-managed StackSets to deploy the necessary IAM execution roles:
create-execution-iam-stackset:
aws cloudformation create-stack-set \
--stack-set-name $(STACKSET_EXECUTION_IAM_STACK) \
--template-body file://$(STACKSET_EXECUTION_IAM_TEMPLATE) \
--capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM \
--permission-model SERVICE_MANAGED \
--auto-deployment Enabled=true,RetainStacksOnAccountRemoval=false
This service-managed StackSet deploys an IAM execution role to each target account with permissions to:
The second tier uses a self-managed StackSet to deploy the SAM template across accounts:
create-per-account-stackset:
aws cloudformation create-stack-set \
--stack-set-name $(PER_ACCOUNT_RESOURCES_STACK) \
--template-body file://packaged-$(PER_ACCOUNT_RESOURCES_TEMPLATE) \
--capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM CAPABILITY_AUTO_EXPAND \
--permission-model SELF_MANAGED \
--administration-role-arn arn:aws:iam::$(ADMIN_ACCOUNT_ID):role/$(STACKSET_ADMIN_ROLE_NAME) \
--execution-role-name $(STACKSET_EXECUTION_ROLE_NAME)
This self-managed StackSet deploys the SAM application, which includes:
The deployment follows a precise sequence:
This sequence ensures that all necessary permissions and resources are in place before deploying application code.
This two-tier StackSet architecture offers several compelling benefits:
The self-managed StackSet correctly processes the AWS::Serverless transform through the IAM execution role, which service-managed StackSets can struggle with:
Resources:
FindStaleKeysFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: !Sub KeyRen-${AWS::Region}-${Environment}-stale-keys
CodeUri: lambdas/key_ren-karen-for-api-key-rotation/
Handler: src/key_ren-karen-for-api-key-rotation.handler
By separating IAM role deployment from application deployment, security teams can maintain control over permissions while application teams control functionality:
KeyRenKarenStackSetExecutionRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Ref ExecutionRoleName
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
AWS: !Sub 'arn:aws:iam::${AdministratorAccountId}:role/${AdministratorRoleName}'
Action: sts:AssumeRole
The solution employs sophisticated dynamic account targeting methods that differ between the service-managed and self-managed StackSets, addressing the unique requirements of each deployment pattern.
For the service-managed StackSet that deploys IAM roles, the solution leverages AWS Organizations integration with a specialized targeting approach:
# Create service-managed stack instances with organizational unit targeting
aws cloudformation create-stack-instances \
--stack-set-name $(STACKSET_EXECUTION_IAM_STACK) \
--deployment-targets "OrganizationalUnitIds=[$(ROOT_OU)],AccountFilterType=INTERSECTION,Accounts=[$(TARGET_ACCOUNT_IDS)]" \
--regions $(REGION)
This approach combines two powerful targeting mechanisms:
This hybrid approach provides the benefits of service-managed StackSets (automatic deployment to new accounts) while ensuring precise control over which accounts receive the IAM roles. The system uses a helper script to dynamically generate the target account list:
# Get accounts from all OUs including sub-OUs recursively
OU_ACCOUNT_IDS := $(shell ./get_accounts.sh $(OU_LIST))
This script recursively traverses the organizational structure to identify all accounts in the target OUs, ensuring complete coverage even as the organization evolves.
For the self-managed StackSet that deploys the SAM-based application resources, a different targeting approach is needed:
# Create stack instances in target accounts using direct account targeting
aws cloudformation create-stack-instances \
--stack-set-name $(PER_ACCOUNT_RESOURCES_STACK) \
--accounts $(SPACE_SEPARATED_ACCOUNTS) \
--regions $(REGION)
This approach:
The solution includes sophisticated error handling to ensure all targeted accounts have the necessary execution roles and to manage deployment failures gracefully:
check-per-account-stack-instances:
@echo "Checking stack instances for all target accounts in self-managed stackset..."
@missing_accounts=""; \
for account in $(SPACE_SEPARATED_ACCOUNTS); do \
if ! aws cloudformation list-stack-instances \
--stack-set-name $(PER_ACCOUNT_RESOURCES_STACK) \
--region $(REGION) \
--query "Summaries[?Account=='$$account'].Account" \
--output text | grep -q "$$account"; then \
if [ -z "$$missing_accounts" ]; then \
missing_accounts="$$account"; \
else \
missing_accounts="$$missing_accounts $$account"; \
fi; \
fi; \
done; \
if [ ! -z "$$missing_accounts" ]; then \
echo "Creating stack instances for missing accounts..."; \
aws cloudformation create-stack-instances \
--stack-set-name $(PER_ACCOUNT_RESOURCES_STACK) \
--accounts $$missing_accounts \
--regions $(REGION) \
--operation-preferences MaxConcurrentPercentage=100,FailureTolerancePercentage=100; \
fi
This automated verification ensures that all targeted accounts successfully receive the application resources, maintaining consistency across the organization.
The solution integrates with CI/CD pipelines (Azure Pipelines in this case) for automated deployment:
- task: AWSShellScript@1
name: deploy_stackset
displayName: "Deploy Per-Account Resources as Self-Managed StackSet"
inputs:
awsCredentials: 'xxxxxxxxxx - AzureDevopsDeploymentRole'
regionName: '$(REGION)'
scriptType: 'inline'
inlineScript: |
make deploy-per-account-resources
The example deployment function is an API key rotation system across multiple AWS accounts using this two-tier StackSet approach. The application:
The Lambda function deployed through SAM examines IAM users in each account:
async function processUserKeys(user, totalStaleKeys, staleAndUnusedKeys, oldButRecentlyUsedKeys, actionsPerformed) {
// Process keys for each user
const keys = await iam.listAccessKeys({ UserName: user.UserName }).promise();
for (const key of keys.AccessKeyMetadata) {
// Check if key is stale and take appropriate action
const keyDetails = await iam.getAccessKeyLastUsed({ AccessKeyId: key.AccessKeyId }).promise();
// Process key based on last usage...
}
}
When implementing this architecture, consider these important factors:
The central S3 bucket requires policies allowing cross-account access:
aws s3api put-bucket-policy \
--bucket $(BUCKET)-stackset \
--policy '{"Version":"2012-10-17","Statement":[{"Sid":"AllowCrossAccountAccess","Effect":"Allow","Principal":{"AWS":"*"},"Action":["s3:GetObject","s3:ListBucket"],"Resource":["arn:aws:s3:::$(BUCKET)-stackset","arn:aws:s3:::$(BUCKET)-stackset/*"],"Condition":{"StringEquals":{"aws:PrincipalOrgID":"$(ORG_ID)"}}}]}'
The self-managed StackSet execution role must trust the administrator role:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
AWS: !Sub 'arn:aws:iam::${AdministratorAccountId}:role/${AdministratorRoleName}'
Action: sts:AssumeRole
Both StackSets require specific CloudFormation capabilities:
--capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM CAPABILITY_AUTO_EXPAND
CAPABILITY_AUTO_EXPAND is particularly important for SAM templates.
The multi-account StackSet solution described in this article represents a complex deployment pattern that would typically require weeks of development, testing, and refinement. However, by leveraging Large Language Models (LLMs) like Claude 3.7 Sonnet, enterprises can dramatically accelerate the development of such solutions while maintaining high quality and security standards.
The complex infrastructure code demonstrated in this article—managing IAM permissions across accounts, handling SAM transforms, and ensuring proper trust relationships—can be developed in a fraction of the traditional timeline using LLM assistance:
For example, the intricate Makefile logic for handling account targeting and deployment sequencing—a component that would typically require careful testing and refinement—can be generated in minutes with proper error handling and edge cases considered.
While our team leveraged advanced LLMs for this project, enterprises with sensitive data or regulatory requirements can achieve similar benefits with proper implementation strategies:
Complex multi-account deployment patterns like the one described in this article typically require 2-3 weeks of development time from experienced cloud engineers. With LLM assistance, similar solutions can be developed in as little as 2 days—representing an 85% reduction in development time without compromising quality or security.
This acceleration provides several specific benefits for enterprises implementing multi-account strategies:
Organizations that successfully integrate LLM-assisted development while respecting their data protection requirements position themselves to achieve significant operational efficiencies while maintaining the security benefits of multi-account architectures.
The two-tier StackSet approach—using a service-managed StackSet to deploy IAM roles followed by a self-managed StackSet to deploy SAM resources—creates a powerful pattern for multi-account serverless deployments. It successfully addresses the challenges of cross-account SAM deployments while maintaining proper separation of security and application concerns.
This architecture is particularly valuable for organizations with strict security requirements that need to deploy serverless applications across complex multi-account environments. By leveraging the strengths of both service-managed and self-managed StackSets, you can achieve streamlined, secure, and scalable serverless deployments across your AWS organization. More importantly, this approach helps overcome the operational hesitancy often associated with multi-account architectures by providing a reliable, automated deployment pattern that scales with your organization.
The integration of LLM-assisted development further removes barriers to multi-account adoption by dramatically reducing the complexity and time required to implement these sophisticated patterns. With the right LLM implementation approach, enterprises can accelerate their cloud security posture while maintaining full control over sensitive infrastructure configurations.
Through infrastructure automation like the pattern described in this article, companies can realize the security benefits of account isolation without multiplying operational overhead. The result is a more secure, scalable, and manageable AWS environment that aligns with enterprise governance requirements while remaining operationally practical.
We’re excited to announce that the complete source code for the two-tier StackSet solution described in this article will be made available in the coming weeks. This release will include:
Stay tuned for updates on our Gitlab repository. Once published, the code will serve as a practical starting point that you can customize for your own multi-account AWS architectures, allowing you to immediately benefit from this advanced deployment pattern while adapting it to your specific organizational needs.