Elastic Container Instance (ECI) ベースの Pod に Resource Access Management (RAM) ロールを割り当てることで、Pod 内で実行されるアプリケーションが、AccessKey ペアを Pod 内に保存することなく、セキュリティトークンサービス (STS) の一時的な認証情報を使用して、他の Alibaba Cloud サービスの API を呼び出せるようになります。
RAM ロールを使用する理由
AccessKey ペアを Pod 内(たとえば構成ファイル内)に直接格納すると、以下のような問題が発生します:
認証情報の漏洩リスク: 漏洩した AccessKey ペアは、手動で取り消すまで永続的に有効であり、不正アクセスのリスクを高めます。
過剰な権限付与: 共有される AccessKey ペアでは、各 Pod が実際に必要とする権限範囲を細かく制御することが困難です。
高いメンテナンス負荷: 認証情報のローテーションには、その認証情報を格納するすべての Pod の更新が必要です。
RAM ロールを活用することで、これらの課題を解消できます。Pod は実行時にロールを「偽装」し、自動的にローテーションされる短期間有効の STS 認証情報を取得します。Pod がアクセスできるリソースを変更する場合は、ロールに紐付ける権限ポリシーを更新するだけでよく、Pod の再起動は不要です。
RAM ロールの概要については、「RAM ロールの概要」をご参照ください。
前提条件
開始する前に、以下の条件を満たしていることを確認してください。
Elastic Container Instance (ECI) ベースの Pod(または ECI Pod をスケジュールするデプロイメント)が存在すること
(任意)RAM ユーザーが本設定を行う場合、当該 RAM ユーザーには対象ロールに対して
ram:PassRole権限が付与されている必要があります。「RAM ロールの作成と権限の付与」のステップ 3 をご参照ください。
RAM ロールの作成と権限の付与
RAM ロールを作成します。詳細については、「信頼できる Alibaba Cloud サービス向けの RAM ロールの作成」をご参照ください。プロンプト表示時に、信頼エンティティとして Alibaba Cloud サービス を、信頼サービスとして Elastic Compute Service を選択します。

ロールに権限ポリシーをアタッチします。
カスタムポリシーを作成します。詳細については、「カスタムポリシーの作成」をご参照ください。
ポリシーを RAM ロールにアタッチします。詳細については、「RAM ロールへの権限付与」をご参照ください。
(任意)RAM ユーザーにロールの渡し権限を付与します。RAM ユーザーがこのロールを Pod に割り当てる場合、当該 RAM ユーザーには、対象ロールを対象とした
ram:PassRole権限が必要です。ECIRamRoleTestは、ご利用のロール名に置き換えてください。{ "Statement": [ { "Effect": "Allow", "Action": "ram:PassRole", "Resource": "acs:ram:*:*:role/ECIRamRoleTest" } ], "Version": "1" }
Pod への RAM ロールの割り当て
Pod を作成する際に、k8s.aliyun.com/eci-ram-role-name アノテーションを Pod の metadata に追加します。${your_ram_role_name} は、ご利用の RAM ロール名に置き換えてください。
アノテーションは、Pod の作成時のみ有効です。既存の Pod に対してアノテーションを追加または変更しても、効果はありません。デプロイメントの場合、アノテーションは最上位の metadata ではなく、spec.template.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}" # RAM ロールを割り当てます。
spec:
containers:
- name: test
image: registry.cn-shanghai.aliyuncs.com/eci_open/centos:7
command: ["sleep"]
args: ["3600"]設定の検証
Pod が起動した後、インスタンスメタデータサービスから STS 認証情報を正常に取得できることを確認します。
Pod 内部から以下のコマンドを実行します。${your_ram_role_name} は、ご利用の RAM ロール名に置き換えてください。
curl http://100.100.100.200/latest/meta-data/ram/security-credentials/${your_ram_role_name}たとえば、ロール名が ECIRamRoleTest の場合:
curl http://100.100.100.200/latest/meta-data/ram/security-credentials/ECIRamRoleTest成功時の応答例は以下のとおりです。
{
"AccessKeyId": "STS.******",
"AccessKeySecret": "******",
"Expiration": "2023-06-22T19:13:58Z",
"SecurityToken": "******",
"LastUpdated": "2023-06-22T13:13:58Z",
"Code": "Success"
}応答に Code: Success が含まれる場合、ロールは正しく割り当てられており、認証情報が利用可能です。STS 認証情報は有効期限切れ前に自動的にローテーションされます。
STS 認証情報を使用した Alibaba Cloud サービスへのアクセス
以下の Go のサンプルコードでは、メタデータサービスから STS 認証情報を取得し、Object Storage Service (OSS) バケット内のオブジェクトを一覧表示しています。
このサンプルは、STS 認証情報を利用する際の一般的なパターンを示すものです。本番環境では、業務ロジックに合わせてコードを調整し、対象サービスの SDK ドキュメントを参照してください。認証情報の有効期限が切れる前に OSS クライアントをリフレッシュすることで、アクセス失敗を回避できます。
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", "OSS エンドポイントを指定してください。推奨:内部エンドポイント(例:oss-cn-hangzhou-internal.aliyuncs.com)")
flag.StringVar(&ossBucketName, "bucket", "", "OSS バケット名を指定してください")
}
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("OSS エンドポイントを指定してください(例:oss-cn-hangzhou-internal.aliyuncs.com)")
}
if ossBucketName == "" {
log.Fatal("OSS バケット名を指定してください")
}
// メタデータサービスから RAM ロール名を取得します。
output, err := exec.Command("curl", securityCredUrl).Output()
if err != nil {
log.Fatalf("メタデータサービスから RAM ロール名を取得できませんでした:%s", err)
}
// ロールに対する STS 認証情報を取得します。
output, err = exec.Command("curl", securityCredUrl+string(output)).Output()
if err != nil {
log.Fatalf("メタデータサービスからセキュリティ認証情報を取得できませんでした:%s", err)
}
authServiceIdentity := new(AssumedRoleUserCredentialsWithServiceIdentity)
if err := json.Unmarshal(output, authServiceIdentity); err != nil {
log.Fatalf("セキュリティ認証情報のデシリアライズに失敗しました:%s", err)
}
// STS 認証情報を使用して OSS クライアントを作成します。
// 本番環境では、認証情報の有効期限が切れる前にクライアントをリフレッシュし、継続的なアクセスを維持してください。
ossClient, err := oss.New(ossEndpoint, authServiceIdentity.AccessKeyId,
authServiceIdentity.AccessKeySecret, oss.SecurityToken(authServiceIdentity.SecurityToken))
if err != nil {
log.Fatalf("OSS クライアントの作成に失敗しました:%s", err)
}
// バケットへの参照を取得します。
bucket, err := ossClient.Bucket(ossBucketName)
if err != nil {
log.Fatalf("バケット %q の取得に失敗しました:%s", ossBucketName, err)
}
// バケット内のすべてのオブジェクトを一覧表示します。デフォルトでは、1 回のリクエストで最大 100 個のオブジェクトが返されます。
marker := ""
for {
lsRes, err := bucket.ListObjects(oss.Marker(marker))
if err != nil {
log.Fatalf("バケット %q 内のオブジェクトの一覧表示に失敗しました:%s", ossBucketName, err)
}
for _, object := range lsRes.Objects {
log.Println("オブジェクト:", object.Key)
}
if lsRes.IsTruncated {
marker = lsRes.NextMarker
} else {
break
}
}
}次のステップ
RAM ロールの概要 — RAM ロールと STS の連携動作について学ぶ
RAM ロールに権限を付与する — ロールがアクセスできるサービスを調整する