After setting up IDC authentication for your OpenSearch UI application, you need to assign users and groups so they can log in. This guide covers how to manage user and group assignments programmatically using the AWS CLI and SDKs.
IDC User & Group Management
How IDC application assignment works
When you create an OpenSearch UI application with IDC enabled, it registers an IAM Identity Center application under the hood. Users must be assigned to this IDC application before they can log in. There are two levels of access:
- Application assignment — controls who can log in to the OpenSearch UI (managed via
sso-adminAPIs) - Application admin — controls who can edit/delete the app and manage workspaces (managed via
opensearch update-application)
Prerequisites
You need three identifiers before managing users:
| Identifier | How to get it |
|---|---|
| IDC Application ARN | From aws opensearch get-application |
| Identity Store ID | From aws sso-admin list-instances |
| User/Group ID | From aws identitystore list-users or list-groups |
Get the IDC Application ARN
aws opensearch get-application \
--id <APP_ID> \
--region <REGION> \
--query 'iamIdentityCenterOptions.iamIdentityCenterApplicationArn' \
--output textGet the Identity Store ID
aws sso-admin list-instances \
--region <REGION> \
--query 'Instances[0].IdentityStoreId' \
--output textManaging users
Find a user by email
aws identitystore list-users \
--identity-store-id <IDENTITY_STORE_ID> \
--filters '[{"AttributePath":"UserName","AttributeValue":"user@example.com"}]' \
--region <REGION> \
--query 'Users[0].UserId' \
--output textAdd a user to the application
aws sso-admin create-application-assignment \
--application-arn <IDC_APP_ARN> \
--principal-id <USER_ID> \
--principal-type USER \
--region <REGION>Remove a user from the application
aws sso-admin delete-application-assignment \
--application-arn <IDC_APP_ARN> \
--principal-id <USER_ID> \
--principal-type USER \
--region <REGION>List all assigned users
aws sso-admin list-application-assignments \
--application-arn <IDC_APP_ARN> \
--region <REGION>Managing groups
Find a group by name
aws identitystore list-groups \
--identity-store-id <IDENTITY_STORE_ID> \
--filters '[{"AttributePath":"DisplayName","AttributeValue":"MyGroup"}]' \
--region <REGION> \
--query 'Groups[0].GroupId' \
--output textAdd a group to the application
aws sso-admin create-application-assignment \
--application-arn <IDC_APP_ARN> \
--principal-id <GROUP_ID> \
--principal-type GROUP \
--region <REGION>Remove a group from the application
aws sso-admin delete-application-assignment \
--application-arn <IDC_APP_ARN> \
--principal-id <GROUP_ID> \
--principal-type GROUP \
--region <REGION>Managing application admins
Application admins can edit/delete the OpenSearch UI application and manage workspaces. This is separate from the IDC application assignment above.
Add an IDC user as admin
aws opensearch update-application \
--id <APP_ID> \
--app-configs '{
"key": "opensearchDashboards.dashboardAdmin.users",
"value": "[\"<IDC_USER_ID>\"]"
}' \
--region <REGION>Add an IDC group as admin
aws opensearch update-application \
--id <APP_ID> \
--app-configs '{
"key": "opensearchDashboards.dashboardAdmin.groups",
"value": "[\"<IDC_GROUP_ID>\"]"
}' \
--region <REGION>Python SDK example
Assign a single user by email
Look up a user by their email address and assign them to the OpenSearch UI application.
import boto3
region = "us-east-1"
app_id = "your-app-id"
opensearch = boto3.client("opensearch", region_name=region)
sso_admin = boto3.client("sso-admin", region_name=region)
identity_store = boto3.client("identitystore", region_name=region)
# Step 1: Get IDC application ARN
app = opensearch.get_application(id=app_id)
idc_app_arn = app["iamIdentityCenterOptions"]["iamIdentityCenterApplicationArn"]
# Step 2: Get identity store ID
instances = sso_admin.list_instances()
identity_store_id = instances["Instances"][0]["IdentityStoreId"]
# Step 3: Find user by email
users = identity_store.list_users(
IdentityStoreId=identity_store_id,
Filters=[{"AttributePath": "UserName", "AttributeValue": "user@example.com"}],
)
user_id = users["Users"][0]["UserId"]
# Step 4: Assign user to the application
sso_admin.create_application_assignment(
ApplicationArn=idc_app_arn,
PrincipalId=user_id,
PrincipalType="USER",
)
print(f"Assigned {user_id} to {idc_app_arn}")Assign a group by name
Look up a group by its display name and assign the entire group. All members of the group get access automatically.
import boto3
region = "us-east-1"
app_id = "your-app-id"
group_name = "Analytics Team"
opensearch = boto3.client("opensearch", region_name=region)
sso_admin = boto3.client("sso-admin", region_name=region)
identity_store = boto3.client("identitystore", region_name=region)
# Get IDC application ARN
app = opensearch.get_application(id=app_id)
idc_app_arn = app["iamIdentityCenterOptions"]["iamIdentityCenterApplicationArn"]
# Get identity store ID
instances = sso_admin.list_instances()
identity_store_id = instances["Instances"][0]["IdentityStoreId"]
# Find group by name
groups = identity_store.list_groups(
IdentityStoreId=identity_store_id,
Filters=[{"AttributePath": "DisplayName", "AttributeValue": group_name}],
)
group_id = groups["Groups"][0]["GroupId"]
# Assign group to the application
sso_admin.create_application_assignment(
ApplicationArn=idc_app_arn,
PrincipalId=group_id,
PrincipalType="GROUP",
)
print(f"Assigned group '{group_name}' ({group_id}) to {idc_app_arn}")Bulk assign multiple users from a list
Assign a list of users by email in a single script. Skips users that are already assigned or not found.
import boto3
from botocore.exceptions import ClientError
region = "us-east-1"
app_id = "your-app-id"
emails = [
"alice@example.com",
"bob@example.com",
"carol@example.com",
]
opensearch = boto3.client("opensearch", region_name=region)
sso_admin = boto3.client("sso-admin", region_name=region)
identity_store = boto3.client("identitystore", region_name=region)
app = opensearch.get_application(id=app_id)
idc_app_arn = app["iamIdentityCenterOptions"]["iamIdentityCenterApplicationArn"]
instances = sso_admin.list_instances()
identity_store_id = instances["Instances"][0]["IdentityStoreId"]
for email in emails:
# Find user
users = identity_store.list_users(
IdentityStoreId=identity_store_id,
Filters=[{"AttributePath": "UserName", "AttributeValue": email}],
)
if not users["Users"]:
print(f"SKIP {email} — not found in identity store")
continue
user_id = users["Users"][0]["UserId"]
try:
sso_admin.create_application_assignment(
ApplicationArn=idc_app_arn,
PrincipalId=user_id,
PrincipalType="USER",
)
print(f"OK {email} ({user_id})")
except ClientError as e:
if e.response["Error"]["Code"] == "ConflictException":
print(f"SKIP {email} — already assigned")
else:
print(f"FAIL {email} — {e}")Bulk assign multiple groups by name
Search for groups by name and assign them all. Useful for onboarding an organization with multiple teams.
import boto3
from botocore.exceptions import ClientError
region = "us-east-1"
app_id = "your-app-id"
group_names = [
"Analytics Team",
"Security Team",
"Platform Engineers",
]
opensearch = boto3.client("opensearch", region_name=region)
sso_admin = boto3.client("sso-admin", region_name=region)
identity_store = boto3.client("identitystore", region_name=region)
app = opensearch.get_application(id=app_id)
idc_app_arn = app["iamIdentityCenterOptions"]["iamIdentityCenterApplicationArn"]
instances = sso_admin.list_instances()
identity_store_id = instances["Instances"][0]["IdentityStoreId"]
for name in group_names:
groups = identity_store.list_groups(
IdentityStoreId=identity_store_id,
Filters=[{"AttributePath": "DisplayName", "AttributeValue": name}],
)
if not groups["Groups"]:
print(f"SKIP '{name}' — not found in identity store")
continue
group_id = groups["Groups"][0]["GroupId"]
try:
sso_admin.create_application_assignment(
ApplicationArn=idc_app_arn,
PrincipalId=group_id,
PrincipalType="GROUP",
)
print(f"OK '{name}' ({group_id})")
except ClientError as e:
if e.response["Error"]["Code"] == "ConflictException":
print(f"SKIP '{name}' — already assigned")
else:
print(f"FAIL '{name}' — {e}")List all current assignments
See who currently has access to your application — useful before making changes.
import boto3
region = "us-east-1"
app_id = "your-app-id"
opensearch = boto3.client("opensearch", region_name=region)
sso_admin = boto3.client("sso-admin", region_name=region)
identity_store = boto3.client("identitystore", region_name=region)
app = opensearch.get_application(id=app_id)
idc_app_arn = app["iamIdentityCenterOptions"]["iamIdentityCenterApplicationArn"]
instances = sso_admin.list_instances()
identity_store_id = instances["Instances"][0]["IdentityStoreId"]
paginator = sso_admin.get_paginator("list_application_assignments")
for page in paginator.paginate(ApplicationArn=idc_app_arn):
for a in page["ApplicationAssignments"]:
principal_type = a["PrincipalType"]
principal_id = a["PrincipalId"]
# Resolve name
if principal_type == "USER":
user = identity_store.describe_user(
IdentityStoreId=identity_store_id, UserId=principal_id
)
print(f"USER {user['UserName']} ({principal_id})")
else:
group = identity_store.describe_group(
IdentityStoreId=identity_store_id, GroupId=principal_id
)
print(f"GROUP {group['DisplayName']} ({principal_id})")Remove a user by email
import boto3
region = "us-east-1"
app_id = "your-app-id"
email = "alice@example.com"
opensearch = boto3.client("opensearch", region_name=region)
sso_admin = boto3.client("sso-admin", region_name=region)
identity_store = boto3.client("identitystore", region_name=region)
app = opensearch.get_application(id=app_id)
idc_app_arn = app["iamIdentityCenterOptions"]["iamIdentityCenterApplicationArn"]
instances = sso_admin.list_instances()
identity_store_id = instances["Instances"][0]["IdentityStoreId"]
users = identity_store.list_users(
IdentityStoreId=identity_store_id,
Filters=[{"AttributePath": "UserName", "AttributeValue": email}],
)
user_id = users["Users"][0]["UserId"]
sso_admin.delete_application_assignment(
ApplicationArn=idc_app_arn,
PrincipalId=user_id,
PrincipalType="USER",
)
print(f"Removed {email} ({user_id})")Remove a group by name
import boto3
region = "us-east-1"
app_id = "your-app-id"
group_name = "Analytics Team"
opensearch = boto3.client("opensearch", region_name=region)
sso_admin = boto3.client("sso-admin", region_name=region)
identity_store = boto3.client("identitystore", region_name=region)
app = opensearch.get_application(id=app_id)
idc_app_arn = app["iamIdentityCenterOptions"]["iamIdentityCenterApplicationArn"]
instances = sso_admin.list_instances()
identity_store_id = instances["Instances"][0]["IdentityStoreId"]
groups = identity_store.list_groups(
IdentityStoreId=identity_store_id,
Filters=[{"AttributePath": "DisplayName", "AttributeValue": group_name}],
)
group_id = groups["Groups"][0]["GroupId"]
sso_admin.delete_application_assignment(
ApplicationArn=idc_app_arn,
PrincipalId=group_id,
PrincipalType="GROUP",
)
print(f"Removed group '{group_name}' ({group_id})")Remove all assignments
Revoke access for all users and groups. Useful when decommissioning or resetting an application.
import boto3
region = "us-east-1"
app_id = "your-app-id"
opensearch = boto3.client("opensearch", region_name=region)
sso_admin = boto3.client("sso-admin", region_name=region)
app = opensearch.get_application(id=app_id)
idc_app_arn = app["iamIdentityCenterOptions"]["iamIdentityCenterApplicationArn"]
paginator = sso_admin.get_paginator("list_application_assignments")
for page in paginator.paginate(ApplicationArn=idc_app_arn):
for a in page["ApplicationAssignments"]:
sso_admin.delete_application_assignment(
ApplicationArn=idc_app_arn,
PrincipalId=a["PrincipalId"],
PrincipalType=a["PrincipalType"],
)
print(f"Removed {a['PrincipalType']} {a['PrincipalId']}")
print("All assignments removed")Sync from a CSV file
Import users and groups from a CSV file. The CSV should have columns type (USER or GROUP) and name (email or group name).
type,name
USER,alice@example.com
USER,bob@example.com
GROUP,Analytics Team
GROUP,Security Teamimport boto3, csv
from botocore.exceptions import ClientError
region = "us-east-1"
app_id = "your-app-id"
csv_file = "assignments.csv"
opensearch = boto3.client("opensearch", region_name=region)
sso_admin = boto3.client("sso-admin", region_name=region)
identity_store = boto3.client("identitystore", region_name=region)
app = opensearch.get_application(id=app_id)
idc_app_arn = app["iamIdentityCenterOptions"]["iamIdentityCenterApplicationArn"]
instances = sso_admin.list_instances()
identity_store_id = instances["Instances"][0]["IdentityStoreId"]
with open(csv_file) as f:
for row in csv.DictReader(f):
principal_type = row["type"].strip().upper()
name = row["name"].strip()
# Resolve principal ID
if principal_type == "USER":
result = identity_store.list_users(
IdentityStoreId=identity_store_id,
Filters=[{"AttributePath": "UserName", "AttributeValue": name}],
)
if not result["Users"]:
print(f"SKIP USER '{name}' — not found")
continue
principal_id = result["Users"][0]["UserId"]
else:
result = identity_store.list_groups(
IdentityStoreId=identity_store_id,
Filters=[{"AttributePath": "DisplayName", "AttributeValue": name}],
)
if not result["Groups"]:
print(f"SKIP GROUP '{name}' — not found")
continue
principal_id = result["Groups"][0]["GroupId"]
try:
sso_admin.create_application_assignment(
ApplicationArn=idc_app_arn,
PrincipalId=principal_id,
PrincipalType=principal_type,
)
print(f"OK {principal_type} '{name}'")
except ClientError as e:
if e.response["Error"]["Code"] == "ConflictException":
print(f"SKIP {principal_type} '{name}' — already assigned")
else:
print(f"FAIL {principal_type} '{name}' — {e}")Create IDC users and groups programmatically
If the user doesn't exist in your IDC identity store yet, you can create them:
Create a user
aws identitystore create-user \
--identity-store-id <IDENTITY_STORE_ID> \
--user-name "newuser@example.com" \
--name '{"GivenName":"Jane","FamilyName":"Doe"}' \
--display-name "Jane Doe" \
--emails '[{"Value":"newuser@example.com","Type":"Work","Primary":true}]' \
--region <REGION>Create a group
aws identitystore create-group \
--identity-store-id <IDENTITY_STORE_ID> \
--display-name "Analytics Team" \
--region <REGION>Add a user to a group
aws identitystore create-group-membership \
--identity-store-id <IDENTITY_STORE_ID> \
--group-id <GROUP_ID> \
--member-id '{"UserId":"<USER_ID>"}' \
--region <REGION>Troubleshooting
| Issue | Cause | Fix |
|---|---|---|
| User can't log in after assignment | IDC assignment propagation delay | Wait 1–2 minutes and retry |
AccessDeniedException on create-application-assignment | Missing sso:CreateApplicationAssignment permission | Add the IDC permissions to your IAM policy |
User not found in list-users | User not created in IDC identity store | Create the user first, or check you're querying the correct identity store |
ConflictException on assignment | User already assigned | Use list-application-assignments to verify |