全部產品
Search
文件中心

Simple Log Service:通過STS實現跨帳號訪問Log Service資源

更新時間:Dec 17, 2024

阿里雲帳號(主帳號)可以通過建立並授權RAM角色的方式授權其他雲帳號一定的資源許可權,其他阿里雲帳號扮演該角色,並為其名下的RAM使用者授予AssumeRole許可權之後,其他阿里雲帳號或RAM使用者可以通過訪問STS介面擷取臨時AK和Token令牌,調用Log ServiceAPI介面。

方案概覽

假設企業A擁有阿里雲帳號A,企業B擁有阿里雲帳號B。出於業務隔離或專案外包等需求,企業A希望將部分Log Service業務授權給企業B維護。需求如下:

  • 阿里雲帳號B擁有向阿里雲帳號A的Log Service中寫入資料和使用消費組的許可權。

  • 阿里雲帳號B的指定RAM使用者也擁有Log Service的寫入和消費組許可權。

  • 阿里雲帳號B可擷取STS臨時憑證,訪問Log ServiceAPI介面。具體操作,請參見什麼是STS

基於以上需求,您可按照以下步驟配置。

步驟一:阿里雲帳號A為阿里雲帳號B建立RAM角色並授權

步驟二:阿里雲帳號B建立RAM使用者user-b並授權

步驟三:RAM使用者user-b擷取STS臨時憑證訪問Log Service

步驟一:阿里雲帳號A為阿里雲帳號B建立RAM角色並授權

在阿里雲帳號A建立RAM角色,指定阿里雲帳號B扮演該角色並為角色賦予Log Service的指定許可權。

可以通過RAM控制台建立RAM角色。具體操作,請參見建立RAM使用者及授權。您也可以通過RAM的API CreateRole建立RAM角色。具體操作,請參見CreateRole。以下以控制台建立為例進行詳細步驟說明。

  1. 使用阿里雲帳號A登入RAM控制台

  2. 建立RAM角色,並指定阿里雲帳號B扮演該角色。

    1. 在左側導覽列,選擇身份管理 > 角色

    2. 在角色頁面,單擊建立角色

    3. 建立角色面板,選擇可信實體類型為阿里雲帳號,單擊下一步

    4. 輸入角色名稱備忘選擇信任的雲帳號其他雲帳號,填寫<阿里雲帳號B的帳號ID>,單擊完成

      說明

      將滑鼠移至上方在控制台右上方頭像的位置,即可查詢主帳號ID。

      以上步驟中建立的RAM角色詳情如下。

      {
        "Statement": [
          {
            "Action": "sts:AssumeRole",
            "Effect": "Allow",
            "Principal": {
              "RAM": [
                "acs:ram::<阿里雲帳號B的帳號ID>:root"
              ]
            }
          }
        ],
        "Version": "1"
      }
  3. 建立一個自訂權限原則,其中在指令碼編輯頁簽,請使用以下指令碼替換配置框中的原有內容。具體操作,請參見通過指令碼編輯模式建立自訂權限原則

    如果僅需要寫資料,授權指令碼如下所示:

    {
      "Version": "1",
      "Statement": [
        {
          "Action": "log:PostLogStoreLogs",
          "Resource": "*",
          "Effect": "Allow"
        }
      ]
    }

    如果需要通過協同消費庫擷取資料,授權指令碼如下所示:

    {
      "Version": "1",
      "Statement": [
        {
          "Action": [
             "log:GetCursorOrData",
             "log:CreateConsumerGroup",
             "log:ListConsumerGroup",
             "log:ConsumerGroupUpdateCheckPoint",
             "log:ConsumerGroupHeartBeat",
             "log:GetConsumerGroupCheckPoint",
             "log:UpdateConsumerGroup"
          ],
          "Resource": "*",
          "Effect": "Allow"
        }
      ]
    }
    重要

    以上兩類資源都是授權指定使用者的所有Project和Logstore,如果您需要授權指定Project和Logstore,請參考如下內容:

    • 授權指定Project:acs:log::{projectOwnerAliUid}:project/

    • 授權指定Logstore:acs:log::{projectOwnerAliUid}:project/{projectName}/logstore/{logstoreName}/

    完整的資源說明請參見資源清單

  4. 為RAM角色添加建立的自訂許可權。具體操作,請參見為RAM角色授權

步驟二:阿里雲帳號B建立RAM使用者user-b並授權

在阿里雲帳號B建立RAM使用者user-b,並為其授予AliyunSTSAssumeRoleAccess(調用STS AssumeRole介面)的系統策略。

  1. 使用阿里雲帳號B登入RAM控制台

  2. 建立一個RAM使用者user-b訪問方式選擇控制台訪問使用永久AccessKey訪問具體操作,請參見建立RAM使用者

    重要
    • RAM使用者的AccessKey Secret只在建立時顯示,不支援查看,請妥善保管。

    • 存取金鑰(AccessKey)是一種長期有效程式訪問憑證。AccessKey泄露會威脅該帳號下所有資源的安全。建議優先採用STS Token臨時憑證方案,降低憑證泄露的風險。更多資訊,請參見使用訪問憑據訪問阿里雲OpenAPI最佳實務

  3. 為RAM使用者添加AliyunSTSAssumeRoleAccess許可權,使其可以通過扮演RAM角色來擷取臨時身份憑證。具體操作,請參見為RAM使用者授權

步驟三:RAM使用者user-b擷取STS臨時憑證訪問Log Service

  1. 調用STS AssumeRole介面擷取臨時AK和Token。更多資訊,請參見AssumeRole

    您可以選擇以下方式調用該介面:

    通過STS SDK調用。更多資訊,請參見STS SDK概覽

  2. 調用Log Service介面,關於Log ServiceSDK請參見SDK參考

