Initializing Enclave...

Fixing AccessDenied for organizations:DescribeAccount When Using AWS Delegated Admin

Threat/Impact Level: HIGH | Exploitability/Downtime Risk: HIGH | Time to Fix: 15 mins


TL;DR

  • What broke: Your delegated admin account is calling organizations:DescribeAccount but the management account's IAM policies and/or SCPs never explicitly authorized that API for the delegated principal — AWS Organizations does not auto-inherit permissions just because an account is registered as a delegated admin.
  • How to fix it: Attach an explicit organizations:DescribeAccount allow either via a cross-account IAM role in the management account or a Resource Control Policy (RCP)/SCP exemption scoped to the delegated admin account's principal ARN.
  • Fast path: Use our Client-Side Sandbox above to auto-refactor your failing policy — paste your IAM JSON or SCP and get a corrected diff without sending your ARNs to a third-party server.

The Incident (What does the error mean?)

You're running automation from a delegated admin account — Security Hub, GuardDuty, or a custom Lambda — and it hard-stops with:

An error occurred (AccessDenied) when calling the DescribeAccount operation:
  User: arn:aws:sts::111122223333:assumed-role/DelegatedAdminRole/session
  is not authorized to perform: organizations:DescribeAccount
  on resource: arn:aws:organizations::*:account/o-exampleorgid/*
  with an explicit deny in a service control policy

Immediate consequence: Any cross-account inventory, compliance check, or account metadata lookup in your Organizations hierarchy fails silently or throws a hard exception. Pipelines that depend on account tags, account status, or OU membership break entirely. If this is in a Security Hub aggregator or a CSPM tool, you are now flying blind across your entire org.


The Attack Vector / Blast Radius

This isn't just an annoyance — it's a visibility gap that directly degrades your security posture.

Why it's dangerous:

  1. Blind spot creation: organizations:DescribeAccount is the primitive that feeds account status (ACTIVE/SUSPENDED), account tags, and parent OU data into every downstream compliance and detection tool. Block it and your CSPM shows stale or missing account records.

  2. SCP explicit deny cascade: The error message says explicit deny in a service control policy. This means somewhere in your OU hierarchy an SCP is running "Effect": "Deny" on organizations:* or a wildcard that catches DescribeAccount. An attacker who has compromised a lower-privileged account in the same OU now knows your SCP is overly broad — a recon signal.

  3. Delegated admin privilege confusion: Developers frequently assume that aws organizations register-delegated-administrator grants API permissions. It does not. It only allows the service (e.g., guardduty.amazonaws.com) to call Organizations APIs on behalf of the service — not your IAM roles inside that account. Your custom automation roles still need explicit IAM grants.

  4. Blast radius if misconfigured the other way: If you "fix" this by attaching organizations:* to the delegated admin role, you've handed that account full Organizations write access — account creation, policy attachment, OU restructuring. A compromised CI/CD pipeline in that account can now restructure your entire org.


How to Fix It (The Solution)

Root Cause Checklist (run in order)

  1. Check for explicit deny in SCPs — this overrides any IAM allow.
  2. Check the IAM role in the delegated admin account — does it have organizations:DescribeAccount?
  3. Check the trust policy — is the role assuming into the management account or calling directly?

Basic Fix — Add the missing permission to the delegated admin IAM role

{
  "Version": "2012-10-17",
  "Statement": [
    {
-     "Sid": "OrgReadOnly",
-     "Effect": "Allow",
-     "Action": [
-       "organizations:ListAccounts"
-     ],
+     "Sid": "OrgReadOnly",
+     "Effect": "Allow",
+     "Action": [
+       "organizations:ListAccounts",
+       "organizations:DescribeAccount",
+       "organizations:ListParents",
+       "organizations:DescribeOrganizationalUnit"
+     ],
      "Resource": "*"
    }
  ]
}

⚠️ organizations:DescribeAccount must be called against the management account's Organizations endpoint. If your delegated admin role lives in account 111122223333, it needs to assume a role in the management account 000000000000 that has this permission, OR the management account must have a resource-based delegation. Direct cross-account Organizations API calls do not work without a role assumption.


Enterprise Best Practice — Scoped cross-account assume-role with condition keys

Step 1: SCP — Remove the overly broad deny, replace with scoped deny

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyOrgWriteActions",
      "Effect": "Deny",
-     "Action": "organizations:*",
+     "Action": [
+       "organizations:CreateAccount",
+       "organizations:DeleteOrganization",
+       "organizations:MoveAccount",
+       "organizations:AttachPolicy",
+       "organizations:DetachPolicy",
+       "organizations:CreatePolicy",
+       "organizations:DeletePolicy"
+     ],
      "Resource": "*",
      "Condition": {
-       "": {}
+       "StringNotEquals": {
+         "aws:PrincipalArn": "arn:aws:iam::000000000000:role/OrgManagementBreakGlassRole"
+       }
      }
    }
  ]
}

Step 2: Management account — IAM role assumable by delegated admin account

+{
+  "Version": "2012-10-17",
+  "Statement": [
+    {
+      "Sid": "AllowDelegatedAdminOrgRead",
+      "Effect": "Allow",
+      "Action": [
+        "organizations:DescribeAccount",
+        "organizations:ListAccounts",
+        "organizations:ListParents",
+        "organizations:DescribeOrganizationalUnit",
+        "organizations:ListTagsForResource"
+      ],
+      "Resource": "*"
+    }
+  ]
+}

Step 3: Trust policy on the management account role

+{
+  "Version": "2012-10-17",
+  "Statement": [
+    {
+      "Effect": "Allow",
+      "Principal": {
+        "AWS": "arn:aws:iam::111122223333:role/DelegatedAdminRole"
+      },
+      "Action": "sts:AssumeRole",
+      "Condition": {
+        "StringEquals": {
+          "sts:ExternalId": "delegated-admin-org-read-2024"
+        },
+        "Bool": {
+          "aws:MultiFactorAuthPresent": "false"
+        }
+      }
+    }
+  ]
+}

💡 Tired of pasting proprietary configs into ChatGPT? Generic AI tools log your company's ARNs, DB strings, and private keys. StackEngine is a zero-backend, pure Client-Side WASM utility. Drop your failing config into the sandbox above. We redact your secrets locally in the browser and auto-generate the refactored code using your own API key.


Prevention in CI/CD

1. Checkov — Catch overly broad SCP denies pre-merge

Add to your .checkov.yaml:

check:
  - CKV_AWS_110  # Ensure IAM policies do not allow wildcard actions
  - CKV_AWS_111  # Ensure IAM policies do not allow write access without constraints
skip_check:
  - CKV2_AWS_14  # adjust based on your org posture

Run in pipeline:

checkov -d ./terraform/iam --framework terraform --check CKV_AWS_110,CKV_AWS_111 --hard-fail-on HIGH

2. OPA/Conftest — Block organizations:* wildcards in SCPs

package aws.organizations.scp

deny[msg] {
  stmt := input.Statement[_]
  stmt.Effect == "Deny"
  stmt.Action == "organizations:*"
  msg := sprintf(
    "SCP statement '%v' uses organizations:* wildcard deny. Enumerate specific write actions instead.",
    [stmt.Sid]
  )
}

3. AWS Config Rule — Continuous compliance

Deploy iam-policy-no-statements-with-admin-access and a custom Config rule that checks delegated admin accounts have organizations:DescribeAccount explicitly listed — not inherited via wildcard — to avoid this class of permission gap silently reappearing after policy rotations.

4. CloudTrail Alert — Catch it before it breaks prod

# EventBridge rule pattern — fires on AccessDenied for Organizations APIs from delegated admin accounts
{
  "source": ["aws.organizations"],
  "detail-type": ["AWS API Call via CloudTrail"],
  "detail": {
    "errorCode": ["AccessDenied"],
    "eventName": ["DescribeAccount", "ListAccounts", "ListParents"],
    "userIdentity": {
      "type": ["AssumedRole"]
    }
  }
}

Route this to an SNS topic wired to your on-call rotation. AccessDenied on read-only Organizations APIs from automation roles is a P2 incident, not a ticket.

Related Diagnostics

"Part of the Security Utility Matrix."

View all 140 Security Tools →