公司在接待外部客戶進行參觀活動時,常見的方案是給訪客一張臨時工牌,訪客憑此工牌可在限定時間內,在授權地區內活動。阿里雲提供的RAM角色功能,可以解決類似的雲上營運情境。它允許使用者扮演特定的臨時身份,並執行授權範圍內的管理動作,適用於跨帳號訪問、角色單點登入(SSO)以及臨時授權等情境。
情境介紹
接下來,我們將以常見的跨帳號訪問情境為例,為您完整示範操作流程。假設您的公司營運著一個電子商務網站,網站服務部署在阿里雲的ECS上。日常營運工作由公司的IT部門負責,但有時也需要外部夥伴的協助來解決特定的技術問題或是執行一些特殊的維護任務。為了保證雲上資源的安全性,您不希望直接分享長期有效帳號(阿里雲帳號、RAM使用者)給這些外部夥伴。
使用RAM角色進行跨帳號訪問授權,整體流程如下:
帳號A:您公司的阿里雲帳號(主帳號)。
帳號B:外部夥伴的阿里雲帳號(主帳號)。
帳號A建立RAM角色,並授權允許帳號B扮演。
帳號B建立RAM使用者,並授權其進行角色扮演。
帳號B使用RAM使用者扮演帳號A的RAM角色,完成帳號A相關資源的管理操作。
操作步驟
帳號A建立RAM角色並授權
1. 建立RAM角色
使用帳號A登入RAM控制台,建立一個可信實體類型為阿里雲帳號的RAM角色,在選擇信任的雲帳號處填入帳號B的帳號ID(UID)。更多關於建立RAM角色的資訊,請參見建立可信實體為阿里雲帳號的RAM角色。
2. 為RAM角色授權
建立一個權限原則,允許查看執行個體資訊及通過Workbench登入ECS執行個體,並將權限原則授予給RAM角色。詳細授權操作,請參見建立自訂權限原則。
帳號B建立RAM使用者並授權
1. 建立RAM使用者
使用帳號B登入RAM控制台,建立一個RAM使用者,注意在建立RAM使用者時選擇允許控制台登入,並允許OpenAPI調用訪問。關於如何建立RAM使用者,請參見建立RAM使用者。
2. 為RAM使用者授權
在扮演RAM角色之前,需要為RAM使用者授予扮演RAM角色的許可權。使用帳號B為該RAM使用者授予AliyunSTSAssumeRoleAccess
許可權,以允許該RAM使用者扮演所有RAM角色。有關如何為RAM使用者授權的詳細資料,請參見為RAM使用者授權。
如果希望該RAM使用者僅能扮演指定的RAM角色,具體操作,請參見能否指定RAM使用者具體可以扮演哪個RAM角色。
扮演RAM角色
雲產品控制台扮演角色
程式調用時扮演
您也可以通過程式碼實現對帳號A的資源訪問。大體流程如下:
將帳號B建立RAM使用者時擷取的AccessKey寫入系統內容變數。不同系統的設定方法存在差異,請參考在Linux、macOS和Windows系統配置環境變數
使用帳號B的RAM使用者調用
AssumeRole
介面,傳入帳號A的RAM角色的ARN,換取臨時身份憑證STS Token。使用換取的臨時身份憑證STS Token調用雲端服務提供的API查看帳號A的雲資源。
Java範例程式碼
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>ecs20140526</artifactId>
<version>5.4.4</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>sts20150401</artifactId>
<version>1.1.4</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>credentials-java</artifactId>
<version>0.3.10</version>
</dependency>
import com.aliyun.ecs20140526.models.DescribeInstancesRequest;
import com.aliyun.ecs20140526.models.DescribeInstancesResponse;
import com.aliyun.sts20150401.Client;
import com.aliyun.sts20150401.models.AssumeRoleRequest;
import com.aliyun.sts20150401.models.AssumeRoleResponse;
import com.aliyun.sts20150401.models.AssumeRoleResponseBody;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.models.RuntimeOptions;
import com.google.gson.Gson;
/**
* 通過扮演RAM角色擷取臨時訪問憑證,然後使用這些憑證訪問ECS資源。
*/
public class Sample {
public static void main(String[] args) {
// 僅供樣本參考,務必根據業務實際情況選擇特定region的endpoint
String stsEndpoint = "sts.cn-shanghai.aliyuncs.com";
String ecsEndpoint = "ecs.cn-shanghai.aliyuncs.com";
// 查詢cn-shanghai的ECS執行個體資訊
String regionId = "cn-shanghai";
// 要扮演的RAM角色的ARN。
String ramRoleArn = "acs:ram::14************16:role/cooperativepartnerrole";
// 使用帳號B的RAM使用者扮演帳號A的RAM角色,擷取臨時訪問憑證。
AssumeRoleResponse assumeRoleResponse = playRamRole(stsEndpoint, ramRoleArn);
// 調用雲端服務提供的API查看帳號A的雲資源。
accessResources(assumeRoleResponse, ecsEndpoint, regionId);
}
/**
* 使用臨時訪問憑證訪問雲資源。
*
* @param assumeRoleResponse 包含臨時訪問憑證的響應對象。
*/
private static void accessResources(AssumeRoleResponse assumeRoleResponse, String ecsEndpoint, String regionId) {
try {
// 提取臨時訪問憑證資訊。
AssumeRoleResponseBody.AssumeRoleResponseBodyCredentials assumeRoleResponseBodyCredentials = assumeRoleResponse.body.credentials;
com.aliyun.credentials.models.Config credentialsConfig = new com.aliyun.credentials.models.Config()
.setType("sts") // 憑證類型。
.setAccessKeyId(assumeRoleResponseBodyCredentials.accessKeyId)
.setAccessKeySecret(assumeRoleResponseBodyCredentials.accessKeySecret)
.setSecurityToken(assumeRoleResponseBodyCredentials.securityToken);
com.aliyun.credentials.Client credentialClient = new com.aliyun.credentials.Client(credentialsConfig);
// 建立ECS用戶端。
Config ecsConfig = new Config()
.setEndpoint(ecsEndpoint)
.setCredential(credentialClient);
com.aliyun.ecs20140526.Client ecsClient = new com.aliyun.ecs20140526.Client(ecsConfig);
DescribeInstancesRequest describeInstancesRequest = new DescribeInstancesRequest()
.setRegionId(regionId);
RuntimeOptions runtimeOptions = new RuntimeOptions();
// 調用DescribeInstances介面並獲得響應。
DescribeInstancesResponse response = ecsClient.describeInstancesWithOptions(describeInstancesRequest, runtimeOptions);
// 列印響應結果。
System.out.println(new Gson().toJson(response.body));
} catch (Exception e) {
throw new RuntimeException("AccessResources failed: " + e.getMessage());
}
}
/**
* 扮演RAM角色擷取臨時訪問憑證。
*
* @return 包含臨時訪問憑證的響應對象。
*/
private static AssumeRoleResponse playRamRole(String stsEndpoint, String ramRoleArn) {
try {
// 建立StsClient對象,並調用assumeRole服務擷取STS Token
Config config = new Config()
// System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID")表示從環境變數中擷取AccessKey ID的值
.setAccessKeyId(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"))
// System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")表示從環境變數中擷取AccessKey Secret的值
.setAccessKeySecret(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"));
config.endpoint = stsEndpoint;
Client client = new Client(config);
// 建立AssumeRole請求對象,指定要扮演的RAM角色ARN和角色會話名稱。
AssumeRoleRequest assumeRoleRequest = new AssumeRoleRequest()
.setRoleArn(ramRoleArn)
.setRoleSessionName("CooperativePartner");
RuntimeOptions runtime = new RuntimeOptions();
return client.assumeRoleWithOptions(assumeRoleRequest, runtime);
} catch (Exception e) {
throw new RuntimeException("play RAM role failed: " + e.getMessage());
}
}
}
調用結果:程式返回了帳號A在杭州地區保有的ECS資源清單。
{
"instances":{
"instance":[
{
"creationTime":"2024-10-23T09:12Z",
"expiredTime":"2099-12-31T15:59Z",
"hostName":"iZ********************pZ",
"imageId":"m-uf****************jf",
"instanceChargeType":"PostPaid",
"instanceId":"i-uf****************ap",
"instanceName":"launch-advisor-20241023-c6",
"instanceNetworkType":"vpc",
"instanceType":"ecs.c6.xlarge",
...
// 省略了部分參數的展示
...
"vpcAttributes":{
"natIpAddress":"",
"privateIpAddress":{
"ipAddress":[
"17*.**.**.*15"
]
},
"vSwitchId":"vsw-uf*****************tk",
"vpcId":"vpc-uf*****************kr"
},
"zoneId":"cn-shanghai-b"
}
]
},
"nextToken":"",
"pageNumber":1,
"pageSize":10,
"requestId":"C1468F7E********************7A3A712",
"totalCount":1
}