What an AWS Landing Zone Actually Does | PulseSoft
PulseSoft

What an AWS Landing Zone Actually Does

Michael Emmanuel · July 16, 2026 · 12 min read

Introduction

The first time I audited a twenty-account AWS organization without a landing zone, I found seventeen different CloudTrail configurations, nine accounts with root access enabled and no MFA, four accounts with the default VPC still intact and hosting workloads, and one account where GuardDuty had been enabled and then manually disabled, by whom and when, nobody knew. Every account had been provisioned by a different person following a different interpretation of "best practices."

An AWS landing zone is the answer to that problem. Not because it's a compliance checkbox or an AWS recommendation, but because it makes account standardization enforceable rather than aspirational. When every account is provisioned through the same pipeline with the same baseline applied, "is this account configured correctly?" has a yes-or-no answer instead of a "well, it depends on who created it and when." That shift, from tribal knowledge to enforced consistency, is where landing zones reduce operational risk in ways that no policy document or runbook can match.

This post covers what a production landing zone baseline actually contains, how to enforce it at scale without Control Tower, and where the common implementation gaps leave organizations exposed.


The Risk That Landing Zones Actually Mitigate

The instinct when thinking about landing zones is to frame them as a governance tool: something you build to satisfy a compliance audit or a security team request. That framing undersells the operational value and misidentifies the actual risk being mitigated.

The risk is configuration drift across accounts. In a multi-account AWS organization without a landing zone, every account starts from a clean slate and gets configured by whoever provisioned it, against whatever checklist or memory they were working from. Some accounts will have CloudTrail. Some won't. Some will have GuardDuty. Some won't. Some will have the default VPC deleted. Many won't. Over time, the delta between accounts grows, and the delta represents unenforced security policy, untracked API activity, and unmonitored threat signals.

The operational risk surfaces in specific scenarios. During an incident, an engineer assumes CloudTrail is logging in the affected account because it's logging in every other account they've worked in. It isn't. The investigation is blind. During a compliance audit, an auditor asks for evidence that encryption at rest is enforced across all S3 buckets in all accounts. The answer requires individual account audits instead of a Config Aggregator query. During a security review, GuardDuty findings for the past quarter are requested. Two accounts have no findings: not because they're clean, but because GuardDuty was never enabled.

The most dangerous version of this pattern is what I call assumed coverage: when engineers operate on the assumption that security controls are in place because they should be, not because they've verified they are. Assumed coverage is how breaches go undetected. A landing zone replaces assumed coverage with enforced coverage, if the baseline deploys it, it's there; if it doesn't deploy it, the account doesn't get provisioned.

The concrete failure that crystallizes this: a SaaS company I was brought in to assess had enabled AWS Config in their production account and their primary staging account but not in seven other accounts across the org. Their SOC 2 audit asked for evidence of Config rules enforcing encryption standards. They could produce it for two accounts. For the other seven, the auditor issued a finding. The remediation (enabling Config, running the rules, reviewing and resolving the findings), took six weeks. A landing zone with Config as a mandatory baseline component would have prevented the gap from existing.


AWS Deep Dive: What a Landing Zone Baseline Actually Contains

The Non-Negotiable Baseline Components

A landing zone baseline is not a list of nice-to-haves. It's the minimum set of controls that every account must have before it's considered safe to use. The components I treat as non-negotiable across every engagement:

1. CloudTrail with centralized log delivery

CloudTrail logging API calls in every account, delivering to a centralized S3 bucket in the security account with a bucket policy that prevents member accounts from modifying or deleting the logs. The S3 bucket should have Object Lock enabled in compliance mode for regulated environments to prevent log tampering.

resource "aws_cloudtrail" "org_trail" {
  name                          = "org-trail"
  s3_bucket_name                = var.log_archive_bucket
  include_global_service_events = true
  is_multi_region_trail         = true
  enable_log_file_validation    = true

  event_selector {
    read_write_type           = "All"
    include_management_events = true

    data_resource {
      type   = "AWS::S3::Object"
      values = ["arn:aws:s3:::"]
    }

    data_resource {
      type   = "AWS::Lambda::Function"
      values = ["arn:aws:lambda"]
    }
  }

  tags = var.common_tags
}

