trust
A trust lets one named identity, usually from another tenant, temporarily assume a role in this tenant.
A trust lets one named identity, usually from another tenant, temporarily assume a role in this tenant. Identities belong to one tenant and parent membership grants nothing in child tenants, so a support engineer or an automation that must act inside a customer's tenant needs a controlled way in. A trust gives exactly that person short-lived, audited access to one role, instead of a second account or standing access. It works like a role trust policy in cloud IAM.
How role assumption works
- A root administrator creates a trust that names the source tenant and identity, the target role, and optional safeguards.
- The source identity calls
roles.assumewith the trust's ID (and the external ID, when the trust requires one). The source also needsiam:roles:assumeon the role's ID in its own tenant, so its own administrators decide who may use trusts at all. - The call returns a short-lived role session token. Requests made with it act in the target tenant with the
role's permissions, never more than the trust's
ceiling.
The safeguards are checked on every assumption:
requireMfa(defaulttrue): the source session must be MFA-verified.externalId: a shared value the caller must present, which protects against a confused deputy (someone tricking a trusted service into assuming the role on their behalf). Only its SHA-256 hash is stored.ceiling: a policy document that caps what role sessions may do, whatever the role grants. Without one, the role's own permissions are the limit.
A role session cannot assume another role, and a "view as" (impersonation) session cannot assume roles at all. Role sessions stop working at their next use once the trust is revoked. The protected Owner role can never be the target of a trust.
Trust options and session attributes
Identity trusts also carry typed knobs, set at creation or later with update (root only):
maxSessionSeconds: the longest role session the trust issues, from 60 up to the deployment'ssts.maxRoleSessionSeconds; 3600 when unset.passSourceAttributes: whether the source identity's attributes reach policies asprincipal.{attribute}in role sessions. New cross-tenant trusts default tofalse, so another tenant's attribute values cannot satisfy this tenant's conditions; same-tenant trusts default totrue, and trusts created before the option existed keep passing attributes until you change them.analysis.findingsreports cross-tenant trusts that still pass them.allowedTagKeys: the session tag keys a caller may set onroles.assume(at most 50, or['*']for any); none by default. Tags reach policies asprincipal.sessionTags.{key}.sourceIdentityMode: whether a caller may (optional), must (required), or may not (forbidden, the default) name a source identity, which policies read asprincipal.sourceIdentity.description: up to 512 characters for the people reviewing the trust.
Tags and a source identity are closed by default because a caller chooses their values, and both can satisfy policy
conditions. Revocation is covered by revokeSessions, which ends sessions issued before a point in
time without revoking the trust.
Web-identity trusts
A trust of kind web-identity admits tokens from an external OpenID Connect provider (see
oidcProviders) instead of a named identity, for CI jobs and workloads that
exchange their platform token through
sts.assumeRoleWithWebIdentity. Unlike identity trusts, they are
tenant-managed: an administrator with iam:trust:create on the role creates one, and only that administrator's grant
authority (or root) may change or revoke it. Each one names:
- the provider (
providerId) and an active service account of the tenant (serviceAccountId) that sessions act as; conditionson the verified token's claims, written in the policy condition grammar overtoken.{claim}keys (nested claims are joined with dots, such astoken.kubernetes.io.namespace). They must pintoken.subwithStringEqualsorStringLikewithout a leading wildcard, or creation fails withWEAK_TRUST_CONDITIONS;- optionally
tagClaims(session tag key to claim name, at most 10),sourceIdentityClaim,maxSessionSeconds,ceiling,passSourceAttributes(defaulttrue), anddescription.
Sessions are bounded by the role, the trust's ceiling, and the grant authorities of the trust's and the provider's
creators; revoking either authority, disabling the provider or the service account, or revoking the trust ends them.
Web identity must be enabled on the deployment (sts.webIdentity.enabled) to create, change, or revoke one.
| Method | What it does | Access |
|---|---|---|
create | Creates a trust that lets one source identity assume one role of this tenant. | Credential |
evaluateWebIdentity | Checks what a web-identity trust would conclude about an external token, without issuing anything. | Credential |
list | Lists the trusts that target this tenant's roles. | Credential |
revoke | Revokes a trust so its source can no longer assume the role, and ends the role sessions already issued under it. | Credential |
revokeSessions | Ends the role sessions issued under one trust before a point in time, without revoking the trust. | Credential |
update | Changes a trust's safeguards and options, such as its MFA requirement, ceiling, session length, attribute passing, tag keys, source identity mode, or a web-identity trust's conditions and claim mappings. | Credential |
create
Creates a trust that lets one source identity assume one role of this tenant.
Used inTemporary access
- Permission:
iam:trust:createon the role (iam/{roleId}); root administrators only, with recent authentication. - Audited as:
iam:trust:create. - Errors:
ACCESS_DENIEDfor anyone but a root administrator;RECENT_AUTH_REQUIREDwithout recent authentication;PROTECTED_RESOURCEwhen the role is the Owner role;NOT_FOUNDwhen the role is not in this tenant or the source identity is not insourceTenantId;INVALID_POLICY,INVALID_ACTION, orINVALID_RESOURCE_TYPEfor aceilingstorage would reject;INVARIANT_VIOLATIONwhen the trust would newly break an enforced access invariant.
Trusts are platform-controlled because they cross tenant boundaries: a tenant administrator cannot open their
tenant to an outside identity on their own. Keep requireMfa on; analysis.findings
reports trusts without it. Give each trust the narrowest ceiling the task needs.
With kind: 'web-identity' the call creates a web-identity trust instead: iam:trust:create
on the role without root, recent authentication, and sts.webIdentity.enabled (else FEATURE_DISABLED). It fails
with WEAK_TRUST_CONDITIONS when the conditions do not pin token.sub, INVALID_IDENTITY when the service account
is not an active service account, and INVALID_INPUT for identity-trust fields such as sourceTenantId or
requireMfa. Both kinds return the public trust, which reports requiresExternalId instead of the stored hash.
const trust = await iam.api.trust.create(rootCredential, {
tenantId: customerTenantId,
sourceTenantId: rootTenantId,
sourceIdentityId: supportEngineerId,
roleId: supportRoleId,
externalId: 'ticket-routing-7f3a',
ceiling: {
version: 1,
statements: [{ effect: 'allow', actions: ['iam:identities:read', 'iam:audit:read'], resources: ['*'] }],
},
});One of IdentityTrustCreateInput | WebIdentityTrustCreateInput.
A PublicTrust object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/trust/create" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"sourceTenantId": "<sourceTenantId>",
"sourceIdentityId": "<sourceIdentityId>",
"roleId": "<roleId>"
}'iam.api.trust.create(
credential: CredentialInput,
input: TrustCreateInput,
): Promise<PublicTrust>evaluateWebIdentity
Checks what a web-identity trust would conclude about an external token, without issuing anything.
Used inTemporary access
- Permission:
iam:trust:readon the trust, andsts.webIdentity.enabled. - Audited as:
iam:trust:read. - Errors:
FEATURE_DISABLEDwhen web identity is off;INVALID_INPUTfor a trust that is not a web-identity trust;NOT_FOUND.
The public exchange answers every refusal with the same WEB_IDENTITY_REJECTED, so callers cannot probe which
trusts exist. This dry run is how administrators find out why a token is refused: it returns verified, the
reason the exchange would give (a verification failure such as audience, expired, or unknown-key, or
conditions or source-identity), the verified registered claims, each failing condition as Operator:key, and
the session tags and source identity the claim mappings would produce. No replay record is written, so the token
stays redeemable.
const result = await iam.api.trust.evaluateWebIdentity(credential, { tenantId, trustId, webIdentityToken });
if (result.conditions && !result.conditions.matched) console.log(result.conditions.failed); // ['StringLike:token.sub']Prop
Type
A WebIdentityEvaluation object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/trust/evaluateWebIdentity" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"trustId": "<trustId>",
"webIdentityToken": "<webIdentityToken>"
}'iam.api.trust.evaluateWebIdentity(
credential: CredentialInput,
input: { tenantId: string; trustId: string; webIdentityToken: string },
): Promise<WebIdentityEvaluation>list
Lists the trusts that target this tenant's roles.
- Permission:
iam:trust:readon the tenant. - Audited as:
iam:trust:read.
Revoked trusts are left out unless includeRevoked is true. External ID hashes are never returned; instead,
requiresExternalId tells you whether callers must present one. Tenant administrators can use this to see who
outside the tenant may assume which role. Trusts of kind web-identity, which admit tokens from an external OpenID
Connect provider, appear here too.
Prop
Type
An array of PublicTrust.
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/trust/list" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.trust.list(
credential: CredentialInput,
input: { tenantId: string; includeRevoked?: boolean },
): Promise<PublicTrust[]>revoke
Revokes a trust so its source can no longer assume the role, and ends the role sessions already issued under it.
- Permission:
iam:trust:revokeon the trust (iam/{trustId}); root administrators only, with recent authentication. - Audited as:
iam:trust:revoke. - Errors:
ACCESS_DENIEDfor anyone but a root administrator;RECENT_AUTH_REQUIREDwithout recent authentication;NOT_FOUNDwhen the trust is not in this tenant.
Existing role sessions under the trust are refused at their next use. The record is kept with revoked: true, so
it still appears with includeRevoked and in the audit history. Revoking an already revoked trust succeeds.
The trust's live role sessions are also deleted in the same transaction, so they disappear from
roles.listSessions at once. A web-identity trust is revoked by the
administrator whose authority created it (or root) rather than root only, and needs sts.webIdentity.enabled
(FEATURE_DISABLED otherwise).
Prop
Type
A PublicTrust object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/trust/revoke" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"trustId": "<trustId>"
}'iam.api.trust.revoke(
credential: CredentialInput,
input: { tenantId: string; trustId: string },
): Promise<PublicTrust>revokeSessions
Ends the role sessions issued under one trust before a point in time, without revoking the trust.
- Permission:
iam:roles:revoke-sessionson the trust's role (iam/{roleId}), with recent authentication. It is not root-only, so the target tenant's administrators can end sessions under a platform-controlled trust. - Audited as:
iam:roles:revoke-sessionsandrole:sessions-revoked(with the watermark and the number of sessions deleted). - Errors:
INVALID_INPUTwhenbeforeis not a whole number of milliseconds, is negative, or lies in the future;NOT_FOUNDwhen the trust is not in this tenant;RECENT_AUTH_REQUIRED;ACCESS_DENIED.
before defaults to now, which ends every session issued so far. The trust's sessionsRevokedBefore watermark only
moves forward, so older sessions are refused at their next use and the matching rows are deleted at once, while new
assumptions keep working. Session JWTs that other services verify offline stay valid there until they expire; those
services can check sts.getCallerIdentity for an online answer.
const { revoked } = await iam.api.trust.revokeSessions(credential, { tenantId, trustId });A TrustRevokeSessionsInput object:
Prop
Type
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/trust/revokeSessions" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"trustId": "<trustId>"
}'iam.api.trust.revokeSessions(
credential: CredentialInput,
input: TrustRevokeSessionsInput,
): Promise<{ trustId: string; sessionsRevokedBefore: number; revoked: number }>update
Changes a trust's safeguards and options, such as its MFA requirement, ceiling, session length, attribute passing, tag keys, source identity mode, or a web-identity trust's conditions and claim mappings.
- Permission:
iam:trust:updateon the trust, with recent authentication. Identity trusts need a root administrator; web-identity trusts need the grant authority that created them (or root). - Audited as:
iam:trust:update. - Errors:
ACCESS_DENIEDfor anyone else;CONFLICT(409) for a revoked trust;INVALID_INPUTwhen nothing changes or a field belongs to the other kind of trust (conditions,tagClaims, orsourceIdentityClaimon an identity trust;requireMfa,allowedTagKeys, orsourceIdentityModeon a web-identity trust);WEAK_TRUST_CONDITIONSfor conditions that do not pintoken.sub;FEATURE_DISABLEDfor a web-identity trust while web identity is off;RECENT_AUTH_REQUIRED;NOT_FOUND.
Only the fields you pass change, and null returns ceiling, maxSessionSeconds, allowedTagKeys,
description, tagClaims, or sourceIdentityClaim to its default. Tightening what the trust admits (its tag keys,
source identity mode, conditions, claim mappings, or a shorter maxSessionSeconds) also moves the trust's
sessionsRevokedBefore watermark to now, so sessions issued under the looser rules end at their next use. Use it
to turn off passSourceAttributes on older cross-tenant trusts.
await iam.api.trust.update(rootCredential, { tenantId, trustId, passSourceAttributes: false, maxSessionSeconds: 900 });A TrustUpdateInput object:
Prop
Type
A PublicTrust object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/trust/update" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"trustId": "<trustId>"
}'iam.api.trust.update(
credential: CredentialInput,
input: TrustUpdateInput,
): Promise<PublicTrust>Better IAM is created by Sean Filimon
Last updated