Landing Zone Architecture

Design cloud landing zones that provide secure, governed foundations for workloads. Covers account structure, network topology, identity federation, guardrails, logging, and the patterns that enable teams to move fast within secure boundaries.

A landing zone architecture defines the foundational cloud environment that enables consistent, repeatable, and governed deployment of cloud resources across multiple teams, applications, and environments. It matters when an organisation scales beyond a single AWS account or Azure subscription, where ad-hoc resource provisioning leads to sprawl, drift, and operational complexity. A landing zone is the starting point for every new project, ensuring that all new work begins on a pre-configured, policy-enforced, and monitored foundation.

Core Principles and Responsibilities

A landing zone is not just infrastructure as code; it is a delivery platform for cloud operations. It establishes a shared, multi-tenant foundation that all teams use as their default environment. The core responsibilities are:

The landing zone is the entry point for every new application, service, or workload. When a team creates a new project, they do not provision resources from scratch. Instead, they “land” into the zone by applying a configuration that declares their intent: environment (dev, staging, prod), application tier (web, api, data), and operational requirements (logging level, retention period, auto-scaling policy).

Establishing the Landing Zone

To create a landing zone, teams start with a core infrastructure repository that defines the baseline. This repository contains configuration files for network, IAM, and foundational services. The configuration is versioned, tested, and deployed through a continuous delivery pipeline.


version: 1.0
name: landing-zone-core
description: Core infrastructure for all cloud projects

parameters:
  environment: dev
  application: orders-service
  region: us-east-1
  vpc-cidr: 10.0.0.0/16
  enable-logging: true
  enable-backup: true
  retention-days: 90

resources:
  - type: aws::vpc
    name: shared-vpc
    cidr: 10.0.0.0/16
    azs: [us-east-1a, us-east-1b, us-east-1c]
    public-subnets:
      - cidr: 10.0.1.0/24
        availability-zone: us-east-1a
      - cidr: 10.0.2.0/24
        availability-zone: us-east-1b
    private-subnets:
      - cidr: 10.0.10.0/24
        availability-zone: us-east-1a
      - cidr: 10.0.11.0/24
        availability-zone: us-east-1b
    route-tables:
      - name: public-route-table
        routes:
          - destination: 0.0.0.0/0
            target: internet-gateway
      - name: private-route-table
        routes:
          - destination: 10.0.0.0/16
            target: local
          - destination: 0.0.0.0/0
            target: nat-gateway
    tags:
      Environment: '{{ environment }}'
      Application: '{{ application }}'
      Owner: '{{ owner }}'
      ManagedBy: 'landing-zone'
    depends-on: [internet-gateway, nat-gateway]

  - type: aws::iam::role
    name: app-execution-role
    assume-role-policy:
      Version: "2012-10-17"
      Statement:
        - Effect: Allow
          Principal:
            Service: lambda.amazonaws.com
          Action: sts:AssumeRole
    managed-policies:
      - arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
      - arn:aws:iam::aws:policy/CloudWatchLogsFullAccess
    tags:
      Environment: '{{ environment }}'
      Application: '{{ application }}'
      RoleType: execution

This configuration is applied using a declarative tool such as Terraform, AWS CloudFormation, or Pulumi. The deployment process is automated and idempotent: running the same configuration multiple times produces the same state.

When a team creates a new project, they instantiate the landing zone by passing a project manifest:

{
  "application": "user-profile-service",
  "environment": "prod",
  "region": "eu-west-1",
  "tags": {
    "Owner": "engineering-team",
    "BusinessUnit": "customer-engagement"
  },
  "services": [
    {
      "name": "web-api",
      "type": "aws::ecs::cluster",
      "settings": {
        "capacity": 2,
        "task-definition": "user-api-task"
      }
    },
    {
      "name": "database",
      "type": "aws::rds::instance",
      "settings": {
        "engine": "postgres",
        "instance-class": "db.t3.medium",
        "backup-retention": 30
      }
    }
  ]
}

