Documentation Index

Fetch the complete documentation index at: https://kb.vastdata.com/llms.txt

Use this file to discover all available pages before exploring further.

STS AssumeRole with a Permanent Access Key Pair (No OIDC)

Prev Next

Grant a user temporary credentials by having them assume an IAM role while the user holds no S3 permissions of their own and no OIDC provider is involved. The permanent access key pair authenticates the STS request; the IAM role supplies the S3 permissions.

Requires VAST Cluster 5.4.3+. Authenticating AssumeRole with an access key
pair is unavailable in earlier 5.4.x (which support only OIDC/JWT).


When to use this

This pattern fits multi-tenant service providers and neoclouds that expose S3 on VAST and want AWS-style access control without distributing long-lived data credentials.

  • Low-privilege bootstrap key. Each tenant or workload holds a permanent key that does nothing in S3 on its own — it can only assume the roles you authorize.

  • Permissions live in roles you control. Define S3 access once per role; many users or jobs share it, and you change it in one place. An IAM role belongs to exactly one tenant — it is assumed by that tenant's users and grants access only within that tenant, so create a role per tenant.

  • Short-lived, scoped credentials on demand. Consumers mint a time-bounded set of credentials (15-minute minimum to 36-hour maximum) per job or pipeline, optionally narrowed further with a session policy. Ideal for ephemeral compute (training runs, batch, CI, etc.).

  • Instant, fleet-wide revocation. Kill all live sessions for a role at once, or remove a user from the trust policy. No re-keying anyone else. Clean offboarding and incident response.

    • iamrole revoke_access_keys --id <id>

       - Dropping a user means rewriting the trust policy without them. Here the User list was ["no-oidc-sts-user","alice"] and alice is dropped: iamrole modify --id 26 --trust-policy '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"User":"no-oidc-sts-user"},"Action":"sts:AssumeRole"}]}'

  • No external IdP required. The same role model as OIDC federation, self-contained on the cluster.

Security note: the long-lived secret is the permanent key — protect it and rotate it, keep session durations short, and monitor AssumeRole. If you have an identity provider, the OIDC variant is stronger still (no long-lived secret at all).

Transport: STS calls are HTTPS-only; the cluster rejects AssumeRole over HTTP. The resulting temporary keys work over either HTTP or HTTPS on the S3 data path.

Security note: the long-lived secret is the permanent key — protect it and rotate it, keep session durations short, and monitor AssumeRole. If you have an identity provider, the OIDC variant is stronger still (no long-lived secret at all).

Transport: STS calls are HTTPS-only; the cluster rejects AssumeRole over HTTP. The resulting temporary keys work over either HTTP or HTTPS on the S3 data path.


How it works

Authentication and authorization are separate mechanisms:

Stage

Question

Decided by

Credential

AssumeRole

May this user assume this role?

The role's trust policy

The user's permanent key (SigV4)

S3 requests

May this session perform this action?

The role's identity policies, bucket policies naming the role, and bucket ownership

The temporary key from STS

Tenant scope: an IAM role is a per-tenant object. The users in its trust policy, the buckets it can reach, and the VIP you call STS on all belong to that same tenant — nothing about a role crosses tenants. A role ARN naming a different tenant is rejected (InvalidArgument).

VAST S3 is default-deny: a request is denied unless something grants it—an identity policy, a bucket policy, or bucket ownership. The assuming user in this pattern has none of those, so the permanent key is purely an STS authentication credential and gets AccessDenied on every S3 request. After AssumeRole, STS returns a temporary key that carries the role's permissions.

The role's permissions can come from any combination of three sources, evaluated as a union (allow if any allows; explicit deny wins): identity policies attached to the role, bucket policies whose Principal names the role ({"Role": "<role-name>"} — role ARNs are not accepted in bucket policies), and bucket ownership — a role that owns a view/bucket (Step 4) has full implicit access to it, including bucket-policy management, with no policy required.

Authorization Flow chart