The enable_log_file_validation field is what most baseline implementations skip. It enables a digest file that lets you verify log file integrity: that no log events were deleted or modified after delivery. For an audit or incident investigation, log integrity is not optional.

2. AWS Config with Organization-Level Aggregation

Config must be enabled in every account and every region where resources are deployed, with a Config Aggregator in the security account that consolidates findings organization-wide. Without the aggregator, compliance questions require per-account investigation. With it, a single query answers compliance questions across the entire org.

The Config rules that belong in every baseline:

  • ROOT_ACCOUNT_MFA_ENABLED, alerts if root MFA is not active
  • S3_BUCKET_SERVER_SIDE_ENCRYPTION_ENABLED, alerts on unencrypted S3 buckets
  • EBS_ENCRYPTED_VOLUMES, alerts on unencrypted EBS volumes
  • RDS_STORAGE_ENCRYPTED, alerts on unencrypted RDS instances
  • VPC_DEFAULT_SECURITY_GROUP_CLOSED, alerts if the default security group has any rules (the default security group should always be empty)
  • CLOUD_TRAIL_ENABLED, alerts if CloudTrail is not active (catches the scenario where someone disables it manually)

3. GuardDuty with Delegated Administration

GuardDuty should be enabled organization-wide via delegated administration from the management account to the security account. This means new accounts get GuardDuty enabled automatically on creation, without any action from the account owner, and findings aggregate in the security account's GuardDuty console.

The non-obvious behavior: GuardDuty's organization-level auto-enable only applies to accounts created after the feature is configured. Existing member accounts at the time of configuration need to be enabled individually. If you're retrofitting GuardDuty to an existing org, run the bulk-enable script against existing members explicitly:

# Enable GuardDuty for all existing member accounts in the organization
aws guardduty list-members \
  --detector-id $DETECTOR_ID \
  --only-associated FALSE \
  --query 'Members[?RelationshipStatus==`Disabled`].AccountId' \
  --output text | tr '\t' '\n' | while read account_id; do
    aws guardduty create-members \
      --detector-id $DETECTOR_ID \
      --account-details AccountId=$account_id,Email=$(aws organizations describe-account \
        --account-id $account_id \
        --query 'Account.Email' \
        --output text)
  done

4. Default VPC Deletion and Security Group Remediation

Every new AWS account comes with a default VPC in every region. The default VPC has a default Internet Gateway, default subnets in every AZ, and a default security group with rules that allow inbound traffic from other resources in the same security group and all outbound traffic. It is a governance liability: workloads launched in it have implicit network paths that weren't deliberately designed, and the default security group's permissive rules are the opposite of least privilege.

A landing zone baseline should delete the default VPC in every region on account creation. This is a one-time operation that can be scripted via the AWS CLI or automated with a Lambda function triggered by the account creation event in EventBridge:

# Delete default VPC in a specific region
VPC_ID=$(aws ec2 describe-vpcs \
  --filters "Name=isDefault,Values=true" \
  --query 'Vpcs[0].VpcId' \
  --output text \
  --region $REGION)

if [ "$VPC_ID" != "None" ]; then
  # Detach and delete Internet Gateway
  IGW_ID=$(aws ec2 describe-internet-gateways \
    --filters "Name=attachment.vpc-id,Values=$VPC_ID" \
    --query 'InternetGateways[0].InternetGatewayId' \
    --output text \
    --region $REGION)
  aws ec2 detach-internet-gateway --internet-gateway-id $IGW_ID --vpc-id $VPC_ID --region $REGION
  aws ec2 delete-internet-gateway --internet-gateway-id $IGW_ID --region $REGION

  # Delete subnets
  aws ec2 describe-subnets \
    --filters "Name=vpc-id,Values=$VPC_ID" \
    --query 'Subnets[].SubnetId' \
    --output text \
    --region $REGION | tr '\t' '\n' | while read subnet_id; do
      aws ec2 delete-subnet --subnet-id $subnet_id --region $REGION
    done

  # Delete the VPC
  aws ec2 delete-vpc --vpc-id $VPC_ID --region $REGION
fi

Deploying the Baseline at Scale with CloudFormation StackSets

