For the complete documentation index, see llms.txt. This page is also available as Markdown.

AWS Application Integration Setup

Getting Started

There are two supported ways to grant BalkanID access to your account. Pick whichever fits your environment.

Requirements

Option 1: Using an IAM Role

  • IAM Role ARN

  • AWS Region

  • External ID (optional, but highly recommended; BalkanID generates this value, see below)

Option 2: Using an IAM User

  • Access Key ID

  • Secret Access Key

  • AWS Region

  • A dedicated service account, rather than a personal or employee-named account, for creating this access key (strongly recommended, see below)

Getting the Configuration

Option 1: Using an IAM Role

We use an IAM User called balkan-service-user, which assumes the IAM Role you provide, to connect to your AWS account.

  1. Navigate to the AWS Web Console, Roles section.

  2. Click Create role.

  3. Set Trusted entity type to Custom trust policy and paste the policy below. Leave the

    External ID condition off for now. You will add it after BalkanID generates a value. See Protecting your role with an External ID.

    Note: the Account ID above (015482169847) is our shared BalkanID service-user account, used for every customer on this trust policy. After you generate an External ID in BalkanID, add an sts:ExternalId condition so your role stays isolated from other tenants that share the same BalkanID principal.

  4. In the Permissions policies section, create a customer-managed policy using the JSON in

    Least-privilege permissions policy below, and attach it to this role.

  5. In the next section, set the IAM Role Name and Description, then click Create role.

  6. Once created, set Maximum session duration to 12 hours.

  7. Copy the ARN from the role's ARN field (just above Maximum session duration).

Protecting your role with an External ID

An External ID is optional, but highly recommended. On our standard, shared environment, every customer's trust policy names the same balkan-service-user principal, so without an External ID the only thing distinguishing your role from any other customer's is the secrecy of your Role ARN. BalkanID mints a tenant-specific value and sends it on sts:AssumeRole. You cannot type or paste your own External ID.

  1. Finish creating the role and save the integration in BalkanID with the Role ARN and Region

    (see Configure AWS in your BalkanID tenant).

  2. On the integration form, next to External ID, click Generate. BalkanID stores a value

    of the form balkanid-<uuid>.

  3. Click the copy control on the field.

  4. In AWS, edit the role's Trust relationships policy and add the condition below, using the

    copied value. Then save the policy.

  5. Sync the integration. If the trust-policy value does not match exactly, sts:AssumeRole

    fails with AccessDenied.

To replace an existing External ID, click Rotate in BalkanID, copy the new value, and update sts:ExternalId in the trust policy before the next sync. Rotating invalidates the previous value. Leaving External ID empty means BalkanID will not send one (Role ARN only).

If your organization requires isolation stronger than Role ARN + External ID, contact support@balkan.id to discuss your options.

