> For the complete documentation index, see [llms.txt](https://docs.balkan.id/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.balkan.id/getting-started/setting-up-your-tenant/application-integrations/direct-application-integrations/aws-identity-center-integration-setup.md).

# AWS Identity Center Integration Setup

### Getting Started <a href="#h_01hkr1f9w1x301w5bd6d96k5qc" id="h_01hkr1f9w1x301w5bd6d96k5qc"></a>

Your AWS account must have **AWS Organizations** and **AWS IAM Identity Center** actually enabled before starting. This is an account/organization-level feature toggle, separate from any IAM permission. If Identity Center isn't enabled, extraction fails with "No instances found" regardless of the IAM policy attached.

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

#### Requirements <a href="#h_01hq2keprp9cmqqvw4mb7gkdha" id="h_01hq2keprp9cmqqvw4mb7gkdha"></a>

**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 <a href="#h_01hkr1hfm8mztsa1kvq5g8yzft" id="h_01hkr1hfm8mztsa1kvq5g8yzft"></a>

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**.

   <figure><img src="https://2975852473-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbVGYwk8aSk5yI1GDPEW9%2Fuploads%2FTGGRDEBuWxzYb5SIZKUT%2Fimage.png?alt=media&amp;token=7d8ca5dc-21d1-45a2-bd45-0fda6a276fb0" alt=""><figcaption></figcaption></figure>

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](#protecting-your-role-with-an-external-id "mention").<br>

   ```json
   {
       "Version": "2012-10-17",
       "Statement": [
           {
               "Sid": "AllowBalkanIDServiceUserAssumeRole",
               "Effect": "Allow",
               "Principal": {
                   "AWS": "arn:aws:iam::015482169847:user/balkan-service-user"
               },
               "Action": "sts:AssumeRole",
               "Condition": {
                   "StringEquals": {
                       "sts:ExternalId": "<paste-external-id-generated-by-balkanid>"
                   }
               }
           }
       ]
   }
   ```

   <div data-gb-custom-block data-tag="hint" data-style="info" class="hint hint-info"><p><strong>Note:</strong> the Account ID above (<code>015482169847</code>) 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 <code>sts:ExternalId</code> condition so your role stays isolated from other tenants that share the same BalkanID principal.</p></div>

   <figure><img src="https://2975852473-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbVGYwk8aSk5yI1GDPEW9%2Fuploads%2Fb4PMFXPl16BR10oWSEK7%2Fimage.png?alt=media&amp;token=ee448d53-2d34-4a75-bffb-ea4364cd3126" alt=""><figcaption></figcaption></figure>

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

   [#least-privilege-permissions-policy](#least-privilege-permissions-policy "mention") below, and attach it to this role.<br>

   <figure><img src="https://2975852473-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbVGYwk8aSk5yI1GDPEW9%2Fuploads%2FS4DuJsiSuwdVfReuhXov%2Fimage.png?alt=media&amp;token=6d874b6d-500f-42b4-b54c-7f5aabaa8729" alt=""><figcaption></figcaption></figure>

   <figure><img src="https://2975852473-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbVGYwk8aSk5yI1GDPEW9%2Fuploads%2FlZRwc4AEzy0FukfdQrxh%2Fimage.png?alt=media&amp;token=774b5a86-1b0f-4ff2-881b-b5758b57c302" alt=""><figcaption></figcaption></figure>

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**.<br>

   <figure><img src="https://2975852473-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbVGYwk8aSk5yI1GDPEW9%2Fuploads%2F7BExqufkkfePvObNFlhA%2Fimage.png?alt=media&amp;token=f846adfb-0958-44fd-a7fd-aa17d6752619" alt=""><figcaption></figcaption></figure>

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

8. Continue to [#h\_01hkr26j1kk0nypd601qv5t424](#h_01hkr26j1kk0nypd601qv5t424 "mention") 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.

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

   (see [#h\_01hkr26j1kk0nypd601qv5t424](#h_01hkr26j1kk0nypd601qv5t424 "mention")).

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

   of the form `balkanid-<uuid>`.<br>

   <figure><img src="https://2975852473-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbVGYwk8aSk5yI1GDPEW9%2Fuploads%2F0O9YqHnA7I152c0KdmvG%2Fimage.png?alt=media&amp;token=9325cc15-b1e0-4936-9602-e9edbad2ff14" alt=""><figcaption></figcaption></figure>

3. Click the copy control on the field.<br>

   <figure><img src="https://2975852473-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbVGYwk8aSk5yI1GDPEW9%2Fuploads%2F95oXczAZzGcA9rHef21r%2Fimage.png?alt=media&amp;token=8252ff69-210e-437e-b1be-bc3577ec971f" alt=""><figcaption></figcaption></figure>

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 <a href="#h_01hkr1hfm8mztsa1kvq5g8yzft" id="h_01hkr1hfm8mztsa1kvq5g8yzft"></a>

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](#least-privilege-permissions-policy "mention") 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**.<br>

   <figure><img src="https://2975852473-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbVGYwk8aSk5yI1GDPEW9%2Fuploads%2FQ8UH48lk1HZbAyzjme5j%2Fimage.png?alt=media&amp;token=5cdd6e64-cf56-4b99-8b16-98ddf272b247" alt=""><figcaption></figcaption></figure>
4. Click **Create Access Key**, select **Third-party service** when prompted for a use case, and click **Next**.<br>

   <figure><img src="https://2975852473-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbVGYwk8aSk5yI1GDPEW9%2Fuploads%2F4DexkqD9lmLAdDWzUD4Q%2Fimage.png?alt=media&amp;token=876c88bb-a649-4217-9628-6ec56ff08218" alt=""><figcaption></figcaption></figure>
5. Provide a description and click **Create Access Key**. You'll be shown your credentials.

   <figure><img src="https://2975852473-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbVGYwk8aSk5yI1GDPEW9%2Fuploads%2FSsVtftSN3mVH639TLTai%2Fimage.png?alt=media&amp;token=db0508ca-aad7-44bb-ac1d-2000d8a24408" alt=""><figcaption></figcaption></figure>
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.<br>

   <figure><img src="https://2975852473-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbVGYwk8aSk5yI1GDPEW9%2Fuploads%2FdZXkDFV62gwy4COk1ZHY%2Fimage.png?alt=media&amp;token=9d1b6628-f048-4b57-b28b-4aad9a3bd165" alt=""><figcaption></figcaption></figure>

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 integration makes. Attach it as a customer-managed policy to the role or user you created above.

The exact permissions you need depend on which entity types you turn on under Selective Extraction. In your BalkanID tenant, on this integration's **Data Sync Preferences** screen, the **Required API Scopes** panel lists the exact IAM actions needed for whatever you've selected there, and updates live as you check or uncheck entities. Use it to confirm which statements below you actually need.

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "BalkanIDCoreReadOnly",
      "Effect": "Allow",
      "Action": "sso:ListInstances",
      "Resource": "*"
    },
    {
      "Sid": "BalkanIDUsers",
      "Effect": "Allow",
      "Action": "identitystore:ListUsers",
      "Resource": "*"
    },
    {
      "Sid": "BalkanIDGroups",
      "Effect": "Allow",
      "Action": [
        "identitystore:ListGroups",
        "identitystore:ListGroupMemberships"
      ],
      "Resource": "*"
    },
    {
      "Sid": "BalkanIDPermissionSets",
      "Effect": "Allow",
      "Action": [
        "sso:ListPermissionSets",
        "sso:DescribePermissionSet",
        "sso:ListManagedPoliciesInPermissionSet",
        "sso:ListCustomerManagedPolicyReferencesInPermissionSet",
        "sso:ListAccountAssignments",
        "organizations:ListAccounts"
      ],
      "Resource": "*"
    },
    {
      "Sid": "BalkanIDApplications",
      "Effect": "Allow",
      "Action": [
        "sso:ListApplications",
        "sso:ListApplicationAssignments"
      ],
      "Resource": "*"
    },
    {
      "Sid": "BalkanIDAccounts",
      "Effect": "Allow",
      "Action": "organizations:ListAccounts",
      "Resource": "*"
    }
  ]
}
```

`organizations:ListAccounts` appears in both `BalkanIDPermissionSets` and `BalkanIDAccounts` on purpose, since each toggle needs it independently. Remove only the statement for a toggle you've disabled.

> **Why every statement is** `Resource: "*"`**.** The AWS SSO Admin and Identity Store APIs don't support resource-level scoping for these actions. Attach this policy to a role dedicated to this integration, rather than trying to restrict `Resource` further.

You can validate this policy against your account without attaching it to anything:

```bash
aws iam simulate-custom-policy \
  --policy-input-list file://balkanid-identitycenter-policy.json \
  --action-names sso:ListInstances identitystore:ListUsers sso:ListPermissionSets \
  --region us-east-1
```

`simulate-custom-policy` validates the policy document itself, not whether Identity Center is enabled in your account. See the note under Getting Started.

### Optional, early-access permissions

#### Last access time for applications and last login time for users

Not enabled by default. Rolled out to tenants on request. Contact your BalkanID account team if you want this; attaching the permission ahead of time doesn't activate the feature by itself, but is required once it's enabled so extraction doesn't fail with `AccessDenied`.

```json
{
  "Sid": "BalkanIDLastAccessCloudTrail",
  "Effect": "Allow",
  "Action": "cloudtrail:LookupEvents",
  "Resource": "*"
}
```

This is used for exactly two lookups, both filtered by CloudTrail's own `EventName` attribute:

* `Federate` events (`EventSource: sso.amazonaws.com`) → per-user, per-application **last access time** (also requires the Applications Selective Extraction toggle enabled).
* `UserAuthentication` events (`EventSource: signin.amazonaws.com`) → per-user **last login time** (also requires the Users Selective Extraction toggle enabled).

**This is the one place in this integration that can't be scoped further.** `cloudtrail:LookupEvents` has no resource-level permissions or conditions, so granting it gives read access to your account's full CloudTrail management-event history (which control-plane APIs were called and by whom, not log contents or resource data). Skip this permission if that's not acceptable; every other entity type still syncs normally.

### Selective Extraction permissions

| Selective Extraction toggle | IAM/API actions required                                                                                                                                                                                              | Notes                                                                                                                                       |
| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| *(always)*                  | `sso:ListInstances`                                                                                                                                                                                                   | Required to locate your Identity Center instance before any entity sync; not tied to a toggle                                               |
| Users                       | `identitystore:ListUsers`                                                                                                                                                                                             |                                                                                                                                             |
| Groups                      | `identitystore:ListGroups`, `identitystore:ListGroupMemberships`                                                                                                                                                      |                                                                                                                                             |
| Permission Sets             | `sso:ListPermissionSets`, `sso:DescribePermissionSet`, `sso:ListManagedPoliciesInPermissionSet`, `sso:ListCustomerManagedPolicyReferencesInPermissionSet`, `sso:ListAccountAssignments`, `organizations:ListAccounts` | `organizations:ListAccounts` is required here too (account assignments are resolved per account), even if the Accounts toggle itself is off |
| Applications                | `sso:ListApplications`, `sso:ListApplicationAssignments`                                                                                                                                                              |                                                                                                                                             |
| Accounts                    | `organizations:ListAccounts`                                                                                                                                                                                          |                                                                                                                                             |

Disable a toggle and the corresponding actions are simply never called, so it's safe to remove the matching policy statement.

### Configuring AWS Identity Center on BalkanID Tenant <a href="#h_01hkr26j1kk0nypd601qv5t424" id="h_01hkr26j1kk0nypd601qv5t424"></a>

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 **AWS Identity Center.**<br>

   <figure><img src="https://2975852473-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbVGYwk8aSk5yI1GDPEW9%2Fuploads%2FXRvzAfUdpqlc7iQZT5Na%2Fimage.png?alt=media&amp;token=43dd9897-4221-45f6-b341-f15fd50fa14a" alt=""><figcaption></figcaption></figure>

   <figure><img src="https://2975852473-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbVGYwk8aSk5yI1GDPEW9%2Fuploads%2FR3uhl4Uoi6Pnkzk6yvIN%2Fimage.png?alt=media&amp;token=7090ce17-82e9-4aa8-8f74-6adaa43b521e" alt=""><figcaption></figcaption></figure>

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).<br>

   <figure><img src="https://2975852473-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbVGYwk8aSk5yI1GDPEW9%2Fuploads%2FeUpIe6eCo7RBZgtV2Ajg%2Fimage.png?alt=media&amp;token=0d4a0d19-c8c8-46a4-b9ed-ccb6e6498b1b" alt=""><figcaption></figcaption></figure>

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](#protecting-your-role-with-an-external-id "mention")<br>

   <figure><img src="https://2975852473-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbVGYwk8aSk5yI1GDPEW9%2Fuploads%2FNZhbyRe1NGZgtQOpJQVW%2Fimage.png?alt=media&amp;token=60c60efc-1131-4492-af12-eecdeed5b4ef" alt=""><figcaption></figcaption></figure>

6. Click on next to move onto *Optional Configuration.*

7. Fill **Optional configuration,** if required.<br>

   <figure><img src="https://2975852473-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbVGYwk8aSk5yI1GDPEW9%2Fuploads%2FWwMwzBtDCwYSplMbZBtP%2Fimage.png?alt=media&amp;token=0d22f002-4d7b-4d31-84c0-31b50ca63edd" alt="" width="563"><figcaption></figcaption></figure>

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**.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.balkan.id/getting-started/setting-up-your-tenant/application-integrations/direct-application-integrations/aws-identity-center-integration-setup.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