CloudFormation StackSets with service-managed permissions (using Organizations integration) is the mechanism that makes landing zone baseline deployment automatic at scale. A StackSet configured with AUTO_DEPLOYMENT enabled will automatically deploy the baseline stack to every new account added to the target OU: no manual trigger, no pipeline invocation required.

resource "aws_cloudformation_stack_set" "security_baseline" {
  name             = "security-baseline"
  description      = "Mandatory security baseline for all member accounts"
  permission_model = "SERVICE_MANAGED"

  auto_deployment {
    enabled                          = true
    retain_stacks_on_account_removal = false
  }

  template_body = file("${path.module}/templates/security-baseline.yaml")

  operation_preferences {
    failure_tolerance_percentage = 0
    max_concurrent_percentage    = 25
  }

  capabilities = ["CAPABILITY_NAMED_IAM"]
  tags         = var.common_tags
}

resource "aws_cloudformation_stack_set_instance" "security_baseline_org" {
  stack_set_name = aws_cloudformation_stack_set.security_baseline.name

  deployment_targets {
    organizational_unit_ids = [var.workloads_ou_id]
  }

  operation_preferences {
    failure_tolerance_percentage = 0
    max_concurrent_percentage    = 25
  }
}

The non-obvious StackSet behavior: failure_tolerance_percentage = 0 means a single account failure stops the deployment. This is the right setting for a security baseline: you want to know immediately if any account failed to receive the baseline, rather than having the operation continue and succeed for 90% of accounts while silently skipping the rest. Use max_concurrent_percentage = 25 to limit blast radius if the StackSet template has a bug; 25% of accounts failing is easier to remediate than 100%.

Rendering diagram…

Enjoying this so far?

Join thousands of engineers receiving practical cloud, DevOps, Kubernetes, Infrastructure and AI engineering insights.

No spam. Unsubscribe anytime.

Tradeoffs & Decision Framework

The primary decision point for landing zone implementation is whether to use AWS Control Tower or build a custom baseline with Organizations, StackSets, and SCPs directly.

Control Tower is the right choice when:

  • The team is building a landing zone for the first time and doesn't have deep Organizations and StackSets expertise
  • Compliance requirements align well with AWS Security Hub's managed standards (CIS AWS Foundations Benchmark, AWS Foundational Security Best Practices)
  • Speed of deployment matters more than customization: a Control Tower landing zone can be operational in hours; a custom build takes days to weeks
  • The team needs the Account Factory UI for non-technical stakeholders to request accounts through a governed self-service process

Custom baseline is the right choice when:

  • The organization has strong IaC discipline and needs every landing zone component managed in Terraform state
  • Compliance requirements have specific controls that don't map cleanly to Control Tower's guardrail library
  • The team has existing Organizations setup that predates Control Tower and migration overhead isn't justified
  • Control Tower's managed resources would conflict with existing automation or Terraform-managed infrastructure

The hybrid approach that often makes sense: Use Control Tower for the organizational structure and account provisioning (Account Factory, OU management, IAM Identity Center integration), and layer custom StackSets and SCPs on top for controls that Control Tower's guardrails don't cover. Control Tower's Customizations for AWS Control Tower (CfCT) pipeline is specifically designed for this pattern.

What neither approach solves automatically: Existing accounts that were provisioned before the landing zone was established. Both Control Tower enrollment of existing accounts and manual StackSet deployment to existing accounts require individual account-level remediation work. Plan for it. Estimate one to two hours per account for remediation and testing in a well-documented org; more in a messy one.


Lessons From the Field

1. The biggest gap in most landing zone implementations isn't the baseline that wasn't deployed, it's the existing accounts that were never enrolled. Completed a landing zone implementation for a healthtech company that took twelve weeks. Four weeks of that was building the baseline and the account vending pipeline. Eight weeks was remediating the twenty-three accounts that had been created before the landing zone existed. Existing account remediation is almost always the majority of the work and is almost always underestimated.

2. Log archive buckets without Object Lock will eventually have their logs deleted. At a fintech audit engagement, the centralized CloudTrail log bucket had a lifecycle policy that deleted logs after 90 days and no Object Lock configuration. During a security investigation for a suspected credential compromise, the logs needed to confirm or rule out access going back six months. They were gone. Enable S3 Object Lock in governance or compliance mode on the log archive bucket before any logs are written to it. You cannot enable Object Lock on a bucket that already has objects in it without creating a new bucket.

