Back to blog
AWSBest PracticesCloud SecurityIdentity & AccessOperations & Compliance

IAM Access Analyzer Not Enabled: Find Unintended External Access in AWS

Learn why IAM Access Analyzer should be enabled in every AWS region, how to fix it via CLI, console, and Terraform, and how to enforce it with policy-as-code.

TL;DR

This check flags AWS regions where IAM Access Analyzer is not enabled, leaving you blind to resources shared outside your account or organization. Create an account or organization-level analyzer in every active region to surface unintended external access.

IAM policies are easy to get wrong. A single overly broad Principal on an S3 bucket policy, a KMS key shared with the wrong account, or a Lambda function exposed to the public internet can sit unnoticed for months. IAM Access Analyzer exists to catch exactly this kind of mistake, and when it is not turned on, you lose one of the cheapest and most effective safety nets AWS provides.

This check is simple: it confirms whether IAM Access Analyzer is enabled in a given region. If it is not, you have no automated continuous monitoring for external access to your resources in that region.


What this check detects

The account_accessanalyzer check inspects each AWS region and verifies that at least one active IAM Access Analyzer exists. Access Analyzer is region-scoped, so an analyzer created in us-east-1 does nothing for resources in eu-west-1. The check fails for any region where no analyzer is found.

Note: IAM Access Analyzer uses automated reasoning (a form of mathematical proof) to evaluate resource policies. It analyzes the resource policy attached to things like S3 buckets, IAM roles, KMS keys, Lambda functions, and SQS queues, then reports any access that is granted to a principal outside your defined "zone of trust" (your account or your AWS Organization).

The findings it generates answer one question: which of my resources can be accessed by someone outside my trust boundary? That includes other AWS accounts, federated users, anonymous public access, and cross-organization access.


Why it matters

Most large-scale data exposure incidents start with a misconfigured resource policy, not a sophisticated exploit. An engineer debugging a cross-account integration adds "Principal": "*" to a bucket policy "just to test it," then forgets to revert. A third-party SaaS vendor asks you to grant their account access to a role, and the role ends up with more permissions than intended. These are routine, human mistakes.

Without Access Analyzer running, nothing tells you these mistakes happened. You are relying on someone noticing during a manual review, which rarely happens at scale.

Consider a few concrete scenarios that Access Analyzer surfaces immediately:

  • Public S3 buckets: A bucket policy granting access to "*" shows up as a finding with the principal flagged as anonymous.
  • Cross-account role trust: An IAM role that trusts an external account ID you do not recognize. This is a common foothold in supply-chain style attacks.
  • Shared KMS keys: An encryption key whose policy allows another account to decrypt data, which can quietly defeat your encryption controls.
  • Exposed secrets: A Secrets Manager secret or SQS queue accessible from outside your organization.

The business impact is straightforward. Unintended external access is the precondition for data exfiltration, lateral movement, and compliance violations. Frameworks like SOC 2, PCI DSS, and CIS AWS Foundations all expect you to monitor for this. The CIS AWS Foundations Benchmark explicitly recommends enabling Access Analyzer in every region.

Tip: Access Analyzer findings for external access are free. There is no per-finding or per-analyzer charge for the standard external access analyzer, so there is no cost reason to leave it disabled. (Unused access analysis is a separate, paid feature, covered later.)


How to fix it

You have two reasonable scopes for an analyzer:

  • Account zone of trust: Flags access from outside the current account. Use this if you do not run AWS Organizations.
  • Organization zone of trust: Flags access from outside your entire AWS Organization. Created from the management or a delegated administrator account, this is the better choice for multi-account setups.

Option 1: AWS CLI

Create an account-level analyzer in a single region:

aws accessanalyzer create-analyzer \
  --analyzer-name account-analyzer \
  --type ACCOUNT \
  --region us-east-1

For an organization-wide analyzer, run this from the management account or a delegated administrator:

aws accessanalyzer create-analyzer \
  --analyzer-name org-analyzer \
  --type ORGANIZATION \
  --region us-east-1

Because analyzers are region-scoped, you need to repeat this for every region you operate in. A quick loop covers the regions you care about:

