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.
Navigate to the AWS Web Console, Roles section.
Click Create role.

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.

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.


In the next section, set the IAM Role Name and Description, then click Create role.
Once created, set Maximum session duration to 12 hours.

Copy the ARN from the role's ARN field (just above Maximum session duration).
Continue to Configure AWS in your BalkanID tenant below.
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.
Finish creating the role and save the integration in BalkanID with the Role ARN and Region
On the integration form, next to External ID, click Generate. BalkanID stores a value
of the form
balkanid-<uuid>.
Click the copy control on the field.

In AWS, edit the role's Trust relationships policy and add the condition below, using the
copied value. Then save the policy.
Sync the integration. If the trust-policy value does not match exactly,
sts:AssumeRolefails 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
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.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.On this user, go to Security credentials, scroll to Access Keys.

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

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

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 (likeiam:ListUsersandiam:SimulateCustomPolicy) don't support resource-level scoping. Everything else is scoped touser/*,role/*,group/*, orpolicy/*in your account, exceptBalkanIDAWSManagedPolicies, which scopes toarn: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:GetServiceLinkedRoleDeletionStatusneedsResource: "*". 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 ofrole/*.
Lifecycle Management action to IAM action mapping
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
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.
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
Login to the BalkanID application and switch to the tenant you would like to add your integration to.
Head to Integrations > Add Integration, select Amazon Web Services.


Set up the Primary Application owner (mandatory) and the Description, if any. Set up Secondary Application Owner(s), if any.
Configure Selective Extraction toggles (see the table above).

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

Click on next to move onto Optional Configuration.
Fill Optional configuration, if required. (Turn on direct provisioning if you plan to use the lifecycle managment features).

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?

