More about AWS Landing Zone (Part 1)

Table of Contents

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
Metadata:
...
Parameters:
...
  projectEnv:  ### e.g. DEV, STAGE, PROD, MGMT
  VpcCidrSize:  ### e.g. 16, 18, 20, etc., but <= than supernet mask
  CidrApiEndpoint:  ### e.g. https://***.execute-api.ap-southeast-2.amazonaws.com/v0
  DDBSubnetsTableName: ip-mgmt-vpc-cidrs ### DynamoDB table from IPAM
...

Conditions:
...

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

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

  LambdaExecutionRole:
    Type: AWS::IAM::Role
...

  AllocateCidr:
    Type: Custom::AllocateCidr
    Properties:
      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 
  updateCidr:
    Type: AWS::Lambda::Function
    Properties:
      Code:
...
      Runtime: python3.7
      Role: !GetAttUpdateCidrLambdaExecutionRole.Arn
...

  UpdateCidrLambdaExecutionRole:
    Type: AWS::IAM::Role
...

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

Outputs:
...

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.
Resources:
  CustomServiceLinkedRole:
    Type: "AWS::IAM::ServiceLinkedRole"
    Properties:
      AWSServiceName: 'backup.amazonaws.com'
      Description: CreateBackup.

  BackupRole:
    Type: "AWS::IAM::Role"
    Properties:
      RoleName: AWSBackupDefaultServiceRole
      Path: /service-role/
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Principal:
              Service:
                -"backup.amazonaws.com"
            Action:
              -"sts:AssumeRole"
      ManagedPolicyArns:
        -"arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForBackup"
        -"arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForRestores"

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

{
  "plans": {
    "backup": {
      "regions": {
        "@@assign": [
          "ap-southeast-2"
        ]
      },
      "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"
              },
              "tag_value": {
                "@@assign": "BackupOrg"
              }
            }
          }
        }
      },
      "backup_plan_tags": {
        "Name": {
          "tag_key": {
            "@@assign": "Name"
          },
          "tag_value": {
            "@@assign": "Backup"
          }
        }
      },
      "selections": {
        "tags": {
          "backup": {
            "iam_role_arn": {
              "@@assign": "arn:aws:iam::$account:role/service-role/AWSBackupDefaultServiceRole"
            },
            "tag_key": {
              "@@assign": "Backup"
            },
            "tag_value": {
              "@@assign": [
                "true"
              ]
            }
          }
        }
      },
      "advanced_backup_settings": {
        "ec2": {
          "windows_vss": {
            "@@assign": "disabled"
          }
        }
      }
    }
  }
}

In the above policy we select an AWS region for backups, schedule, backup window, lifecycle, a backup vault name and the most important section “selections”. In the “selections” we have to set the IAM role that was deployed earlier and define a TagKey-Value pair (in our case Backup=true), which will be added to AWS resources that require backup, including Amazon Elastic Compute Cloud (Amazon EC2) instances, Amazon Elastic Block Store (Amazon EBS) volumes, Amazon Relational Database Service (Amazon RDS) databases (including Amazon Aurora clusters), Amazon DynamoDB tables, Amazon Elastic File System (Amazon EFS) file systems, Amazon FSx for Lustre file systems, Amazon FSx for Windows File Server file systems, and AWS Storage Gateway volumes.

Once a backup policy is created, we can attach it to an AWS account or Organizational Unit (OU)

Then an AWS Backup Plan will be created in every member account where the policy was attached to:

Let’s check how it works with the DynamoDB table for IPAM solution in the Networking account and a Jenkins server installed to EC2 instance in DevOps account.

In the “Backups” tab we can see backups created by a defined schedule.

In the AWS Backup console we can see all Protected resources of the current account.

The same procedure is for EC2 instances, add tag and check backups.

AWS License manager

AWS License Manager makes it easier to manage your software licenses from vendors such as Microsoft, SAP, Oracle, and IBM across AWS and on-premises environments. AWS License Manager lets administrators create customized licensing rules that mirror the terms of their licensing agreements. Administrators can use these rules to help prevent licensing violations, such as using more licenses than an agreement stipulates. Rules in AWS License Manager help prevent a licensing breach by stopping the instance from launching or by notifying administrators about the infringement. Administrators gain control and visibility of all their licenses with the AWS License Manager dashboard and reduce the risk of non-compliance, misreporting, and additional costs due to licensing overages. Independent software vendors (ISVs) can also use AWS License Manager to easily distribute and track licenses.

Our use case here is a bit different. Sometimes we need to subscribe to some AMI from the AWS Marketplace. If we have dozens or hundreds of accounts, AWS License manager can help us manage subscriptions centrally.

By linking License Manager with AWS Organizations, you can enable cross-account discovery of computing resources throughout your organization.

You can enable trusted access using only AWS License Manager.

To enable trusted access between Organizations and License Manager

  1. Sign in to the AWS Management Console using your organization’s management account.
  2. Navigate to the License Manager console and choose Settings.
  3. Choose Edit.
  4. Choose Link AWS Organizations accounts.

Enable trusted access in AWS Marketplace of Master account

Once you subscribed to any product from the marketplace, you will see it in Manage

Subscriptions

There is a managed WAF ACL from Marketplace and AMI for OpenVPN Access Server that require a subscription for every AWS account where it is going to be used. First of all I subscribe to these products in the master account. Next I grant access for member accounts of the AWS organization.

On the AWS managed licenses page, you can choose a specific license to see its details and perform entitlement distribution. At launch, the entitlement distribution functionality is supported for AWS Marketplace AMI, Containers, and Machine Learning products.

You can create a grant for AWS account ot whole AWS Organization

You will see a list of accounts that are members of AWS Organization

Member accounts get subscriptions automatically.

Unfortunately we can not grant a subscription for WAF ACL from the Marketplace yet, but it works with AMI, Containers, and Machine Learning products.

Conclusion

Separating your environment to multiple AWS accounts is a best practice for a well-architected infrastructure recommended by AWS. We are continuously working on discovery and implementing new features in our Landing Zone solution. In the next part I will show you how to work with budgets, tag policies and AWS Security Hub.