RAM Roles for Service Accounts (RRSA) lets each pod in a Container Service for Kubernetes (ACK) cluster assume a dedicated Resource Access Management (RAM) role and obtain short-lived Security Token Service (STS) tokens for cloud service access.
RRSA provides two key security properties:
-
Least privilege: You can scope RAM permissions to a specific service account, so only pods using that account can access those resources. This eliminates the need for static AccessKey pairs.
-
Credential isolation: Pods cannot access credentials used by other pods on the same node. Without RRSA, all pods on a node share the permissions of the underlying Elastic Compute Service (ECS) instance role.
How it works
Without RRSA, applications running in ACK pods use the ECS instance metadata to obtain STS tokens tied to the instance role. Every pod on that node shares the same permissions — a significant security risk.
RRSA solves this by binding a specific RAM role to a specific Kubernetes service account. When a pod starts, it receives an OpenID Connect (OIDC) token scoped to its service account. The pod uses that token to call the AssumeRoleWithOIDC API and receive a role-scoped STS token, which it then uses to call cloud service APIs.
The flow, step by step:
-
The pod starts with service account token volume projection enabled.
-
ACK mounts an OIDC token file into the pod, scoped to the pod's service account.
-
The application calls
AssumeRoleWithOIDCwith the OIDC token and receives an STS token for the specified RAM role. -
The application uses the STS token to call the target cloud service API.
The OIDC token is short-lived. Configure your application to read the token from the OIDC token file each time it needs to authenticate — do not cache it. ACK automatically renews the token before it expires.
When RRSA is enabled, ACK performs the following setup automatically:
-
Creates a dedicated OIDC issuer for the cluster, managed by ACK.
-
Enables service account token volume projection for the cluster.
-
Creates a RAM identity provider (IdP) in your account, named
ack-rrsa-<cluster_id>, configured for single sign-on (SSO) with the cluster's OIDC issuer.
Limitations
RRSA is supported on ACK clusters running Kubernetes 1.22 and later. Supported cluster types:
-
ACK Basic cluster
-
ACK Pro cluster
-
ACK Serverless Basic cluster
-
ACK Serverless Pro cluster
-
ACK Edge Pro cluster
After RRSA is enabled, the maximum validity period for all newly created ServiceAccount tokens is capped at 12 hours.
Prerequisites
Before you begin, ensure that you have:
-
An ACK cluster running Kubernetes 1.22 or later
-
Permissions to manage RAM roles and policies in the RAM console
-
Permissions to manage add-ons and cluster settings in the ACK console
Enable RRSA
You can enable RRSA during cluster creation or after the cluster is running. For ACK Serverless clusters, enable RRSA after cluster creation from the cluster details page.
Enable during cluster creation
When creating an ACK managed cluster or ACK Edge cluster, go to the Cluster Configurations step, expand Advanced Options (Optional), and click Enable next to RRSA OIDC.
Enable after cluster creation
-
Log on to the ACK console. In the left navigation pane, click Clusters.
-
Click the name of your cluster. In the left navigation pane, click Cluster Information.
-
On the Basic Information tab, scroll to the Security and Auditing section and click Enable next to RRSA OIDC.

