Skip to main content

Architecture Overview

Xpander self-hosted uses a three-tier IAM role architecture for connector authentication:

Why Three Tiers?

  1. Least privilege — Each connector only has access to its specific service. A Redshift connector can’t access EKS and vice versa.
  2. Auditability — CloudTrail shows exactly which connector role accessed which resource. No shared credentials.
  3. Independent lifecycle — Add or remove connectors without touching other roles. Revoke one connector’s access without affecting others.
  4. Role chaining — The AI Gateway assumes the appropriate connector role per request. This is standard AWS role chaining, fully supported by xpander.
If you’re using a single IAM role for all connectors (the setup from AWS Operator Setup), the instructions on this page show how to split that into per-connector roles for better isolation and auditability.

Step 1: Base Role

The base role is the only role attached to pods. It has no service permissions — it can only assume other roles.
Attach the assume permissions (update this list as you add connectors):
Associate with the xpander service account via Pod Identity:

Step 2: Connector Roles

Each connector role needs a trust policy with four statements:

Trust Policy Template

The SelfAssume and AllowFromBaseRole statements must not have an ExternalId condition. The AI Gateway’s internal AssumeRole calls do not pass an external ID. If you add an ExternalId condition to these statements, the connector will fail with AccessDenied.

Permission Policies Per Connector

Each connector role needs its own service permissions plus self-assume.

Self-Assume + Session Tagging (required for all connector roles)

The EKS connector also needs Kubernetes RBAC:

Step 3: Configure in xpander UI

In the connector settings, set the IAM Role ARN to the connector-specific role (not the base role):

Adding a New Connector

When adding a new AWS connector (e.g., S3, DynamoDB, Athena):
1

Create the connector role

Use the trust policy template above.
2

Attach service-specific permissions

Add the service permissions + the self-assume policy.
3

Update the base role

Add the new role ARN to the AssumeConnectorRoles policy on the base role.
4

Configure in xpander UI

Set the connector’s IAM Role ARN.
5

Restart the AI Gateway

No Pod Identity changes needed — the base role association stays the same.

Role Creation Order

IAM roles can’t reference themselves during creation. Follow this order:
  1. Create the role with only PodIdentity + CrossAccountWithExternalId trust statements
  2. Wait 10 seconds for IAM propagation
  3. Update the trust policy to add SelfAssume + AllowFromBaseRole statements

Troubleshooting

Cause: Missing sts:TagSession in either the trust policy or the permission policy.Fix: Ensure both:
  • Trust policy allows sts:TagSession from the caller
  • Permission policy includes sts:TagSession on the role’s own ARN
Cause: The SelfAssume trust statement has an ExternalId condition, or the self-assume permission policy is missing.Fix: The SelfAssume and AllowFromBaseRole statements must NOT have conditions. The AI Gateway does not pass an ExternalId during internal role operations.
Cause: Base role doesn’t have permission to assume the connector role, or the connector role’s trust policy doesn’t list the base role.Fix: Check both sides:
  • Base role permission policy lists the connector role ARN
  • Connector role trust policy has AllowFromBaseRole statement
Cause: In cloud mode, the xpander platform assumes the role directly with the ExternalId. In self-hosted mode, the AI Gateway chains through the base role without an ExternalId.Fix: Add the AllowFromBaseRole trust statement to the connector role.

Security Recommendations

  1. Scope resources — Use specific ARNs in permission policies, not "Resource": "*" where possible
  2. Separate roles per data source — Don’t combine Redshift + EKS permissions in one role
  3. Rotate ExternalId — The organization ID is used as ExternalId. If compromised, rotate it in the xpander platform
  4. Monitor with CloudTrail — Each connector role appears separately in CloudTrail, making it easy to audit which connector accessed which resource
  5. Tag roles — Tag all roles with Environment, Project, ManagedBy for governance
  6. Restrict base role — The base role should ONLY have sts:AssumeRole + sts:TagSession. Never attach service permissions directly to it