This manifest is consumed by a landing zone orchestrator—a CI/CD pipeline or a configuration service—that applies the core template and then instantiates the application-specific resources.

Governance and Policy Enforcement

Governance is enforced through policy-as-code, where rules are defined independently of infrastructure and applied across all resources. The landing zone uses a policy engine to validate, audit, and enforce configuration.

Policies are evaluated as part of the deployment pipeline. Each policy checks a set of criteria and fails the build if any rule is violated.

# policies/iam-policy.yaml
name: enforce-iam-tags
description: All IAM resources must have Environment and Owner tags
rules:
  - resource-type: aws::iam::role
    required-tags:
      - Environment
      - Owner
    enforcement: "required"
    description: "All roles must have Environment and Owner tags"
  - resource-type: aws::iam::policy
    required-tags:
      - Environment
      - Application
    enforcement: "recommended"
    description: "Policies should include Application tag"
  - resource-type: aws::iam::user
    required-tags:
      - Environment
      - Owner
      - Department
    enforcement: "required"
    description: "All users must have Department tag"

# Policies can be evaluated using a tool like:
#   aws cloudformation validate-template --template-body file://templates/landing-zone.yaml
#   aws config put-remediation-configurations --remediation-configurations file://policies/iam-policy.yaml

A failure in policy enforcement returns a clear error:

{
  "error": "Policy Violation",
  "policy": "enforce-iam-tags",
  "violations": [
    {
      "resource": "arn:aws:iam::123456789012:role/user-api-role",
      "type": "aws::iam::role",
      "rule": "required-tags",
      "expected": ["Environment", "Owner"],
      "actual": ["Environment", "Application"],
      "missing": ["Owner"]
    },
    {
      "resource": "arn:aws:iam::123456789012:user/[email protected]",
      "type": "aws::iam::user",
      "rule": "required-tags",
      "expected": ["Environment", "Owner", "Department"],
      "actual": ["Environment", "Owner"],
      "missing": ["Department"]
    }
  ]
}

This error stops the CI pipeline, prevents deployment, and notifies the responsible team.

Network and Security Topology

The landing zone defines a multi-tiered network architecture with isolated subnets and consistent security rules.

Every new application lands in a shared VPC or a dedicated VPC with consistent naming and tagging. The network layout includes:

Security is enforced through security group templates and network ACLs.

# templates/security-groups.yaml
defaults:
  ingress:
    - protocol: tcp
      port: 80
      source: 0.0.0.0/0
      description: "HTTP access from internet"
    - protocol: tcp
      port: 443
      source: 0.0.0.0/0
      description: "HTTPS access from internet"
  egress:
    - protocol: all
      destination: 0.0.0.0/0
      description: "All outbound traffic"

services:
  web:
    description: "Web frontend"
    ingress:
      - protocol: tcp
        port: 80
        source: 0.0.0.0/0
        description: "HTTP for web"
      - protocol: tcp
        port: 443
        source: 0.0.0.0/0
        description: "HTTPS for web"
      - protocol: tcp
        port: 22
        source: 10.0.1.0/24
        description: "SSH from dev team"
    egress:
      - protocol: tcp
        port: 5432
        destination: 10.0.10.0/24
        description: "Database access"
      - protocol: tcp
        port: 9000
        destination: 10.0.20.0/24
        description: "API gateway access"

Security groups are applied at deployment time and verified via a post-deployment validation step:

$ aws ec2 describe-security-groups \
    --filters Name=group-name,Values=web-service-sg \
    --query 'SecurityGroups[0].IpPermissions[]' \
    --output json
[
  {
    "IpProtocol": "tcp",
    "FromPort": 80,
    "ToPort": 80,
    "IpRanges": [
      {
        "CidrIp": "0.0.0.0/0",
        "Description": "HTTP access from internet"
      }
    ]
  },
  {
    "IpProtocol": "tcp",
    "FromPort": 443,
    "ToPort": 443,
    "IpRanges": [
      {
        "CidrIp": "0.0.0.0/0",
        "Description": "HTTPS access from internet"
      }
    ]
  },
  {
    "IpProtocol": "tcp",
    "FromPort": 22,
    "ToPort": 22,
    "IpRanges": [
      {
        "CidrIp": "10.0.1.0/24",
        "Description": "SSH from dev team"
      }
    ]
  }
]

