Assign a Resource Access Management (RAM) role to an Elastic Container Instance-based pod so that applications running in the pod can call other Alibaba Cloud service APIs using Security Token Service (STS) temporary credentials — without storing an AccessKey pair in the pod.
Why use a RAM role
Storing an AccessKey pair directly in a pod (for example, in a configuration file) creates several problems:
Credential exposure: A leaked AccessKey pair grants permanent access until manually revoked.
Excessive permissions: A shared AccessKey pair is hard to scope to only what each pod needs.
High maintenance overhead: Rotating credentials requires updating every pod that stores them.
A RAM role eliminates these problems. The pod assumes the role at runtime and receives short-lived STS credentials that are automatically rotated. To change what a pod can access, update the role's permission policy — no pod restart required.
For background on RAM roles, see RAM role overview.
Prerequisites
Before you begin, ensure that you have:
An Elastic Container Instance-based pod (or a Deployment that schedules ECI pods)
(Optional) If a RAM user will perform this setup, the RAM user must have the
ram:PassRolepermission for the target role. See step 3 in Create a RAM role and grant permissions
Create a RAM role and grant permissions
Create a RAM role. For more information, see Create a RAM role for a trusted Alibaba Cloud service. When prompted, select Alibaba Cloud Service as the trusted entity and Elastic Compute Service as the trusted service.

Attach a permission policy to the role.
Create a custom policy. For more information, see Create custom policies.
Attach the policy to the RAM role. For more information, see Grant permissions to a RAM role.
(Optional) Grant a RAM user permission to pass the role. If a RAM user will assign this role to pods, the RAM user needs the
ram:PassRolepermission scoped to the role. ReplaceECIRamRoleTestwith your role name.{ "Statement": [ { "Effect": "Allow", "Action": "ram:PassRole", "Resource": "acs:ram:*:*:role/ECIRamRoleTest" } ], "Version": "1" }
Assign the RAM role to a pod
Add the k8s.aliyun.com/eci-ram-role-name annotation to the pod's metadata when creating it. Replace ${your_ram_role_name} with your RAM role name.
Annotations take effect only when the pod is created. Adding or modifying annotations on an existing pod has no effect. For a Deployment, add the annotation under spec.template.metadata, not under the top-level metadata.
apiVersion: apps/v1
kind: Deployment
metadata:
name: test
labels:
app: test
spec:
replicas: 1
selector:
matchLabels:
app: test
template:
metadata:
name: test
labels:
app: test
alibabacloud.com/eci: "true"
annotations:
k8s.aliyun.com/eci-ram-role-name: "${your_ram_role_name}" # Assign the RAM role.
spec:
containers:
- name: test
image: registry.cn-shanghai.aliyuncs.com/eci_open/centos:7
command: ["sleep"]
args: ["3600"]Verify the configuration
After the pod starts, confirm it can retrieve STS credentials from the instance metadata service.
Run the following command from inside the pod. Replace ${your_ram_role_name} with your RAM role name.
curl http://100.100.100.200/latest/meta-data/ram/security-credentials/${your_ram_role_name}For example, if your role is named ECIRamRoleTest:
curl http://100.100.100.200/latest/meta-data/ram/security-credentials/ECIRamRoleTestA successful response looks like this:
{
"AccessKeyId": "STS.******",
"AccessKeySecret": "******",
"Expiration": "2023-06-22T19:13:58Z",
"SecurityToken": "******",
"LastUpdated": "2023-06-22T13:13:58Z",
"Code": "Success"
}If the response returns Code: Success, the role is correctly assigned and credentials are available. STS credentials are automatically rotated before they expire.
Access Alibaba Cloud services using STS credentials
The following Go example retrieves STS credentials from the metadata service and uses them to list objects in an Object Storage Service (OSS) bucket.
This example demonstrates the pattern for using STS credentials. In production, adapt the code to your business logic and consult the SDK documentation for the service you are calling. Refresh the OSS client before credentials expire to avoid access failures.
package main
import (
"encoding/json"
"flag"
"log"
"os/exec"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
)
const (
securityCredUrl = "http://100.100.100.200/latest/meta-data/ram/security-credentials/"
)
var (
ossEndpoint string
ossBucketName string
)
func init() {
flag.StringVar(&ossEndpoint, "endpoint", "oss-cn-hangzhou-internal.aliyuncs.com", "Please input oss endpoint, Recommended internal endpoint, eg: oss-cn-hangzhou-internal.aliyuncs.com")
flag.StringVar(&ossBucketName, "bucket", "", "Please input oss bucket name")
}
type AssumedRoleUserCredentialsWithServiceIdentity struct {
AccessKeyId string `json:"AccessKeyId" xml:"AccessKeyId"`
AccessKeySecret string `json:"AccessKeySecret" xml:"AccessKeySecret"`
Expiration string `json:"Expiration" xml:"Expiration"`
SecurityToken string `json:"SecurityToken" xml:"SecurityToken"`
LastUpdated string `json:"LastUpdated" xml:"LastUpdated"`
Code string `json:"Code" xml:"Code"`
}
func main() {
flag.Parse()
if ossEndpoint == "" {
log.Fatal("Please input oss endpoint, eg: oss-cn-hangzhou-internal.aliyuncs.com")
}
if ossBucketName == "" {
log.Fatal("Please input oss bucket name")
}
// Retrieve the RAM role name from the metadata service.
output, err := exec.Command("curl", securityCredUrl).Output()
if err != nil {
log.Fatalf("Failed to get RAM role name from metadata service: %s", err)
}
// Retrieve STS credentials for the role.
output, err = exec.Command("curl", securityCredUrl+string(output)).Output()
if err != nil {
log.Fatalf("Failed to get security credentials from metadata service: %s", err)
}
authServiceIdentity := new(AssumedRoleUserCredentialsWithServiceIdentity)
if err := json.Unmarshal(output, authServiceIdentity); err != nil {
log.Fatalf("Failed to unmarshal security credentials: %s", err)
}
// Create an OSS client using STS credentials.
// In production, refresh the client before credentials expire to maintain continuous access.
ossClient, err := oss.New(ossEndpoint, authServiceIdentity.AccessKeyId,
authServiceIdentity.AccessKeySecret, oss.SecurityToken(authServiceIdentity.SecurityToken))
if err != nil {
log.Fatalf("Failed to create OSS client: %s", err)
}
// Get a reference to the bucket.
bucket, err := ossClient.Bucket(ossBucketName)
if err != nil {
log.Fatalf("Failed to get bucket %q: %s", ossBucketName, err)
}
// List all objects in the bucket. By default, up to 100 objects are returned per request.
marker := ""
for {
lsRes, err := bucket.ListObjects(oss.Marker(marker))
if err != nil {
log.Fatalf("Failed to list objects in bucket %q: %s", ossBucketName, err)
}
for _, object := range lsRes.Objects {
log.Println("Object:", object.Key)
}
if lsRes.IsTruncated {
marker = lsRes.NextMarker
} else {
break
}
}
}What's next
RAM role overview — learn how RAM roles and STS work together
Grant permissions to a RAM role — refine what services the role can access