for region in us-east-1 us-west-2 eu-west-1 eu-central-1; do
  aws accessanalyzer create-analyzer \
    --analyzer-name "account-analyzer-${region}" \
    --type ACCOUNT \
    --region "$region"
done

Option 2: AWS Console

  1. Open the IAM console and choose Access Analyzer from the left navigation.
  2. Select Analyzers, then Create analyzer.
  3. Confirm the region in the top-right matches the region you want to protect.
  4. Choose the zone of trust: Current account or Current organization.
  5. Name the analyzer and choose Create analyzer.
  6. Repeat for each active region.

Option 3: Terraform

resource "aws_accessanalyzer_analyzer" "account" {
  analyzer_name = "account-analyzer"
  type          = "ACCOUNT"
}

To cover multiple regions with Terraform, use provider aliases and one resource per region, or wrap the module in a for_each over a set of regional providers. Here is the organization variant:

resource "aws_accessanalyzer_analyzer" "org" {
  analyzer_name = "org-analyzer"
  type          = "ORGANIZATION"
}

Note: An organization analyzer must be created from the Organizations management account or from an account you have registered as a delegated administrator for Access Analyzer. Delegating to a dedicated security account is the cleaner pattern, since it keeps the management account out of day-to-day operations.

Once an analyzer is active, it scans existing resources within minutes and begins monitoring continuously. Review the findings under Access Analyzer > Findings, then either archive findings that represent intended access or fix the underlying policy for the ones that do not.


How to prevent it from happening again

Enabling an analyzer once is not enough. New regions get used, new accounts join the organization, and analyzers can be deleted. Bake the control into your account setup so it is never a manual step.

Deploy through your landing zone

If you use AWS Control Tower or a custom landing zone, add Access Analyzer to the account baseline so every new account gets an analyzer in your standard regions automatically. CloudFormation StackSets is the usual delivery mechanism:

{
  "Resources": {
    "AccountAnalyzer": {
      "Type": "AWS::AccessAnalyzer::Analyzer",
      "Properties": {
        "AnalyzerName": "account-analyzer",
        "Type": "ACCOUNT"
      }
    }
  }
}

Deploy this StackSet with auto-deployment enabled to all regions in your organization, and new accounts inherit it on creation.

Gate it in CI/CD with policy-as-code

If you provision accounts or regions through Terraform, add a check that fails the pipeline when an analyzer is missing. With Open Policy Agent and conftest against a Terraform plan:

conftest test tfplan.json --policy policy/access_analyzer.rego

A simple Rego rule asserting that an analyzer resource exists keeps anyone from shipping infrastructure to a new region without it.

Tip: Pair the deployment control with continuous monitoring. Lensix re-runs the account_accessanalyzer check across every region on a schedule, so if someone deletes an analyzer or spins up activity in a new region, you get a finding instead of a silent gap.


Best practices

  • Enable in every region, not just the ones you use today. Attackers often pick idle regions precisely because nobody is watching them. Coverage everywhere closes that blind spot.
  • Prefer an organization analyzer for multi-account environments. It treats cross-account access between your own accounts as trusted, cutting noise while still flagging genuinely external access.
  • Triage findings with archive rules. Create archive rules for known-good shared access (for example, a vendor account you intentionally trust) so your active findings list reflects only things that need attention.
  • Route findings to Security Hub or EventBridge. Access Analyzer integrates with both. Forwarding findings into your central alerting pipeline means a new public bucket pages someone instead of sitting in a console nobody checks.
  • Use policy validation before deployment. Access Analyzer can validate IAM policies against AWS best practices through the ValidatePolicy API. Run it in CI to catch overly permissive policies before they ever reach an account.

Warning: Access Analyzer also offers unused access analysis, which finds unused IAM roles, permissions, and access keys. This is a separate analyzer type and is billed per IAM role and user analyzed per month. It is genuinely useful for least-privilege work, but enable it deliberately rather than assuming it is free like the external access analyzer.

Enabling Access Analyzer is one of those rare security controls that costs nothing for the core feature, takes minutes to set up, and immediately answers a question every team should be able to answer: who outside my organization can touch my resources? Turn it on everywhere, wire the findings into your alerting, and enforce it through your account baseline so it never quietly disappears.