3. GuardDuty findings with no response process are noise, not signal. Deployed GuardDuty organization-wide for a SaaS client and then watched the finding count grow from zero to 4,400 over the following month. Nobody had a process for reviewing findings, triaging severity, or remediating confirmed threats. The findings became background noise and lost their value entirely. A GuardDuty deployment is only as useful as the response process attached to it. Build the runbook before you enable the service.

4. StackSet drift is real and will undo your baseline configuration if you don't detect it. A member account engineer with AdministratorAccess manually changed a Config rule that had been deployed by a StackSet, turning off a rule that was alerting on a resource configuration they found inconvenient. The StackSet instance showed as OUTDATED in the console. Nobody noticed for two months. Enable AWS Config rules that detect StackSet instance drift, or implement a Lambda that alerts on OUTDATED StackSet instance status changes. Baseline enforcement isn't automatic just because the StackSet deployed it.

5. IAM Identity Center must be configured as part of the landing zone, not after. Built a landing zone for an enterprise client that delayed IAM Identity Center configuration because "it wasn't part of the initial scope." When accounts started being provisioned, engineers were accessing them using locally created IAM users, precisely the pattern a landing zone is supposed to eliminate. Human access configuration is not optional post-provisioning work. It must be part of the provisioning pipeline. An account that engineers can only access with root or locally-created IAM users is not a governed account.


Final Thoughts

The AWS landing zone conversation has matured significantly in the last few years. Control Tower has made the baseline case easier to implement, Security Hub has made compliance posture easier to visualize, and the broader industry awareness of multi-account security design has raised the floor for what teams consider minimum viable governance. More organizations start multi-account projects with a landing zone in scope than did three years ago.

What hasn't changed is the remediation problem. Most of the organizations we work with have some accounts that predate any governance structure, accounts from acquisitions, accounts created for deprecated projects, accounts created when the org was four people and none of this felt necessary. Those accounts carry the highest risk and the most remediation complexity.

The lesson I keep returning to: the best time to implement a landing zone baseline is before the first account is created. The second best time is now. Every account provisioned without a baseline is an account you'll eventually have to remediate manually, against a live environment, with the risk that something you change breaks a running workload. The accumulation of unbaselined accounts is how a governance problem becomes a governance crisis.

This is foundational work we design and build at PulseSoft. If your multi-account AWS organization has grown beyond its current governance structure, or you're starting a new org and want the baseline right the first time, let's talk.


Key Takeaways

  • A landing zone replaces assumed coverage with enforced coverage. In organizations without one, engineers assume security controls exist because they should. With one, every account is provably configured to the same baseline, because the pipeline that provisioned it can only produce one outcome.
  • CloudTrail log file validation is not optional for security-relevant auditing. enable_log_file_validation produces integrity digest files that allow you to verify no log events were deleted or modified after delivery. Without it, log evidence in a security investigation is unverifiable.
  • GuardDuty's auto-enable for new organization members does not retroactively cover existing accounts. Existing members at the time of configuration must be enrolled individually. Run the bulk-enable script against all members and verify coverage before treating the org as fully monitored.
  • CloudFormation StackSets with failure_tolerance_percentage = 0 will stop deployment on the first failed account. This is the right configuration for a security baseline, silent partial deployment is worse than a failed deployment you know about immediately.
  • S3 Object Lock must be configured before any objects are written to the bucket. You cannot enable Object Lock on an existing bucket with objects in it. For log archive buckets, configure Object Lock before the first CloudTrail delivery: not after logs are already accumulating.
  • StackSet baseline deployment does not prevent manual drift inside member accounts. Engineers with AdministratorAccess can modify or disable StackSet-deployed resources. Monitor for OUTDATED StackSet instance status and alert on Config rules being disabled in any member account.
  • Existing account remediation is almost always the majority of a landing zone implementation effort. Plan for one to two hours per account in a well-documented org. Eight weeks of remediation work for twenty existing accounts is typical, not exceptional, and it is almost always underestimated in initial project scopes.

Get insights like this in your inbox

Join thousands of engineers receiving practical cloud, DevOps, Kubernetes, Infrastructure and AI engineering insights.

No spam. Unsubscribe anytime.

← Back to Blog