Connecting to AWS IAM (NHI)

Last updated: August 3, 2026


This integration will not sync any information. Any integration errors are not indicative of the integration status

What You're Setting Up

You're creating a read-only IAM role in your AWS account that Lumos assumes via AWS STS using an External-ID-gated trust policy. Lumos uses this role to surface non-human-identity risk — over-privileged roles, weak OIDC trust, wildcard-principal trust policies, externally-shared resources, publicly-invokable Lambda Function URLs, unused access keys, abandoned IAM users, GuardDuty compromise signals, and more.

What Lumos does NOT do:

  • No data-plane access — we never read secret values, S3 objects, DynamoDB rows, log-stream contents, or environment-variable values.

  • No writes — every action is read-only.

  • No CloudTrail event reads — we rely on GuardDuty's pre-analyzed signals.

  • No role assumption beyond this scoped role.

The full permission ask is 14 IAM actions. Every call Lumos makes lands in your CloudTrail so you can audit exactly what ran.


Prerequisites

Before you start, make sure you have:

  • AWS IAM admin permissions in the account you want to connect (or a role that can create IAM roles and policies).

  • The Service Role External ID shown on your Lumos integration page (used in Step 2). Do not generate your own — Lumos issues a per-tenant value.

  • For full finding coverage, enable these in each region you want scanned:

    • IAM Access Analyzer with both analyzer types configured: an External Access analyzer (Type ACCOUNT or ORGANIZATION) powers externally-shared-resource and public-resource findings; an Unused Access analyzer powers stale-access-key and abandoned-user findings. Both are needed for full Phase 1 coverage.

    • Amazon GuardDuty for active-compromise and lateral-movement detection.

  • If you're connecting multiple AWS accounts: repeat this setup per account, or deploy from your AWS Organization management or delegated-admin account so Lumos can distinguish "external to your org" trust relationships from "sibling account in your org."


Step 1 — Create the IAM policy

In the AWS console: IAM → Policies → Create policy → JSON. Paste the policy below and name it LumosNHIReadOnly-policy (any name works).

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowAccessToIAM",
      "Effect": "Allow",
      "Resource": "*",
      "Action": [
        "iam:GetAccountAuthorizationDetails",
        "iam:ListUsers",
        "iam:GetUser",
        "iam:ListUserPolicies",
        "iam:GetUserPolicy",
        "iam:ListAttachedUserPolicies",
        "iam:ListGroupsForUser",
        "iam:ListRoles",
        "iam:GetRole",
        "iam:ListRolePolicies",
        "iam:GetRolePolicy",
        "iam:ListAttachedRolePolicies",
        "iam:ListGroups",
        "iam:ListGroupPolicies",
        "iam:GetGroupPolicy",
        "iam:ListAttachedGroupPolicies",
        "iam:ListPolicies",
        "iam:GetPolicy",
        "iam:ListPolicyVersions",
        "iam:GetPolicyVersion",
        "iam:GetInstanceProfile",
        "iam:ListOpenIDConnectProviders",
        "iam:GetOpenIDConnectProvider",
        "iam:ListSAMLProviders",
        "iam:GetSAMLProvider",
        "access-analyzer:ListAnalyzers",
        "access-analyzer:ListFindings",
        "access-analyzer:GetFinding",
        "sts:GetCallerIdentity",
        "ec2:DescribeInstances",
        "ec2:DescribeSecurityGroups",
        "ecs:ListTaskDefinitions",
        "ecs:DescribeTaskDefinition",
        "eks:ListClusters",
        "eks:DescribeCluster",
        "eks:ListPodIdentityAssociations",
        "eks:DescribePodIdentityAssociation",
        "lambda:ListFunctions",
        "lambda:GetFunctionConfiguration",
        "lambda:ListFunctionUrlConfigs",
        "lambda:GetPolicy",
        "kms:ListKeys",
        "kms:DescribeKey",
        "kms:GetKeyPolicy",
        "bedrock:List*",
        "bedrock:Get*",
        "s3:List*",
        "s3:Get*",
        "guardduty:ListDetectors",
        "guardduty:ListFindings",
        "guardduty:GetFindings"
      ]
    },
    {
      "Sid": "AllowAccessToIdentityCenter",
      "Effect": "Allow",
      "Resource": "*",
      "Action": [
        "sso:ListInstances",
        "sso:DescribeInstance",
        "sso:ListPermissionSets",
        "sso:DescribePermissionSet",
        "sso:ListManagedPoliciesInPermissionSet",
        "sso:GetInlinePolicyForPermissionSet",
        "sso:ListCustomerManagedPolicyReferencesInPermissionSet",
        "sso:GetPermissionsBoundaryForPermissionSet",
        "sso:ListAccountAssignments",
        "sso:ListAccountAssignmentsForPrincipal",
        "sso:ListAccountsForProvisionedPermissionSet",
        "sso:ListApplications",
        "sso:DescribeApplication",
        "sso:ListApplicationAssignments",
        "sso:ListApplicationGrants",
        "sso:ListApplicationAccessScopes",
        "sso:ListApplicationAuthenticationMethods",
        "sso:GetApplicationAuthenticationMethod",
        "sso:GetApplicationGrant",
        "sso:ListTrustedTokenIssuers",
        "sso:DescribeTrustedTokenIssuer",
        "sso:DescribeInstanceAccessControlAttributeConfiguration",
        "identitystore:ListUsers",
        "identitystore:DescribeUser",
        "identitystore:ListGroups",
        "identitystore:DescribeGroup",
        "identitystore:ListGroupMemberships",
        "organizations:ListAccounts",
        "organizations:DescribeOrganization"
      ]
    },
    {
      "Sid": "AllowReadAccessToCloudTrail",
      "Effect": "Allow",
      "Resource": "*",
      "Action": [
        "cloudtrail:LookupEvents",
        "cloudtrail:Describe*",
        "cloudtrail:Get*",
        "cloudtrail:List*"
      ]
    }
  ]
}