Keep the permanent key powerless: attach no S3 identity policy to the assuming user — directly or through a group. This doesn't change what the role session can do (a user's own policies never flow into their role sessions, and vice versa); it ensures that the long-lived permanent key cannot access data on its own, so every data access occurs through short-lived, revocable role credentials.


Working example

Values below are from a reference build; substitute your own.

Item

Value

Tenant

rando-tenant (id 10, VAST provider ID 15)

S3 + STS endpoint

https://10.1.100.1 (a protocol VIP; STS requires HTTPS)

Assuming username

no-oidc-sts-user — a user with no identity policy

Identity policy

s3-fullaccess-policys3:* on all resources (for my example)

IAM role

s3-fullaccess-role — trust policy names the user

View/bucket

rando-bucketname — S3 bucket and s3 protocol, owned by the role

View policy

no-oidc-sts-default (S3 Native)

Client needs the AWS CLI and jq.


Step 1 — User with a permanent key and no S3 permissions

The assuming user can come from any identity source configured for the tenant — the VAST provider (formerly "local provider"), AD, LDAP, or NIS. Any user with a permanent S3 access key pair can assume roles. Access keys are minted in a tenant context, so pass the tenant ID when generating the key:

tenant list # note the tenant's provider ID (VAST provider)
user generate_key --username no-oidc-sts-user --tenant-id 10

vcli: admin> user generate_key --username no-oidc-sts-user --tenant-id 10
{'access_key': '5C87Lfoo-bar-baz5CDTP9A',
 'secret_key': 'ad/ZIRxVIq2rfoo-bar-bazsp/L339GYMhn'}
vcli: admin>

Record the returned access_key / secret_key (the secret is shown once).

Verify the user has no S3 identity policy — directly or via group membership — in the Web UI (user → Identity Policies). This is the control that keeps the permanent key powerless on its own.


Step 2 — Identity policy granting full S3

This is the permission set the assumed session will carry. Pass the policy as compact JSON:

identitypolicy create --name s3-fullaccess-policy --tenant-id 10 \
  --policy '{"Version":"2012-10-17","Statement":[{"Sid":"FullS3Control","Effect":"Allow","Action":"s3:*","Resource":"*"}]}'

Note the returned policy ID (e.g. 1292). Narrow down Action/Resource for production use.

An identity policy is not the only way to grant the role access. A bucket policy with "Principal": {"Role": "<role-name>"} works too, and a role that owns the bucket (Step 4) already has full access to that bucket with no policy at all. In this example the identity policy is what grants access beyond the role-owned bucket.


Step 3 — IAM role with a trust policy that names the user

The trust policy is the authorization gate. Action is sts:AssumeRole; the principal is the user name. Attach the identity policy by ID:

iamrole create --name s3-fullaccess-role --tenant-id 10 --identity-policies-ids 1292 \
  --trust-policy '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"User":"no-oidc-sts-user"},"Action":"sts:AssumeRole"}]}'
  • Multiple users: "User":["no-oidc-sts-user","alice"].

  • AD/LDAP users: use user@domain as the principal.

  • Always replace the factory-default trust policy ("Principal":"*","Action":"sts:*"); it lets anyone assume the role.

  • Optional --max-session-duration <seconds> (900–129600).


Step 4 — View/bucket owned by the role

Pick an existing S3 Native view policy (or create one), then create the view with the role as bucket owner:

viewpolicy list                   # choose an S3_NATIVE policy in tenant 10 → note its id (e.g. 40)

view create --path /noidc-sts-bucket --bucket noidc-sts-bucket \
  --bucket-owner s3-fullaccess-role --bucket-owner-type ROLE \
  --policy-id 40 --protocols S3 --tenant-id 10 --create-dir

--bucket-owner-type ROLE makes the role the bucket owner, which by itself grants the assumed session full access to this bucket. Confirm:

view list --path=/noidc-sts-bucket

Step 5 — Assume the role and use S3