Option 2: Getting the Access Key and Secret Access Key

  1. Create a dedicated IAM user for this integration first (AWS Console, Users, Create user, e.g. balkanid-identitycenter-integration). Do not generate this access key under your own (or any other individual's) AWS Console user. A key tied to a named human user inherits that person's account lifecycle: if they leave, rotate their password, or lose console access, the integration can break unexpectedly or, worse, keep running on a credential nobody is actively tracking as a live secret. A dedicated service IAM user has a lifecycle you control independently of any individual's employment status.

  2. In the Permissions step, choose Attach policies directly, then Create policy to

    open the policy editor in a new tab. Paste the JSON from Least-privilege permissions policy below, name it (for example BalkanIDLeastPrivilegePolicy), and save it. Back in the user wizard, refresh the policy list and select it.

  3. On this user, go to Security credentials, scroll to Access Keys.

  4. Click Create Access Key, select Third-party service when prompted for a use case, and click Next.

  5. Provide a description and click Create Access Key. You'll be shown your credentials.

  6. Make a note of the Access Key and Secret Access Key. Your Region is the AWS Region your AWS Identity Center is configured in. Check the region selector next to your account name in the top-right of the console.

Do not generate an External ID on this path. External ID is an sts:AssumeRole trust-policy condition. Static access keys never call AssumeRole, and BalkanID rejects External ID together with access keys. If your organization can create cross-account IAM roles, prefer Option 1.

Least-privilege permissions policy

This is the exact list of AWS API calls this extractor makes. Attach it as a customer-managed policy to the role or user you created above. Replace <AWS_ACCOUNT_ID> with your account ID.

The policy is split into a Core statement (always required) and one statement per Selective Extraction entity, so you can remove the statements for entities you don't plan to enable. See Selective Extraction permissions for the full mapping, or check this integration's Data Sync Preferences screen in your BalkanID tenant: the Required API Scopes panel there lists the exact IAM actions needed for whatever entities you've selected, and updates live as you check or uncheck them.

Why some statements are Resource: "*". Account-wide or list-only actions (like iam:ListUsers and iam:SimulateCustomPolicy) don't support resource-level scoping. Everything else is scoped to user/*, role/*, group/*, or policy/* in your account, except BalkanIDAWSManagedPolicies, which scopes to arn:aws:iam::aws:policy/* since AWS-managed policies (e.g. AmazonS3ReadOnlyAccess) live under AWS's own account, not yours.

You can validate this policy against your account without attaching it to anything, using the IAM policy simulator:

Lifecycle Management (provisioning) permissions

BalkanID's Lifecycle Management feature creates, deletes, and modifies AWS IAM users, groups, roles, and policies directly from BalkanID, for example offboarding a user by deleting their IAM user. It requires the Direct Provisioning fulfillment option enabled under Optional Configuration (see Configure AWS in your BalkanID tenant), and the policy below attached in addition to the read-only Access Review policy above. Skip this section if you only use this integration for Access Review.

Attach a customer-managed policy with the exact write actions below, split into one statement per resource type so you can omit statements for actions you don't want to allow.

Why iam:GetServiceLinkedRoleDeletionStatus needs Resource: "*". Deleting a service-linked role is asynchronous: AWS returns a deletion task ID, and this action polls that task by ID, not by role ARN. AWS does not support resource-level permissions for it.

Service-linked roles live under a fixed path. AWS always creates them at role/aws-service-role/<service>/<role-name>, which is why their Create/Delete statement is scoped to that path instead of role/*.

Lifecycle Management action to IAM action mapping

Lifecycle Management action
IAM actions called

Create user (+ initial console password)

iam:CreateUser, iam:CreateLoginProfile

Reset user password

iam:UpdateLoginProfile

Delete user

iam:GetUser, iam:ListAttachedUserPolicies, iam:DetachUserPolicy, iam:ListUserPolicies, iam:DeleteUserPolicy, iam:ListGroupsForUser, iam:RemoveUserFromGroup, iam:DeleteLoginProfile, iam:ListAccessKeys, iam:DeleteAccessKey, iam:ListMFADevices, iam:DeactivateMFADevice, iam:DeleteVirtualMFADevice, iam:ListSigningCertificates, iam:DeleteSigningCertificate, iam:ListSSHPublicKeys, iam:DeleteSSHPublicKey, iam:ListServiceSpecificCredentials, iam:DeleteServiceSpecificCredential, iam:DeleteUser

Create group

iam:CreateGroup

Delete group

iam:ListAttachedGroupPolicies, iam:DetachGroupPolicy, iam:ListGroupPolicies, iam:DeleteGroupPolicy, iam:GetGroup, iam:RemoveUserFromGroup, iam:DeleteGroup

Add / remove user to or from a group

iam:AddUserToGroup / iam:RemoveUserFromGroup

Create role or AWS Service Role

iam:CreateRole, iam:ListAttachedRolePolicies (Service Role only, to record initial attachments)

Create AWS Service-Linked Role

iam:CreateServiceLinkedRole

Delete role or AWS Service Role

iam:ListAttachedRolePolicies, iam:DetachRolePolicy, iam:ListRolePolicies, iam:DeleteRolePolicy, iam:DeleteRole

Delete AWS Service-Linked Role

iam:DeleteServiceLinkedRole, iam:GetServiceLinkedRoleDeletionStatus

Create policy

iam:CreatePolicy

Delete policy

iam:DeletePolicy

Attach / detach a policy to a user, group, or role

iam:AttachUserPolicy / iam:DetachUserPolicy, iam:AttachGroupPolicy / iam:DetachGroupPolicy, iam:AttachRolePolicy / iam:DetachRolePolicy

Not supported by this integration: suspending or reactivating a user (AWS IAM has no concept of a suspended user; BalkanID falls back to deleting the user if you enable that option), updating an existing identity's attributes, and creating or deleting non-IAM resources.

Optional, early-access permissions

The features below are not enabled by default and are rolled out to tenants on request. If you want one of these, contact your BalkanID account team and they'll turn it on for your tenant. Attaching the IAM permissions ahead of time doesn't activate the feature by itself, but is required once it's enabled so extraction doesn't fail with AccessDenied.

Bedrock Classic agents and AgentCore harnesses

Early Access: Agents discovery must be enabled for your tenant. For what BalkanID surfaces after sync, see AWS: Agents.

To discover Bedrock Classic agents and AgentCore harnesses (Non-Human Identity / Agents inventory), add:

If this isn't enabled for your tenant or you don't attach these permissions, extraction still succeeds. Agent discovery simply skips (logged, not fatal) and every other entity type continues to sync normally.

Access keys as first-class credential entities

Part of BalkanID's Non-Human Identity (NHI) capability. In addition to the Access Keys statement already in the core policy above, this requires the NHI feature to be enabled for your tenant by your BalkanID account team. Ask them if you want access keys modeled and risk-scored as standalone credential entities rather than just a user attribute.

IAM last-accessed data (Access Advisor)

To let BalkanID show when a user, role, group, or policy last accessed an AWS service, add:

This is the AWS Access Advisor API family, the same feature that powers the "Last accessed" tab in the IAM console, and not CloudTrail. GetServiceLastAccessedDetails* reads back a previously submitted job by ID rather than by resource, which is why AWS requires Resource: "*" for those two actions specifically; GenerateServiceLastAccessedDetails and ListPoliciesGrantingServiceAccess support the scoped ARNs above. Ask your BalkanID account team to enable "last access time" for your tenant if you want this populated.

Deeper cross-account role-chain resolution

Used to compute the graph of roles that can be assumed from other roles in your account, so BalkanID can show effective, transitive access. It only simulates whether an sts:AssumeRole call would be allowed. It never actually calls AssumeRole, and no trust-policy changes are needed on the target roles. This ships enabled by default with unlimited chain depth; contact your BalkanID account team if you'd like the depth limited or this turned off entirely for your tenant.

If you don't attach this permission, extraction still succeeds; every user, group, and role logs an AccessDenied warning for this specific check (not fatal), and role-chain data simply stays empty. Every other entity type continues to sync normally.

Selective Extraction permissions

BalkanID's Selective Extraction toggles (in the tenant integration form) control which entity types are synced, and each toggle maps directly to a subset of the core policy above. Disable a toggle and the corresponding actions are simply never called, so it's safe to remove the matching policy statement.

Selective Extraction toggle
IAM actions required
Always on?

Users

iam:ListUsers, iam:GetLoginProfile, iam:GenerateCredentialReport, iam:GetCredentialReport, iam:ListAccountAliases

Yes, cannot be disabled

Groups

iam:ListGroups, iam:ListGroupsForUser, iam:GetGroup, iam:ListGroupPolicies, iam:GetGroupPolicy, iam:ListAttachedGroupPolicies, iam:GetPolicy, iam:GetPolicyVersion

No

Roles / AWS Service Linked Roles / AWS Service Roles

iam:ListRoles, iam:GetRole, iam:ListRolePolicies, iam:GetRolePolicy, iam:ListAttachedRolePolicies, iam:GetPolicy, iam:GetPolicyVersion

No

Policies

iam:ListPolicies, iam:GetPolicy, iam:GetPolicyVersion, iam:ListUserPolicies, iam:GetUserPolicy, iam:ListAttachedUserPolicies

No

Generic Resources

(none, derived from already-synced data, no additional API calls)

No

Insights

iam:SimulateCustomPolicy

No

MFA Devices

iam:ListMFADevices

No

Access Keys

iam:ListAccessKeys, iam:GetAccessKeyLastUsed

No, also requires the early-access NHI feature, see above

Some actions appear under more than one toggle (e.g. iam:GetPolicy under both Groups and Roles) because BalkanID resolves attached-policy details as part of both entity types.

Not required, despite being included in IAMReadOnlyAccess: iam:SimulatePrincipalPolicy (only used, scoped, for the optional role-chain feature above, not for Insights), and any credential-report-adjacent SSH-key/signing-certificate actions or IAM account-summary/password-policy reads that aren't in the tables above. None of these are called by this extractor.

Configure AWS in your BalkanID tenant

  1. Login to the BalkanID application and switch to the tenant you would like to add your integration to.

  2. Head to Integrations > Add Integration, select Amazon Web Services.

  3. Set up the Primary Application owner (mandatory) and the Description, if any. Set up Secondary Application Owner(s), if any.

  4. Configure Selective Extraction toggles (see the table above).

  5. In the Direct Integration section provide your Role ARN or Access Key + Secret Access Key, and Region obtained above. After you save a Role ARN integration, click Generate on External ID (highly recommended), copy the value, and add it to the role's trust policy as described in Protecting your role with an External ID

  6. Click on next to move onto Optional Configuration.

  7. Fill Optional configuration, if required. (Turn on direct provisioning if you plan to use the lifecycle managment features).

  8. Once you filled in the information, click Save. Your integration is now configured and you will see the status of the integration displayed alongside other integrations on the Integrations page. When data is available, the integration Status will read Connected and the integration Message will read Data available.

Last updated

Was this helpful?