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
AssumeRolewith 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
Userlist was["no-oidc-sts-user","alice"]andaliceis 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 |
|---|---|---|---|
| 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.
.png?sv=2026-02-06&spr=https&st=2026-08-19T19%3A36%3A43Z&se=2026-08-19T19%3A53%3A43Z&sr=c&sp=r&sig=FPPiP%2BlSY6FCx%2FiGBHXmlHdE9zUZfLhIn6KNcgPFOv4%3D)
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 |
|
S3 + STS endpoint |
|
Assuming username |
|
Identity policy |
|
IAM role |
|
View/bucket | rando-bucketname — S3 bucket and s3 protocol, owned by the role |
View policy |
|
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@domainas 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-bucketStep 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-sslThe 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 |
|
|---|---|
Permanent key (no session token) |
|
Temporary key (after AssumeRole) | Full access |
Parameters
Parameter | Notes |
|---|---|
|
|
| Any label for the session. |
| A protocol VIP; STS requires HTTPS. |
| 900–129600 (36 h). Requests above the role's max session duration are rejected ( |
| Optional inline session policy (≤2K). |
Revoking access
Goal | Command/action |
|---|---|
Invalidate all live sessions for the role |
|
Stop a user from assuming the role | Remove them from the trust policy ( |
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 |
| User not in the trust policy | Match |
| Wrong tenant in the role ARN (or role doesn't exist in that tenant) | The ARN tenant must equal the permanent key's tenant: |
|
| Lower the request or raise the role's |
S3 | Role identity policy or inline session policy too narrow | Check |
| 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 |
|
|
CLI |
|
|
Caller auth | SigV4 permanent key |
|
Trust principal |
|
|
External IdP | None | Required |
Min version | 5.4.3 | 5.4.0 |