-
In the Enable RRSA dialog box, click Confirm. Wait for the cluster status to change from Updating to Running. RRSA is now enabled.
Get the OIDC provider URL and ARN
After RRSA is enabled, hover over the Enabled label next to RRSA OIDC in the Security and Auditing section. The URL and Alibaba Cloud Resource Name (ARN) of the OIDC provider are displayed.
You need both values when configuring RAM roles and application templates.
Set up RRSA for an application
This section walks through the full setup for a sample application. The setup has two parts:
-
Cluster-level setup (do once per cluster): Enable RRSA and install
ack-pod-identity-webhook. -
Per-application setup (repeat for each app): Create a RAM role, grant permissions, deploy the application.
Sample configuration:
| Item | Value |
|---|---|
| Namespace | rrsa-demo |
| Service account | demo-sa |
| RAM role | demo-role-for-rrsa |
Step 1: Install ack-pod-identity-webhook
ack-pod-identity-webhook automatically injects the OIDC token file path and RAM role ARN into pods as environment variables. Skip this step if you prefer to configure the pod template manually — see Configure the pod template manually.
-
In the ACK console, click the name of your cluster. In the left navigation pane, choose Operations > Add-ons.
-
On the Add-ons page, click the Security tab.
-
Find ack-pod-identity-webhook and click Install on the card.
-
Confirm the information and click OK.
Step 2: Create a RAM role for the OIDC identity provider
Create a RAM role named demo-role-for-rrsa that trusts the cluster's OIDC identity provider (IdP). For full instructions, see Create a RAM role for an OIDC IdP.
Use the following parameter values:
| Parameter | Value |
|---|---|
| Identity Provider Type | Select OIDC |
| Identity Provider | Select the IdP named ack-rrsa-<cluster_id> |
| oidc:iss | Use the default value |
| oidc:aud | Use the default value |
| oidc:sub | Add this condition manually: Key = oidc:sub, Operator = StringEquals, Value = system:serviceaccount:rrsa-demo:demo-sa |
| RAM Role Name | demo-role-for-rrsa |
Theoidc:subcondition scopes the trust to a specific service account in a specific namespace. Replacerrsa-demoanddemo-sawith your actual namespace and service account name.
Step 3: Grant permissions to the RAM role
Attach the AliyunCSReadOnlyAccess policy to demo-role-for-rrsa. For instructions, see Grant permissions to a RAM role.
This grants the application read-only access to ACK cluster information.
Step 4: Deploy the application
Create a file named demo.yaml with the following content. The namespace label pod-identity.alibabacloud.com/injection: 'on' and the service account annotation pod-identity.alibabacloud.com/role-name: demo-role-for-rrsa enable automatic injection by ack-pod-identity-webhook. For configuration details, see ack-pod-identity-webhook.
---
apiVersion: v1
kind: Namespace
metadata:
name: rrsa-demo
labels:
pod-identity.alibabacloud.com/injection: 'on'
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: demo-sa
namespace: rrsa-demo
annotations:
pod-identity.alibabacloud.com/role-name: demo-role-for-rrsa
---
apiVersion: v1
kind: Pod
metadata:
name: demo
namespace: rrsa-demo
spec:
serviceAccountName: demo-sa
containers:
- image: registry.cn-hangzhou.aliyuncs.com/acs/ack-ram-tool:1.2.0
imagePullPolicy: "Always"
args:
- rrsa
- demo
- --region=cn-hangzhou
name: demo
restartPolicy: OnFailure
Deploy the application:
kubectl apply -f demo.yaml
Step 5: Verify the injected configuration
Run the following command to confirm that ack-pod-identity-webhook injected the required environment variables and volume mounts into the pod:
kubectl -n rrsa-demo get pod demo -o yaml
The expected output includes the following injected items:
| Category | Item | Description |
|---|---|---|
| Environment variable | ALIBABA_CLOUD_ROLE_ARN |
ARN of the RAM role to assume |
| Environment variable | ALIBABA_CLOUD_OIDC_PROVIDER_ARN |
ARN of the OIDC identity provider |
| Environment variable | ALIBABA_CLOUD_OIDC_TOKEN_FILE |
Path to the OIDC token file |
| VolumeMount | rrsa-oidc-token |
Mounts the OIDC token into the container |
| Volume | rrsa-oidc-token |
Projected volume source for the OIDC token |
A correctly injected pod spec looks like this:
apiVersion: v1
kind: Pod
metadata:
name: demo
namespace: rrsa-demo
spec:
containers:
- args:
- rrsa
- demo
env:
- name: ALIBABA_CLOUD_ROLE_ARN
value: acs:ram::1***:role/demo-role-for-rrsa
- name: ALIBABA_CLOUD_OIDC_PROVIDER_ARN
value: acs:ram::1***:oidc-provider/ack-rrsa-c***
- name: ALIBABA_CLOUD_OIDC_TOKEN_FILE
value: /var/run/secrets/ack.alibabacloud.com/rrsa-tokens/token
image: registry.cn-hangzhou.aliyuncs.com/acs/ack-ram-tool:1.0.0
imagePullPolicy: Always
name: demo
volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: kube-api-access-4bwdg
readOnly: true
- mountPath: /var/run/secrets/ack.alibabacloud.com/rrsa-tokens
name: rrsa-oidc-token
readOnly: true
restartPolicy: OnFailure
serviceAccount: demo-sa
serviceAccountName: demo-sa
volumes:
- name: kube-api-access-4bwdg
projected:
defaultMode: 420
sources:
- serviceAccountToken:
expirationSeconds: 3607
path: token
- configMap:
items:
- key: ca.crt
path: ca.crt
name: kube-root-ca.crt
- downwardAPI:
items:
- fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
path: namespace
- name: rrsa-oidc-token
projected:
defaultMode: 420
sources:
- serviceAccountToken:
audience: sts.aliyuncs.com
expirationSeconds: 3600
path: token
Step 6: Check application logs
Run the following command to print the application log:
kubectl -n rrsa-demo logs demo
A successful run lists the clusters in your Alibaba Cloud account:
cluster id: cf***, cluster name: foo*
cluster id: c8***, cluster name: bar*
cluster id: c4***, cluster name: foob*
Optional: To verify that RRSA correctly enforces least-privilege access, detach the AliyunCSReadOnlyAccess policy from the RAM role (see Remove permissions from a RAM role). Wait 30 seconds, then run the log command again. The application returns a 403 error similar to:
StatusCode: 403
Code: StatusForbidden
Message: code: 403, STSToken policy Forbidden for action cs:DescribeClustersForRegion request id: E78A2E2D-***
Data: {"accessDeniedDetail":{"AuthAction":"cs:DescribeClustersForRegion","AuthPrincipalDisplayName":"demo-role-for-rrsa:ack-ram-tool","AuthPrincipalOwnerId":"11***","AuthPrincipalType":"AssumedRoleUser","NoPermissionType":"ImplicitDeny","PolicyType":"ResourceGroupLevelIdentityBasedPolicy"},"code":"StatusForbidden","message":"STSToken policy Forbidden for action cs:DescribeClustersForRegion","requestId":"E78A2E2D-***","status":403,"statusCode":403}
This confirms that RRSA is enforcing permissions at the pod level.
Use an existing RAM role
To use an existing RAM role instead of creating a new one, update the role's trust policy to allow the service account to assume it. For instructions, see Edit the trust policy of a RAM role.
Add a Statement entry with the following structure:
{
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"oidc:aud": "sts.aliyuncs.com",
"oidc:iss": "<oidc_issuer_url>",
"oidc:sub": "system:serviceaccount:<namespace>:<service_account>"
}
},
"Effect": "Allow",
"Principal": {
"Federated": [
"<oidc_provider_arn>"
]
}
}
Replace the placeholders:
| Placeholder | Value |
|---|---|
<oidc_issuer_url> |
URL of the cluster's OIDC provider — see Get the OIDC provider URL and ARN |
<oidc_provider_arn> |
ARN of the cluster's OIDC provider — see Get the OIDC provider URL and ARN |
<namespace> |
Namespace of the application |
<service_account> |
Service account used by the application |
To automate trust policy updates, use ack-ram-tool:
ack-ram-tool rrsa associate-role --cluster-id <cluster_id> \
--namespace <namespace> --service-account <service_account> \
--role-name <role_name> --create-role-if-not-exist
SDK support
Alibaba Cloud SDK V2.0 supports RRSA OIDC token authentication. All cloud service SDKs that support STS token authentication and are built on Alibaba Cloud SDK V2.0 support RRSA automatically.
Supported SDK versions and demos
| Language | Minimum version | Demo |
|---|---|---|
| Go | Alibaba Cloud Credentials for Go 1.2.6 | Go SDK demo |
| Java | Alibaba Cloud Credentials for Java 0.2.10 | Java SDK demo |
| Python 3 | Alibaba Cloud Credentials for Python 0.3.1 | Python SDK demo |
| Node.js / TypeScript | Alibaba Cloud Credentials for TypeScript/Node.js 2.2.6 | Node.js SDK demo |
For the authentication method reference ("Method 6: Use the RAM role of an OIDC IdP"), see the credentials documentation for each language.
Cloud-service-specific SDK demos
Some cloud service SDKs have their own OIDC token support. The following demos show how to use RRSA with those SDKs:
| Cloud service | SDK | Demo |
|---|---|---|
| Object Storage Service (OSS) | OSS Go SDK — Method 5: Use OIDCRoleARN | Go demo |
| OSS | OSS Java SDK — Configure access credentials | Java demo |
| OSS | OSS Python SDK — Use the role of an OIDC IdP | Python demo |
| Simple Log Service | Simple Log Service SDK for Java | Java demo |
Enable RRSA authentication for CLIs
Use ack-ram-tool to configure commonly used CLIs so they can authenticate using RRSA OIDC tokens from within a pod.
Alibaba Cloud CLI
Alibaba Cloud CLI v3.0.206 and later support RRSA. Set region_id to your target region.
Option A: Configuration file. Set mode to OIDC in ~/.aliyun/config.json:
{
"current": "rrsa",
"profiles": [
{
"name": "rrsa",
"mode": "OIDC",
"region_id": "cn-hangzhou",
"ram_session_name": "test-rrsa"
}
],
"meta_path": ""
}
Option B: Direct command (no configuration file required):
aliyun sts GetCallerIdentity --region cn-hangzhou --role-session-name=test-rrsa
Expected output:
{
"AccountId": "11380***",
"Arn": "acs:ram::1138***:assumed-role/test-rrsa-***/test-rrsa",
"IdentityType": "AssumedRoleUser",
"PrincipalId": "33300***:test-rrsa",
"RequestId": "20F78881-F47E-5771-90D6-***",
"RoleId": "33300***"
}
For credential type details, see Credential types.
ossutil 2.0
ossutil V2.1.0 and later support RRSA. Replace region with your actual region.
Set mode to oidcRoleArn in ~/.ossutilconfig:
cat <<EOF > ~/.ossutilconfig
[default]
mode = oidcRoleArn
OIDCProviderArn = "${ALIBABA_CLOUD_OIDC_PROVIDER_ARN}"
OIDCTokenFilePath = "${ALIBABA_CLOUD_OIDC_TOKEN_FILE}"
roleArn = "${ALIBABA_CLOUD_ROLE_ARN}"
roleSessionName = test-rrsa
region = cn-hangzhou
EOF
For configuration examples, see Examples in the ossutil 2.0 documentation.
Simple Log Service CLI
Simple Log Service CLI does not support OIDC configuration files. Use ack-ram-tool to inject credentials at runtime:
ack-ram-tool export-credentials -f environment-variables -- aliyunlog log list_project --region-endpoint=cn-hangzhou.log.aliyuncs.com
Terraform
Alibaba Cloud Provider V1.222.0 and later supportassume_role_with_oidc. Setregionto your target region.
Add assume_role_with_oidc to your provider configuration:
provider "alicloud" {
assume_role_with_oidc {
role_session_name = "terraform-with-rrsa-auth-example"
}
region = "cn-hangzhou"
}
For complete examples, see Terraform RRSA demo.
Troubleshooting
SDK errors
| Error | Cause | Fix |
|---|---|---|
AuthenticationFail.OIDCToken.Expired — "This JsonWebToken is expired." |
The application cached the OIDC token and is using an expired copy. | Read the token from the file (ALIBABA_CLOUD_OIDC_TOKEN_FILE) each time you authenticate. Use an Alibaba Cloud SDK to handle this automatically — see SDK support. |
Throttling.User — "Request was denied due to user flow control." |
The application is calling AssumeRoleWithOIDC too frequently. |
Reuse the STS token until it expires. Do not re-fetch a token before the current one expires. Use an Alibaba Cloud SDK to manage token lifecycle automatically — see SDK support. |
AuthenticationFail.OIDCToken.AudienceNotMatch — "Invalid audience." |
The audience parameter in the pod spec is not set to sts.aliyuncs.com. |
Set audience: sts.aliyuncs.com in the projected volume source of the pod spec. |
AuthenticationFail.OIDCToken.IssuerConfigurationBroken / IssuerNotMatch / AuthenticationFail.NoPermission — "No such OIDC Provider registered." |
RRSA is not enabled for the cluster. | Enable RRSA for the cluster — see Enable RRSA. After enabling, recreate any pods that use RRSA. |
EntityNotExist.Role — "The role not exists: acs:ram::..." |
The RAM role assumed by the application does not exist. | Create the RAM role — see Create a RAM role for an OIDC IdP and Step 2: Create a RAM role for the OIDC identity provider. |
AuthenticationFail.NoPermission — "There is no permission" |
The RAM role does not have a trust policy that allows the service account to assume it. | Update the trust policy — see Use an existing RAM role. |