A RAM role is a virtual identity with a specific permission that an ECI pod can assume, thereby inheriting the role's permission. Assigning a role allows applications in the pod to use STS credentials from Security Token Service (STS) to access other Alibaba Cloud services.
Background
Applications deployed on ECI pods often use an AccessKey pair from an Alibaba Cloud account or a RAM user to access other Alibaba Cloud services, such as Object Storage Service (OSS), Virtual Private Cloud (VPC), and ApsaraDB RDS. For convenience, some users embed the AccessKey pair directly into the pod, for example, by hard-coding it in a configuration file. This practice creates security risks, including credential leaks, excessive permissions, and difficulties with key rotation and maintenance.
Using an instance RAM role eliminates the need to store an AccessKey pair in your ECI pods. You can change the permission for an ECI pod at any time by modifying the permission policies attached to its assigned RAM role. This method is more secure and convenient. For more information about RAM roles, see Overview of RAM roles.
Create a RAM role and grant permissions
-
Create a RAM role. For detailed instructions, see Create a RAM role for a trusted Alibaba Cloud service.
When you create the RAM role, select Alibaba Cloud Service as the trusted entity type and Elastic Compute Service as the trusted service.

-
Grant permissions to the RAM role.
-
Create a permission policy. For detailed instructions, see Create a custom policy.
-
Attach the permission policy to the RAM role. For detailed instructions, see Grant permissions to a RAM role.
-
-
(Optional) Authorize a RAM user to use the RAM role.
If you want a RAM user to assign the RAM role, you must grant the
ram:passRolepermission to that RAM user. The following policy shows an example where ECIRamRoleTest is the name of the RAM role that the user is permitted to pass.{ "Statement": [ { "Effect": "Allow", "Action": "ram:PassRole", "Resource": "acs:ram:*:*:role/ECIRamRoleTest" } ], "Version": "1" }
Assign RAM role to ECI pod
When you create an ECI pod, you can use the k8s.aliyun.com/eci-ram-role-name annotation to assign a RAM role. This allows the pod to access other Alibaba Cloud services.
Annotations must be added to the metadata in the configuration file of the pod. For example, when you create a Deployment, you must add annotations in the spec.template.metadata section.
Elastic Container Instance-related annotations are only applied when a pod is created. Adding or modifying these annotations on an existing pod will have no effect.
The following YAML file provides an example:
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"]
Obtain an STS token
From an ECI instance, you can access a metadata URL to retrieve an STS token for the assigned RAM role. You can use this token to access resources based on the permissions of the role. The STS token is automatically and periodically refreshed.
curl http://100.100.100.200/latest/meta-data/ram/security-credentials/${your_ram_role_name}
Replace ${your_ram_role_name} with the name of your RAM role. For example, if the role name is ECIRamRoleTest, the command is as follows:
curl http://100.100.100.200/latest/meta-data/ram/security-credentials/ECIRamRoleTest
The response contains the STS token. The following output provides an example:
{
"AccessKeyId" : "STS.******",
"AccessKeySecret" : "******",
"Expiration" : "2023-06-22T19:13:58Z",
"SecurityToken" : "******",
"LastUpdated" : "2023-06-22T13:13:58Z",
"Code" : "Success"
}
Accessing cloud services with an STS token
The following example shows how to use the Go SDK and an STS token to access Object Storage Service (OSS). In this example, the code accesses a specified OSS bucket and lists all the objects within it.
This example is for demonstration purposes only. In a production environment, write your code based on your specific business requirements. For more information, refer to the SDK documentation for the Alibaba Cloud service that you want to access.
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 provide an OSS bucket name.")
}
output, err := exec.Command("curl", securityCredUrl).Output()
if err != nil {
log.Fatalf("Failed to get the RAM role name from the metadata server: %s", err)
}
output, err = exec.Command("curl", securityCredUrl+string(output)).Output()
if err != nil {
log.Fatalf("Failed to get security credentials from the metadata server: %s", err)
}
authServiceIdentity := new(AssumedRoleUserCredentialsWithServiceIdentity)
if err := json.Unmarshal(output, authServiceIdentity); err != nil {
log.Fatalf("Failed to unmarshal to AssumedRoleUserCredentialsWithServiceIdentity: %s", err)
}
// Create an OSS client. In a production environment, you must periodically update the client to prevent access failures due to an expired STS token.
ossClient, err := oss.New(ossEndpoint, authServiceIdentity.AccessKeyId,
authServiceIdentity.AccessKeySecret, oss.SecurityToken(authServiceIdentity.SecurityToken))
if err != nil {
log.Fatalf("Failed to create an OSS client: %s", err)
}
// Get the bucket.
bucket, err := ossClient.Bucket(ossBucketName)
if err != nil {
log.Fatalf("Failed to get bucket %q: %s", ossBucketName, err)
}
// List objects in the bucket.
marker := ""
for {
lsRes, err := bucket.ListObjects(oss.Marker(marker))
if err != nil {
log.Fatalf("Failed to list objects from bucket %q: %s", ossBucketName, err)
}
// Print the listed objects. By default, a maximum of 100 objects are returned at a time.
for _, object := range lsRes.Objects {
log.Println("Object: ", object.Key)
}
if lsRes.IsTruncated {
marker = lsRes.NextMarker
} else {
break
}
}
}