Daily working with the AWS Landing Zone Accelerator
Photo generated by chatGPT

Introduction

In previous posts such as setting up the LZA and using the LZA we elaborated the setup and usage of the LZA. In this post, we will go on with more daily usage/admin task and customizations, such as

  • updating the solution
  • showing possible errors in the LZA pipeline and how to solve them
  • adding nested OUs (organizational Units) for sandbox accounts with SCPs (Service Control Policies)
  • adding customizations via cloudformation stacks

Let’s get started and get into the details!

Updating the solution

The constant update of the solution is a common task, as we want to benefit from new features and bug fixes. In the the documentation, you can find a good guide on how to do this (see here). However, we want to dive a bit deeper into certain topics.

Imagine you are on v1.6.2 and the current version is v1.9.0 and by reading the Release Notes you see that in v1.7.0 the following detail:

Any AWS Config rules in the security-config.yaml are not automatically updated and must be manually validated against the sample configurations for updated configuration files.

Then you decided, ok, let’s first update to v1.7.0 and then to the latest available version. Here are the steps, how to do this:

  1. use the template of the desired version to deploy https://s3.amazonaws.com/solutions-reference/landing-zone-accelerator-on-aws/v1.7.0/AWSAccelerator-InstallerStack.template
  2. see the difference in changes of the sample config you used: via
git diff v1.6.2..v1.7.0 reference/sample-configurations/lza-sample-config/

which leads to the following output: git-diff-1 git-diff-2 git-diff-3 We can see what changed between the two versions in the sample configuration files.

  1. So then adapt the files to your needs.
  2. Now we use a command that we introduced already in a previous post to validate the config against a specific version of the LZA:
cd landing-zone-accelerator-on-aws/source
# to use the version that you want to deploy now
git checkout v1.7.0
cd source 
yarn install
yarn validate-config ../../aws-accelerator-config/
  1. Now you can even transpile and do a dry-run of the LZA. See the full details here
# use the an absolute path
export CODEBUILD_SRC_DIR_Config=../../../../aws-accelerator-config/
cd packages/@aws-accelerator/accelerator
yarn run ts-node \
 --transpile-only cdk.ts synth \
 --require-approval never \
 --config-dir $CODEBUILD_SRC_DIR_Config \
 --partition aws

If you do not have any errors in the error.log file you can commit the config changes.

When I first updated the config and then LZA solution template, those were the times

  • AWSAccelerator-Installer: 9min
  • AWSAccelerator-Pipeline: 2h05min (with CT (Controltower) 50min in between)

Handling Pipeline failures

As of now we only talked about the Happy Path, but as Werner Vogels said

“Everything fails, all the time.”

So how can we deal best when something like this happens

action-failure

  1. go into AWS account where the cloudformation stack failed. We can recommend the assume command / tool
  2. Take a look at the details of the failure action-failure2
  3. Turn the termination protection off
  4. delete the cloudformation stack
  5. retry the stage in LZA pipeline action-pass

Budgets

As mentioned in the previous post, we were using budget notification as follows in the global-config.yaml file

# Report configuration
reports:
  # omitted for brevity...
  budgets:
 - deploymentTargets:
        accounts:
 - Management
      name: accel-budget
      timeUnit: MONTHLY
      type: COST
      amount: 200
      includeUpfront: true
      includeTax: true
      includeSupport: true
      includeSubscription: true
      includeRecurring: true
      includeOtherSubscription: true
      includeDiscount: true
      includeCredit: false
      includeRefund: false
      useBlended: false
      useAmortized: false
      unit: USD
      notifications:
 - type: ACTUAL
          thresholdType: PERCENTAGE
          threshold: 100
          comparisonOperator: GREATER_THAN
          subscriptionType: EMAIL
          address: lza-budget@mycompany.test
 - type: ACTUAL
          thresholdType: PERCENTAGE
          threshold: 90
          comparisonOperator: GREATER_THAN
          subscriptionType: EMAIL
          address: lza-budget@mycompany.test
 - type: ACTUAL
          thresholdType: PERCENTAGE
          threshold: 80
          comparisonOperator: GREATER_THAN
          subscriptionType: EMAIL
          address: lza-budget@mycompany.test
 - type: ACTUAL
          thresholdType: PERCENTAGE
          threshold: 75
          comparisonOperator: GREATER_THAN
          subscriptionType: EMAIL
          address: lza-budget@mycompany.test
 - type: ACTUAL
          thresholdType: PERCENTAGE
          threshold: 50
          comparisonOperator: GREATER_THAN
          subscriptionType: EMAIL
          address: lza-budget@mycompany.test

This is how the notification EMail looks like budgets-mail

However, what is far more interesting is how the costs are distributed if we use the sample config without the whole networking stack. Here you see our bill after one month:

