top of page

More about AWS Landing Zone (Part 1)

Since AWS launched the Landing Zone capability in June 2018, Automat-IT has invested in building secured and robust solutions around it. The first post about our Landing Zone solutions was published 1 year ago. Since then we added many interesting and useful solutions and AWS features, including: - IP address management - Backup policies

- License manager

- Tag policies - Budget alerts and actions - Security Hub

There will be a series of posts about all of them. In this post we will take a look at IP address management system, Backup policy and AWS License manager.

IP address management system

As I described in the previous post, we have a central networking account with a shared Transit Gateway, then we create VPCs in different accounts that are automatically attached to TGW. In this case we have to prevent IP overlapping. Initially it was a responsibility of the networking team to allocate the correct CIDR block for a particular VPC. Then the CIDR block was passed as input parameter to a CloudFormation template of VPC.

AWS has developed a serverless solution for a IP address management that looks like this:

The solution contains an API Gateway that we will be calling. Behind the API Gateway we have a Lambda function with a core logic of the solution (calculating CIDR block, checking already allocated blocks, updating data in DynamoDB table, releasing CIDR block in case of VPC removal, etc.). As data store we have two DynamoDB tables, one contains initial supernets defined manually by the networking team (common CIDR blocks for different environments and regions), another table, updated by the mentioned Lambda function, will contain relevant CIDR blocks that were already allocated to particular VPCs in different accounts, environments and regions.

Here is an example of data in the DynamoDB supernets table:

The IPAM solution is usually deployed in the Networking account of our Landing zone. Once the solution is deployed and supernets are defined, we can start using it. First of all we have to add a custom lambda backed resource to a CloudFormation template for VPC.

Here is an example:

AWSTemplateFormatVersion: '2010-09-09'
Description: CreatesVPCwithIPAMwithnewCIDRblock,3subnets,InternetGateway,securitygroups,androutetables
  projectEnv:  ### e.g. DEV, STAGE, PROD, MGMT
  VpcCidrSize:  ### e.g. 16, 18, 20, etc., but <= than supernet mask
  CidrApiEndpoint:  ### e.g. https://***
  DDBSubnetsTableName: ip-mgmt-vpc-cidrs ### DynamoDB table from IPAM


    Type: "AWS::EC2::VPC"
      CidrBlock: !GetAttAllocateCidr.cidr  ### Get CIDR block from IPAM

### Deploy Lambda that will be calling IPAM API and getting CIDRs   
    Type: AWS::Lambda::Function
      Runtime: python3.7
      Role: !GetAttLambdaExecutionRole.Arn

    Type: AWS::IAM::Role

    Type: Custom::AllocateCidr
      ServiceToken: !GetAttgetCidr.Arn
      Prefix: !RefVpcCidrSize
      CidrApiEndpoint: !RefCidrApiEndpoint
      AccountId: !Ref AWS::AccountId
      ProjectCode: !RefProjectCode
      Requestor: !RefRequestor
      Reason: !RefReason
      Region: !Ref AWS::Region
      Env: !RefprojectEnv
      ApiRegion: !Select[2,!Split[".",!RefCidrApiEndpoint]]
      StackId: !Ref AWS::StackId

### Deploy Lambda that will be calling IPAM API and updating CIDRs 
    Type: AWS::Lambda::Function
      Runtime: python3.7
      Role: !GetAttUpdateCidrLambdaExecutionRole.Arn

    Type: AWS::IAM::Role

    Type: Custom::updateCidr
      ServiceToken: !GetAttupdateCidr.Arn
      CidrApiEndpoint: !RefCidrApiEndpoint
      Cidr: !GetAttAllocateCidr.cidr
      VpcId: !RefVPC
      ApiRegion: !Select[2,!Split[".",!RefCidrApiEndpoint]]


When we launch the VPC stack from some AWS account within our Landing Zone (API allows calls only within AWS organization), new items appear in the relevant DynamoDB table:

We can see an allocated CIDR block, AWS account ID and VPC ID. Environment, region, reason, requestor, project code, that were passed as parameters in the CloudFormation template for VPC. The IP management solution uses both tables in the process of CIDR block calculation and allocation.

If you have existing VPCs, you can manually add information into the above-mentioned table, so that CIDR block will not be allocated to any other VPC.

Each time a request is made for a CIDR the tool checks how much free space is available for the Environment and Region being requested. Once 80% of all available addresses are used for any environment and region combination an alert is sent to the alert email address you supplied when you installed the solution. This gives the network team time to add more CIDR ranges to resolve the issue.

Backup policy

AWS Backup enables you to create backup plans that define how to back up your AWS resources. The rules in the plan include a variety of settings, such as the backup frequency, the time window during which the backup occurs, the AWS Region containing the resources to back up and the vault in which to store the backup. You can then apply a backup plan to groups of AWS resources identified by using tags. You must also identify an AWS Identity and Access Management (IAM) role that grants AWS Backup permission to perform the backup operation on your behalf.

Backup policies in AWS Organizations combine all of those pieces into JSON text documents. You can attach a backup policy to any of the elements in your organization's structure, such as the root, organizational units (OUs), and individual accounts.

First of all you need to enable Backup policies for your AWS Organization:

Then you have to deploy an IAM role that will be used by AWS Backup service. You can use CloudFormation StackSets and choose all AWS accounts that require backups.

AWSTemplateFormatVersion: '2010-09-09'
Description: CreateBackupservicerole.
    Type: "AWS::IAM::ServiceLinkedRole"
      AWSServiceName: ''
      Description: CreateBackup.

    Type: "AWS::IAM::Role"
      RoleName: AWSBackupDefaultServiceRole
      Path: /service-role/
        Version: "2012-10-17"
          - Effect: "Allow"

For creating a Backup policy you can use either web console or provide a JSON containing all required information.

  "plans": {
    "backup": {
      "regions": {
        "@@assign": [
      "rules": {
        "backup": {
          "schedule_expression": {
            "@@assign": "cron(0 12 ? * * *)"
          "start_backup_window_minutes": {
            "@@assign": "60"
          "complete_backup_window_minutes": {
            "@@assign": "180"
          "lifecycle": {
            "delete_after_days": {
              "@@assign": "30"
          "target_backup_vault_name": {
            "@@assign": "Default"
          "recovery_point_tags": {
            "Name": {
              "tag_key": {
                "@@assign": "Name"