Elastic Container Instance (ECI) に RAM ロールを割り当てることで、そのインスタンス上で実行されるアプリケーションが、自動的にローテーションされるセキュリティトークンサービス(STS)の認証情報を使用して、他の Alibaba Cloud サービスの API を呼び出せるようになります。この方法では、インスタンス上に AccessKey ペアを保存する必要はありません。
インスタンス RAM ロールを利用する理由
構成ファイル内に AccessKey ペアをハードコードすると、以下の 2 つの問題が発生します:認証情報が漏洩するリスクがあり、権限の更新にはすべてのインスタンスを個別に変更する必要があります。インスタンス RAM ロールは、これらの課題を両方解決します。
ディスク上に認証情報が存在しない。 アプリケーションは、ランタイム時にインスタンスメタデータから短期間有効な STS トークンを取得します。
権限管理の一元化。 インスタンスがアクセス可能なリソースを変更するには、RAM ロールの設定を更新するだけで済み、各インスタンスを個別に変更する必要はありません。
トークンの自動ローテーション。 STS トークンは有効期限が切れると自動的に更新され、万一の漏洩による影響範囲を最小限に抑えます。
前提条件
開始する前に、以下の条件を満たしていることを確認してください。
Alibaba Cloud アカウント、または RAM で
CreateRole、CreatePolicy、AttachPolicyToRoleの各 API を呼び出す権限、および ECI でCreateContainerGroupを呼び出す権限を持つ RAM ユーザー(任意)Elastic Container Instance を RAM ユーザーで作成する場合、その RAM ユーザーは対象のロールに対して
ram:PassRole権限も付与されている必要があります。
仕組み
インスタンス RAM ロールを作成し、信頼ポリシーを設定して ECS がそのロールを偽装できるようにします。
権限ポリシーを作成し、それをロールにアタッチします。
(任意)RAM ユーザーがインスタンスにロールをデリゲートできるように、そのユーザーに権限を付与します。
CreateContainerGroupを使用して、Elastic Container Instance (ECI) にロールを割り当てます。Pod 内からインスタンスメタデータ経由で STS 認証情報を取得し、他の Alibaba Cloud サービスの API 呼び出しに使用します。
ステップ 1:インスタンス RAM ロールの作成
以下のパラメーターを指定して CreateRole を呼び出します。
RoleName:ロールの説明的な名前。本例では
ECIRamRoleTestを使用します。AssumeRolePolicyDocument:ECS がこのロールを偽装できるように許可する信頼ポリシー。
{
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": [
"ecs.aliyuncs.com"
]
}
}
],
"Version": "1"
}信頼できるエンティティは Elastic Container Instance に設定し、信頼できるサービスは Elastic Compute Service (ECS) に設定する必要があります。これは ecs.aliyuncs.com というプリンシパルで表されます。ステップ 2:ロールへの権限ポリシーのアタッチ
2a. カスタムポリシーの作成
以下のパラメーターを指定して CreatePolicy を呼び出します。
PolicyName:
ECIRamRoleTestPolicyPolicyDocument:付与する権限。以下の例では、すべての Object Storage Service (OSS) バケットに対する読み取りアクセスを許可しています。
{
"Statement": [
{
"Action": [
"oss:Get*",
"oss:List*"
],
"Effect": "Allow",
"Resource": "*"
}
],
"Version": "1"
}最小権限の原則に従い、アプリケーションが実際に必要とする権限のみを付与してください。
2b. ポリシーをロールにアタッチ
以下のパラメーターを指定して AttachPolicyToRole を呼び出します。
| パラメーター | 値 |
|---|---|
PolicyName | ECIRamRoleTestPolicy |
PolicyType | Custom |
RoleName | ECIRamRoleTest |
ステップ 3(任意):RAM ユーザーによるロールのデリゲート権限の付与
Elastic Container Instance を Alibaba Cloud アカウントで作成する場合は、このステップはスキップしてください。
RAM ユーザーが Elastic Container Instance を作成・ロールを割り当てる場合、その RAM ユーザーは対象のロールに対して ram:PassRole 権限を付与されている必要があります。この権限がないと、RAM ユーザーはロールをインスタンスにデリゲートできません。
RAM コンソール に、Alibaba Cloud アカウントまたは管理者権限を持つ RAM ユーザーでログインします。
以下のドキュメントを含むカスタムポリシーを作成し、それを RAM ユーザーにアタッチします。詳細については、「RAM ユーザーへの権限付与」をご参照ください。
{
"Statement": [
{
"Effect": "Allow",
"Action": "ram:PassRole",
"Resource": "acs:ram:*:*:role/ECIRamRoleTest"
}
],
"Version": "1"
}ステップ 1 で異なるロール名を使用した場合は、ECIRamRoleTest を実際のロール名に置き換えてください。
ステップ 4:Elastic Container Instance へのロールの割り当て
CreateContainerGroup を呼び出す際に、RamRoleName パラメーターにステップ 1 で作成したロール名を指定します。
Elastic Container Instance 1 台につき、インスタンス RAM ロールは 1 つまでしかサポートされていません。すでにロールが割り当てられている場合、別のロールを割り当てようとするとエラーが返されます。
ステップ 5:STS 認証情報の取得と利用
STS トークンの取得
Pod 内から、インスタンスメタデータのエンドポイントをクエリします。
curl http://100.100.100.200/latest/meta-data/ram/security-credentials/ECIRamRoleTestECIRamRoleTest は、実際のロール名に置き換えてください。応答は以下のようになります。
{
"AccessKeyId": "STS.******",
"AccessKeySecret": "******",
"Expiration": "2023-06-22T19:13:58Z",
"SecurityToken": "******",
"LastUpdated": "2023-06-22T13:13:58Z",
"Code": "Success"
}| フィールド | 説明 |
|---|---|
AccessKeyId | 一時的なアクセスキー ID(プレフィックス STS. 付き) |
AccessKeySecret | 一時的なアクセスキーのシークレット |
SecurityToken | サービス API を呼び出す際に、AccessKeyId および AccessKeySecret とともに必要なセッショントークン |
Expiration | トークンの有効期限(UTC タイムスタンプ)。STS トークンは自動的かつ定期的に更新されます。 |
LastUpdated | トークンが最後にリフレッシュされた時刻(UTC タイムスタンプ) |
Code | Success は、有効な認証情報であることを示します。 |
STS トークンを用いた Alibaba Cloud サービスへのアクセス
以下の Go のサンプルコードでは、インスタンスメタデータから認証情報を取得し、OSS バケット内のオブジェクトを一覧表示します。認証情報はメタデータエンドポイントから読み込まれるため、コード内に静的な AccessKey ペアは含まれません。
このサンプルは、認証情報の取得パターンを示すものです。本番環境では、アプリケーションの要件に合わせてコードを調整し、対象サービスの SDK ドキュメントを参照してください。
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 バケット名が必要です")
}
output, err := exec.Command("curl", securityCredUrl).Output()
if err != nil {
log.Fatalf("メタデータサーバーから RAM ロール名の取得に失敗しました:%s", err)
}
output, err = exec.Command("curl", securityCredUrl+string(output)).Output()
if err != nil {
log.Fatalf("メタデータサーバーから STS 認証情報の取得に失敗しました:%s", err)
}
authServiceIdentity := new(AssumedRoleUserCredentialsWithServiceIdentity)
if err := json.Unmarshal(output, authServiceIdentity); err != nil {
log.Fatalf("STS 認証情報の解析に失敗しました:%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
}
}
}次のステップ
API を使用せずにコンソールから RAM ロールおよびポリシーを管理する場合は、「RAM ロールの概要」をご参照ください。
RAM ユーザーが Elastic Container Instance を作成・ロールを割り当てる権限を制御する場合は、「RAM ユーザーへの権限付与」をご参照ください。