costs-root

What you can note:

  • we have rougly about 40% of the cost from KMS
  • 15% for the AWS config rules to ensure compliance
  • 14% for the logs collection via Kinesis streams

Regarding KMS, the LZA deploys (with our currert condfiguration) around 7 KMS keys with each 1$ per month per account. Here you see the keys:

kms-child

So as conclusion it is possible to run the LZA deploy with around 150$ / month 💰

Sandboxes

As we discussed admin tasks, customizations, and budget, we will now move on to another use case: disposable sandbox accounts with a small blast radius.

For this case, we use a great project called sandbox-accounts-for-events. Therefore we use as recommended a nested OU called Event-Sandbox-Children

Root 
 |
 - Event-Sandbox
 |
 - Event-Sandbox-Children

and apply a merged SCP from the following sources

which results the following json:

{
  "Version": "2012-10-17",
  "Statement": [
 {
      "Sid": "PotentiallyExpensiveActions",
      "Effect": "Deny",
      "Action": [
        "acm-pca:CreateCertificateAuthority",
        "aws-marketplace:AcceptAgreementApprovalRequest",
        "aws-marketplace:Subscribe",
        "backup:PutBackupVaultLockConfiguration",
        "bedrock:CreateProvisionedModelThroughput",
        "bedrock:InvokeAgent",
        "bedrock:InvokeModel",
        "bedrock:InvokeModelWithResponseStream",
        "dynamodb:PurchaseReservedCapacityOfferings",
        "ec2:ModifyReservedInstances",
        "ec2:PurchaseHostReservation",
        "ec2:PurchaseReservedInstancesOffering",
        "ec2:PurchaseScheduledInstances",
        "elasticache:PurchaseReservedCacheNodesOffering",
        "es:PurchaseReservedElasticsearchInstanceOffering",
        "es:PurchaseReservedInstanceOffering",
        "glacier:CompleteVaultLock",
        "glacier:InitiateVaultLock",
        "outposts:CreateOutpost",
        "rds:PurchaseReservedDBInstancesOffering",
        "redshift:PurchaseReservedNodeOffering",
        "route53domains:RegisterDomain",
        "route53domains:RenewDomain",
        "route53domains:TransferDomain",
        "s3-object-lambda:PutObjectLegalHold",
        "s3-object-lambda:PutObjectRetention",
        "s3:BypassGovernanceRetention",
        "s3:PutBucketObjectLockConfiguration",
        "s3:PutObjectLegalHold",
        "s3:PutObjectRetention",
        "savingsplans:CreateSavingsPlan",
        "shield:CreateSubscription",
        "snowball:CreateCluster"
 ],
      "Resource": "*"
 }
 ]
}

Therefore, we first need to create the OUs Event-Sandbox and Event-Sandbox-Children via Controltower and then we add them to the organizational-config.yaml:

organizationalUnits:
 - name: Security
 - name: Infrastructure
  # omitted for brevity...
 - name: Event-Sandbox # <- new
 - name: Event-Sandbox/Event-Sandbox-Children # <- new nested OU
 - name: Suspended

and add the EventsSandboxMain and respective EventsSandbox1 accounts in the accounts-config.yaml

workloadAccounts:
    # omitted for brevity...
 - name: EventsSandboxMain
    description: The Main account for event accounts
    email: root+events-main-random-123@aws.mycompany.test
    organizationalUnit: Event-Sandbox
 - name: EventsSandbox1
    description: The sandbox account 1 for events
    email: root+events-main-1-random-678@aws.mycompany.test # <- using rootmail :)
    organizationalUnit: Event-Sandbox/Event-Sandbox-Children
 - name: EventsSandbox2
  # ...

Now, we can push the config and run the pipeline to apply the changes.

Note: there is still a PR open to adapt the aws-nuke configuration to work with the LZA. See here for more details

Customizations

The LZA solution is also highly custmizable, and there is a job in the pipeline that runs last, which allows you to deploy your own cloudformation stacks

The customizations-config.yaml file allows customers to manage and deploy their own custom CloudFormation templates to accounts in their AWS environment using the LZA.

There is a full blog post here which describes on how to Use Landing Zone Accelerator on AWS customizations to deploy Cloud Intelligence Dashboards 👇

lza-customization

It is a good read, and you can also find a walkthrough in the LZA Immersion Day here.

Conclusion

In this post, we talked about the daily usage of the LZA, admin tasks, and customizations. Some topics were only touched briefly as more in-depth blog posts and hands-on exercises were linked.

We can recommend the following links to dive even deeper:

  • using the LZA solution: link
  • LZA immersion Day: link
  • Discover new features with the tsdocs
  • Simplified network structure setup for the LZA: link

Like what you read? You can hire me, or drop me a message to see which services 💻 may help you 👇