The most common failure in network configuration is incorrect routing between subnets. A service in a private subnet cannot reach a database in another private subnet because the route table lacks a route to the correct CIDR block. This is silent until logs show Connection timed out or Could not resolve host.

Identity and Access Management

The landing zone centralizes identity through federated authentication and role-based access control.

All applications use AWS IAM roles that are assumed by services at runtime. The landing zone defines a role template:

# templates/iam-role-template.yaml
name: "{{ application }}-{{ environment }}-role"
assumed-by: "ecs-tasks.amazonaws.com"
policies:
  - inline:
      name: "s3-access"
      policy-document:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Action:
              - s3:GetObject
              - s3:PutObject
            Resource: "arn:aws:s3:::{{ application }}-data/*"
  - managed:
      arn: "arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy"
  - managed:
      arn: "arn:aws:iam::aws:policy/SecretsManagerReadWrite"
tags:
  Environment: "{{ environment }}"
  Application: "{{ application }}"
  Tier: "backend"
  Owner: "{{ owner }}"

Applications use this role via EC2 instance metadata, AWS STS, or OpenID Connect.

When a task is launched in ECS, it assumes the role:

{
  "roleArn": "arn:aws:iam::123456789012:role/user-profile-service-prod-role",
  "roleSessionName": "ecs-task-1234567890",
  "durationSeconds": 3600
}

The application then uses the credentials to access AWS services.

A common failure is role assumption timeout. The ECS task starts, but the role is not assumed due to a misconfigured trust relationship or STS endpoint.

{
  "error": "STSException",
  "code": "InvalidIdentityProvider",
  "message": "The identity provider does not support the specified role.",
  "details": {
    "expected": {
      "principal": "ecs-tasks.amazonaws.com",
      "condition": {
        "StringEquals": {
          "sts:AssumedRole": "arn:aws:iam::123456789012:role/user-profile-service-prod-role"
        }
      }
    },
    "actual": {
      "principal": "ecs-tasks.amazonaws.com",
      "condition": {
        "StringEquals": {
          "sts:AssumedRole": "arn:aws:iam::123456789012:role/user-profile-service-dev-role"
        }
      }
    }
  }
}

This error is silent until logs show AWS::STS::AssumeRole failed with 400.

Observability and Operations

The landing zone includes standard observability tooling. Every application is instrumented with:

The landing zone defines a standard logging configuration:

# templates/logging-config.yaml
format: json
level: info
fields:
  application: "{{ application }}"
  environment: "{{ environment }}"
  service: "{{ service }}"
  version: "{{ version }}"
  host: "{{ hostname }}"

destination:
  type: cloudwatch
  log-group: "/app/{{ application }}/{{ environment }}"
  retention-days: 90
  batch-size: 1000
  flush-interval: 10s

Applications emit logs in this format:

{
  "timestamp": "2023-10-05T12:34:56.789Z",
  "level": "info",
  "message": "User profile fetched",
  "application": "user-profile-service",
  "environment": "prod",
  "service": "web-api",
  "version": "1.2.0",
  "host": "ip-10-0-1-10.ec2.internal",
  "userId": "u12345",
  "durationMs": 142
}

A failure in observability is missing log fields. The logs arrive, but application, environment, and service are missing. The root cause is an inconsistent logging configuration across services.

Key Failure Modes

The landing zone is not a one-time setup. It is a living system, continuously updated with new templates, policies, and tooling. The most valuable insight is that a landing zone is not the infrastructure—it is the process of how teams interact with that infrastructure.

This page was rewritten on 17 October 2026. It replaced a templated version that was not specific to its own title. How these pages are written and checked. If anything here is wrong, tell us at [email protected] and we will correct it.