範例程式碼

基於Java SDK,以RAM帳號user-b通過STS向阿里雲帳號A的Project寫入資料為例。範例程式碼如下所示:

package com.aliyun.openservices.log.sample;

import java.util.Date;
import java.util.Vector;

import com.aliyun.openservices.log.Client;
import com.aliyun.openservices.log.common.LogItem;
import com.aliyun.openservices.log.exception.LogException;
import com.aliyun.openservices.log.request.PutLogsRequest;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.http.ProtocolType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.aliyuncs.sts.model.v20150401.AssumeRoleRequest;
import com.aliyuncs.sts.model.v20150401.AssumeRoleResponse;

public class StsSample {
	  // now sts only support "cn-hangzhou"
	  public static final String REGION_CN_HANGZHOU = "cn-hangzhou";
	  // current sts api version
	  public static final String STS_API_VERSION = "2015-04-01";
	  static AssumeRoleResponse assumeRole(String accessKeyId, String accessKeySecret,
	                                       String roleArn, String roleSessionName, String policy,
	                                       ProtocolType protocolType) throws ClientException {
	    try {
	      // construct Aliyun Acs Client to ivoke OpenAPI
	      IClientProfile profile = DefaultProfile.getProfile(REGION_CN_HANGZHOU, accessKeyId, accessKeySecret);
	      DefaultAcsClient client = new DefaultAcsClient(profile);
	      // create AssumeRoleRequest object
	      final AssumeRoleRequest request = new AssumeRoleRequest();
	      request.setVersion(STS_API_VERSION);
	      request.setMethod(MethodType.POST);
	      request.setProtocol(protocolType);
	      request.setRoleArn(roleArn);
	      request.setRoleSessionName(roleSessionName);
	      request.setPolicy(policy);
	      // send request
	      final AssumeRoleResponse response = client.getAcsResponse(request);
	      return response;
	    } catch (ClientException e) {
	      throw e;
	    }
	  }
	  public static void main(String[] args) {
	    // only RAM user(sub account)can invoke AssumeRole interface
	    // Aliyun root account's AccessKeys can't invoke AssumeRole
	    // please create sub account in RAM web console(https://ram.console.aliyun.com), and create AK for this sub account
	    String accessKeyId = "<subaccountaccesskey>";
	    String accessKeySecret = "<subaccountaccesssecret>";
	    // AssumeRole API parameter: RoleArn, RoleSessionName, Policy, and DurationSeconds
	    // RoleArn can retrieve in RAM web console
	    // https://ram.console.aliyun.com/#/role/detail/< specifid rolename>/info
	    String roleArn = "<rolearn found in web console>";
	    // RoleSessionName is  temporary Token(mainly used for audit)
	    String roleSessionName = "bluemix-001";
	    String policy = "{\n" +
	            "    \"Version\": \"1\", \n" +
	            "    \"Statement\": [\n" +
	            "        {\n" +
	            "            \"Action\": \"log:PostLogStoreLogs\",\n" +
	            "            \"Resource\": \"*\",\n" +
	            "            \"Effect\": \"Allow\"\n" +
	            "        }\n" +
	            "    ]\n" +
	            "}";
	    System.out.println(policy);
	    // only support HTTPS here
	    ProtocolType protocolType = ProtocolType.HTTPS;
	    AssumeRoleResponse response = new AssumeRoleResponse();
	    try {
	      response = assumeRole(accessKeyId, accessKeySecret,
	              roleArn, roleSessionName, policy, protocolType);
	      System.out.println("Expiration: " + response.getCredentials().getExpiration());
	      System.out.println("Access Key Id: " + response.getCredentials().getAccessKeyId());
	      System.out.println("Access Key Secret: " + response.getCredentials().getAccessKeySecret());
	      System.out.println("Security Token: " + response.getCredentials().getSecurityToken());
	    } catch (ClientException e) {
	      System.out.println("Failed to get a token.");
	      System.out.println("Error code: " + e.getErrCode());
	      System.out.println("Error message: " + e.getErrMsg());
	    }
	    
	    // log service parameter
	    // log service endpoint doc: https://help.aliyun.com/zh/sls/developer-reference/api-sls-2020-12-30-endpoint
	    String logServiceEndpoint = "cn-hangzhou.log.aliyuncs.com";
	    // means project region must be cn-hangzhou
	    String project = "<log service project name>";
	    String logstore = "<log service logstore name>";
	    
	    // construct log service client object
	    Client client = new Client(logServiceEndpoint, 
	    		response.getCredentials().getAccessKeyId(), 
	    		response.getCredentials().getAccessKeySecret());
	    // notice: the AK & Security Token will be expire in 1hour
	    // so you must invoke asumeRole interface when expired
	    client.SetSecurityToken(response.getCredentials().getSecurityToken());
	    Vector<LogItem> logGroup = new Vector<LogItem>();
	    LogItem logItem = new LogItem((int) (new Date().getTime() / 1000));
	    logItem.PushBack("StsSample", "Send Data");
	    logGroup.add(logItem);
	    
	    PutLogsRequest req2 = new PutLogsRequest(project, logstore, "", "", logGroup);
	    try {
	    	client.PutLogs(req2);
	    } catch (LogException e) {
			System.out.println("Failed to send data.");
			System.out.println("Error code: " + e.GetErrorCode());
			System.out.println("Error message: " + e.GetErrorMessage());
	    }
	  }
}