Authenticate with the permanent key, capture the temporary credentials with jq, then operate on S3:

# Permanent key authenticates the STS request
export AWS_ACCESS_KEY_ID=<permanent-access-key>
export AWS_SECRET_ACCESS_KEY=<permanent-secret-key>
unset AWS_SESSION_TOKEN

CREDS=$(aws sts assume-role \
  --role-arn arn:vast::rando-tenant:role/s3-fullaccess-role \
  --role-session-name session1 \
  --endpoint-url https://10.1.100.1 \
  --duration-seconds 3600 --no-verify-ssl)

export AWS_ACCESS_KEY_ID=$(echo "$CREDS" | jq -r .Credentials.AccessKeyId)
export AWS_SECRET_ACCESS_KEY=$(echo "$CREDS" | jq -r .Credentials.SecretAccessKey)
export AWS_SESSION_TOKEN=$(echo "$CREDS" | jq -r .Credentials.SessionToken)

aws s3 ls s3://noidc-sts-bucket/ --endpoint-url https://10.1.100.1 --no-verify-ssl
echo hello | aws s3 cp - s3://noidc-sts-bucket/hello.txt --endpoint-url https://10.1.100.1 --no-verify-ssl

The jq capture avoids hand-copying the long secret and session token (a dropped character produces SignatureDoesNotMatch or InvalidToken). Temporary keys are prefixed TEMP, distinguishing them from permanent keys at a glance.

ARN format: arn:vast::<tenant>:role/<role> (empty account field - double colon). The tenant must match the permanent key's tenant.

Confirm the boundary

Credential

aws s3 ls/cp on the bucket

Permanent key (no session token)

AccessDenied

Temporary key (after AssumeRole)

Full access

Parameters

Parameter

Notes

--role-arn

arn:vast::<tenant>:role/<role>; tenant matches the permanent key.

--role-session-name

Any label for the session.

--endpoint-url

A protocol VIP; STS requires HTTPS.

--duration-seconds

900–129600 (36 h). Requests above the role's max session duration are rejected (ValidationError), not silently capped.

--policy

Optional inline session policy (≤2K).


Revoking access

Goal

Command/action

Invalidate all live sessions for the role

iamrole revoke_access_keys --id <ROLE_ID>

Stop a user from assuming the role

Remove them from the trust policy (iamrole modify); combine with revoke for an immediate cutoff

Disable the user entirely

Remove the user's permanent access key

Revocation is immediate — in-flight temporary keys stop working on the next request — and it does not block new AssumeRole calls afterward.


Troubleshooting

Symptom

Cause

Fix

Permanent key can access S3 directly

The user has an S3 identity policy attached (directly or via group)

Detach it; only the role should carry S3 permissions

assume-roleAccessDenied

User not in the trust policy

Match Principal.User exactly

assume-roleInvalidArgument

Wrong tenant in the role ARN (or role doesn't exist in that tenant)

The ARN tenant must equal the permanent key's tenant: arn:vast::<tenant>:role/<role>

assume-roleValidationError

--duration-seconds exceeds the role's max session duration

Lower the request or raise the role's --max-session-duration

S3 AccessDenied after assuming

Role identity policy or inline session policy too narrow

Check iamrole show --id <ID> --identity-policies and any --policy passed

AccessDenied on aws s3 mb

Bucket creation via the S3 API is denied for role sessions

Create buckets as views (Step 4)

aws s3 ls with no bucket lists only buckets the principal owns and returns empty (not denied); always test against a specific bucket.


Permanent key vs. OIDC

Permanent access key (this guide)

OIDC / JWT

Action

sts:AssumeRole

sts:AssumeRoleWithWebIdentity

CLI

aws sts assume-role

aws sts assume-role-with-web-identity

Caller auth

SigV4 permanent key

--web-identity-token <JWT>

Trust principal

{"User":"<name>"}

{"Federated":"oidc-provider/<issuer>"}

External IdP

None

Required

Min version

5.4.3

5.4.0