A note on iam:GetAccountAuthorizationDetails: this is AWS's purpose-built read-only API for retrieving the IAM authorization graph — users, roles, groups, their inline + managed policy documents, trust policies, and RoleLastUsed. Using it in one paginated call (rather than ~20 per-entity reads) keeps your CloudTrail cleaner, makes scans deterministic, and doesn't expose anything extra


Step 2: Create the IAM role

  1. Go to IAM → Roles → Create role.

  2. For Trusted entity type, choose AWS account.

  3. Under An AWS account, select Another AWS account and enter the Lumos account ID:

349123981986
  1. Check Require external ID and enter the Service Role External ID shown in the Lumos connector setup form.

  2. Click Next.

  3. On the Add permissions screen, search for the policy you created in Step 2, select it, and click Next.

  4. Give the role a name (e.g. LumosNHIReadOnly) and click Create role.


Step 3 — Note the role ARN

After the role is created, copy its ARN (format: arn:aws:iam::<your-account-id>:role/LumosNHIReadOnly). You'll paste it into Lumos in the next step.

Step 4 — Update the trust policy

  1. Open the role you just created (click View role from the success banner, or find it under IAM → Roles).

  2. Go to the Trust relationships tab and click Edit trust policy.

  3. In the JSON document, set the AWS value inside the Principal block to the Lumos Customer Integrator Role ARN shown in the Lumos connector setup form.

  4. Click Save changes.


Step 5 — Connect in Lumos

  1. In the Lumos app, go to Integrations → Add Integration and search for "AWS NHI".

Fill in the connector settings in Lumos with the values you collected:

  • Region - AWS region code

  • IAM Identity Center ARN - (Optional) Instance ARN from IAM Identity Center Settings

  • Service Role ARN - ARN of the IAM role created in Step 3

  • SCIM Endpoint or Tenant ID - (Optional) SCIM endpoint URL or tenant ID


Scan behavior

  • Cadence: Follow the NHI security agent configuration. We don’t pull AWS IAM data on a regular basis by default unless the agent is configured to run on a schedule.

  • Session lifetime: each scan opens a short-lived STS session (5-10 min). Lumos never holds long-lived credentials.


Security FAQ

Does Lumos access data inside my AWS account (S3 objects, secret values, log contents)?

The full permission ask is approximately 75 read-only actions across IAM, Identity Center, Access Analyzer, GuardDuty, EC2, ECS, EKS, Lambda, KMS, Bedrock, and Organizations. Every call Lumos makes lands in your CloudTrail so you can audit exactly what ran.

Does Lumos read CloudTrail events?

No. Lumos uses GuardDuty's pre-analyzed compromise signals rather than raw CloudTrail event bodies. This keeps Lumos out of your audit-log pipeline.

Why is iam:GetAccountAuthorizationDetails in the policy?

It's AWS's dedicated read-only API for retrieving the IAM authorization graph — users, roles, groups, their inline + managed policy documents, trust policies, and RoleLastUsed. Using it in one call (rather than ~20 per-entity reads) keeps your CloudTrail cleaner and makes scans predictable. It's IAM-metadata-only; there is no data-plane exposure.

How are credentials handled?

Lumos's service account in AWS account 349123981986 assumes your role via sts:AssumeRole with the External ID condition.

Can I scope the role down further?

The 14-action policy is already the minimum shipping scope. Dropping any of the IAM or Access Analyzer actions drops specific findings; dropping GuardDuty drops active-compromise detection. A future optional Phase 2 policy will add EC2 / ECS / EKS Pod Identity / Lambda execution-role classification / intra-account KMS (13 additional actions, 6 additional findings) when large-account scan performance is optimized. Your Lumos account team can walk through the trade-offs.

Can I remove the role later?

Yes. Delete the role in IAM; Lumos's next scan will fail with AccessDenied and we'll surface a "connection lost" banner in the integration UI. No data exfiltration — Lumos cannot assume the role once it's deleted.


Questions? Contact your Lumos account team or support@lumos.com.