Enabling External Deployments within the AWS Landing Zone Accelerator

Richard Keit
Principal Solution Architect

Richard Keit
Principal Solution Architect
Creating a Secure Landing Zone
Background on Landing Zone Accelerator
The AWS Landing Zone Accelerator (LZA) is a solution that helps organisations quickly set up a secure, multi-account AWS environment based on AWS best practices. It provides a standardised architecture that incorporates security, compliance, and operational capabilities, enabling enterprises to accelerate their cloud adoption journey while maintaining governance and control.
While it is an open-source solution, it has a dedicated AWS engineering team that is the core maintainers of the solution and has greatly standardised the deployment format for customers and partners alike.
Below is the standard deployment approach that is included out of the box, which provides for the delivery pipeline deployed within the Management Account. It’s worth noting the AWS whitepaper that dives into the details of a secure landing zone using multiple AWS accounts, reducing access to the Management Account, given that it has elevated permissions within the AWS Organisation. For rapid proof-of-concepts and initial setup, it’s acceptable to use the Management Account; however, with continued use, it increases the risk profile, as operators must be in that account, and through this period, the potential for misadventure increases (through human error or compromised credentials).

Introducing the External Deployment Account
With the above in mind, AWS released the feature allowing the pipeline to be deployed in an external account, therefore significantly reducing the foot traffic needed in the AWS Management Account.

What we aim to walk through in this article is to highlight exactly what is required for anyone considering this for a new or existing solution, where a migration from the existing pipeline will need to take place.
The “Deployment” Account
The most basic of prerequisites is the presence of the “Deployment” account. Like with most things in technology, there are multiple ways to achieve an outcome, for example:
- Create an account via the AWS Organisations Service
- Create an account using AWS Control Tower
- Create an account using the LZA framework
Our approach is to use the LZA Framework account vending process to create an account, which feels the cleanest and most straightforward. This can be applied within an already existing installation or at the end of a new installation (following the completion of Deploy the solution).
# accounts-config.yaml
workloadAccounts:
- name: Deployment
description: The external deployment account
email: <network>@example.com
organizationalUnit: Infrastructure # Can be in any OU
The “AcceleratorPipelineDeploymentRole” access role
The Deployment Account pipeline uses this new IAM role to perform actions within the Management account, therefore, due care needs to taken when crafting the trust policy.
We’ve built a robust process and CI practices using GitHub Actions, and the diagram below highlights the new architecture with the External Deployment Account.

Below is an example given the above to provide the required AWS Trust Policy:
- Effect: Allow
Principal:
AWS: !Sub 'arn:aws:iam::${PipelineDeploymentAccountId}:root'
Action: 'sts:AssumeRole'
Condition:
StringLike:
aws:PrincipalArn: !Sub arn:aws:iam::${PipelineDeploymentAccountId}:role/${AcceleratorQualifier}-*
# Only create Github permissions if required
- !If
- ExternalDeploymentPermissions # AWS Condition
- Effect: Allow
Action: sts:AssumeRole
Principal:
AWS: !Sub 'arn:aws:iam::${PipelineDeploymentAccountId}:root'
Condition:
ArnLike:
aws:PrincipalArn: !Sub 'arn:aws:iam::${PipelineDeploymentAccountId}:role/${BootstrapRoleStackName}*'
StringLike:
# This is spoken about further down the article
sts:RoleSessionName: acceleratorAssumeRoleSession
Why is there a complicated trust policy for the Deployment account role?
We’ve built an entire CI process (continuous integration) centered around multiple AWS organisations for multiple engineers to work on features in parallel and an integration environment where these features are validated prior to being promoted to a customer’s Production landing zone. This validation process happens via GitHub Actions (could be another provider), and therefore, the trust policy needs to allow this Principal.
A key callout for the validation process, the validate-config
process behaves in the following way:
- Completes the
Replacements
process (if applicable) where environment-specific values are inserted into the configuration files
The replacements process can rely on AWS SSM Parameter store values — this is a powerful technique allowing environment-agnostic SSM values to be stored in the respective environments to keep the configuration of the LZA consistent across environments.
This happens within the context of the Principal running the command (either
CodeBuild
orGithubActions
in our example in the Deployment Account)
- Then, assumes the AcceleratorPipelineDeploymentRole in the Management Account (if using the external account)
- Completes the validation process
⚠️ MANAGEMENT_ACCOUNT_ROLE_NAME
and MANAGEMENT_ACCOUNT_ID
environment variables are required to be set to use the external deployment account. Otherwise, the following error message is presented:

Failed validation running in the External Deployment account without the required environment variables
We’ve raised an issue to have the documentation updated for the same.

MANAGEMENT_ACCOUNT_ID
and MANAGEMENT_ACCOUNT_ROLE_NAME
environment variablesThe automation (kicked off from Github Actions) we had built used a Principal following a privilege model to install the InstallerStack, ControlTower, etc. With the above in mind, those role needs to be assumed by the highly privileged AcceleratorPipelineDeploymentRole
; therefore, on the trust policy, we wanted to add extra controls and just allow the GitHub pipeline the permission to assume it directly.
How that Condition relied on looking at the LZA Codebase — referenced below:
const assumeRoleCredential = await throttlingBackOff(() =>
stsClient.assumeRole({ RoleArn: roleArn, RoleSessionName: 'acceleratorAssumeRoleSession' }).promise(),
);
ℹ️ Note: If AWS change the below hard coding of the RoleSessionName
, this will break the above trust policy
Generate and deploy a new InstallerStack template
This is well-documented on the External Deployment Pipeline page. Pay keen attention to what was entered for the AcceleratorQualifier
In the Accelerator Pipeline Deployment Role, if there is a mismatch, the pipeline will fail to assume the role in the Management account.
Run the Pipeline
If you’re having issues with the Diff
Stage, note that we completed a fix for this https://github.com/awslabs/landing-zone-accelerator-on-aws/issues/753, and it is available in the latest release (v1.12.2).
CLI Usage
As mentioned above, if using the external deployment account, there are considerations such as:
- Ensure the environment variables are set
- Ensure the
AcceleratorPipelineDeploymentRole
trust policy allows this Principal to assume the role.
Key Takeaways
- AWS Landing Zone Accelerator (LZA) enables rapid setup of secure, multi-account AWS environments following best practices
- External deployment account capability reduces security risks by moving pipeline operations outside the Management Account
- A deployment account can be created through LZA’s account vending process for seamless integration
AcceleratorPipelineDeploymentRole
requires careful trust policy configuration, especially for CI/CD implementations- Environment variables
MANAGEMENT_ACCOUNT_ROLE_NAME
andMANAGEMENT_ACCOUNT_ID
are mandatory for the external deployment setup - Successful implementation requires precise matching of AcceleratorQualifier values and proper role assumptions
If you need assistance with your AWS Landing Zone journey, reach out — we have a rich background in assessments in Brownfield to Greenfield Migrations/Uplifts and Greenfield Landing Zone design, implementation, and operations.