本文介紹行動裝置 App如何使用RAM角色的臨時安全性權杖(STS Token)訪問阿里雲資源。
背景資訊
企業A開發了一款行動裝置 App(App),併購買了Object Storage Service服務。App需要直連OSS上傳或下載資料,但是App運行在使用者自己的行動裝置上,這些裝置不受企業A的控制。
企業A有如下要求:
直傳資料:企業A不希望所有App都通過企業的服務端應用伺服器(Application Server)來進行資料中轉,而希望能夠直連OSS上傳或下載資料。
安全管控:企業A不希望將存取金鑰(AccessKey)儲存到行動裝置中,因為行動裝置是歸屬於使用者控制,屬於不可信的運行環境。
風險控制:企業A希望將風險控制到最小,每個App直連OSS時都必須擁有最小的存取權限且訪問時效需要很短。
解決方案
當行動裝置 App(App)直連OSS上傳或下載資料時,App需要嚮應用伺服器申請訪問憑證。應用伺服器以RAM使用者身份扮演RAM角色,調用STS API AssumeRole介面擷取臨時安全性權杖,並將臨時安全性權杖傳遞給App,App使用臨時安全性權杖訪問OSS。
App嚮應用伺服器申請訪問憑證。
使用阿里雲帳號A建立一個RAM角色,並為RAM角色授予合適的許可權。
具體操作,請參見建立RAM角色並授權。
使用阿里雲帳號A為應用伺服器建立一個RAM使用者,並允許應用伺服器以RAM使用者身份扮演該RAM角色。
具體操作,請參見建立RAM使用者並允許扮演RAM角色。
應用伺服器通過調用STS的AssumeRole介面擷取RAM角色的臨時安全性權杖。
具體操作,請參見應用伺服器擷取臨時安全性權杖。
應用伺服器可以進一步限制臨時安全性權杖的許可權,以更精細地控制每個App的許可權。
具體操作,請參見限制臨時安全性權杖的許可權。
當App需要直連OSS上傳或下載資料時,可以使用臨時安全性權杖訪問OSS進行資料直傳。
具體操作,請參見App使用臨時安全性權杖並訪問OSS。
建立RAM角色並授權
假設阿里雲帳號A的帳號ID為123456789012****
。
使用阿里雲帳號A建立可信實體為雲帳號的RAM角色
oss-objectmanager
。說明建立RAM角色時選擇當前雲帳號作為信任主體,即只允許阿里雲帳號A下的RAM使用者來扮演該RAM角色。
具體操作,請參見建立可信實體為阿里雲帳號的RAM角色。
RAM角色建立成功後,在角色基本資料頁面可以查看到該RAM角色的ARN和信任策略。
RAM角色的ARN為
acs:ram::123456789012****:role/oss-objectmanager
。RAM角色的信任策略如下。
說明以下策略表示只允許阿里雲帳號A下的RAM使用者來扮演RAM角色。
{ "Statement": [ { "Action": "sts:AssumeRole", "Effect": "Allow", "Principal": { "RAM": [ "acs:ram::123456789012****:root" ] } } ], "Version": "1" }
為RAM角色授權。為RAM角色
oss-objectmanager
授予OSS的系統管理權限AliyunOSSFullAccess
。具體操作,請參見為RAM角色授權。
建立RAM使用者並允許扮演RAM角色
應用伺服器擷取臨時安全性權杖
應用伺服器使用RAM使用者的存取金鑰(AccessKey)調用STS的 AssumeRole介面。
說明使用阿里雲CLI前需要在應用伺服器中安裝CLI工具,並使用RAM使用者的AccessKey配置相應憑證。具體操作,請參見STS CLI參考。
當前CLI樣本中未指定
Policy
參數,因此返回的臨時安全性權杖將擁有RAM角色oss-objectmanager
的所有許可權。您也可以額外限制臨時安全性權杖的許可權,更多資訊,請參見限制臨時安全性權杖的許可權。
使用阿里雲CLI調用AssumeRole的樣本如下:
aliyun sts AssumeRole --RoleArn 'acs:ram::123456789012****:role/oss-objectmanager' --RoleSessionName 'client-001'
STS服務將臨時安全性權杖返回給應用伺服器。返回的臨時安全性權杖中包含
AccessKeyId
、AccessKeySecret
和SecurityToken
。返回樣本如下:
{ "AssumedRoleUser": { "AssumedRoleId": "391578752573****:client-001", "Arn": "acs:ram::123456789012****:role/oss-objectmanager/client-001" }, "Credentials": { "AccessKeySecret": "yourAccessKeySecret", "SecurityToken": "yourSecurityToken", "Expiration": "2016-01-13T15:02:37Z", "AccessKeyId": "yourAccessKeyId" }, "RequestId": "E1779AAB-E7AF-47D6-A9A4-53128708B6CE" }
說明SecurityToken
到期時間較短。如果需要一個較長的到期時間,應用伺服器需要重新頒發臨時安全性權杖,例如:每隔1800秒頒發一次。
限制臨時安全性權杖的許可權
您可以使用Policy
參數來根據使用者或裝置限制不同臨時安全性權杖的許可權,避免越權風險。
以下樣本表示:只允許下載sample-bucket/2015/01/01/*.jpg
。
請求樣本
aliyun sts AssumeRole --RoleArn 'acs:ram::123456789012****:role/oss-objectmanager' --RoleSessionName 'client-002' --Policy '{"Version":"1", "Statement": [{"Effect":"Allow", "Action":"oss:GetObject", "Resource":"acs:oss:*:*:sample-bucket/2015/01/01/*.jpg"}]}'
說明臨時安全性權杖到期時間預設值為3600秒,通過
DurationSeconds
參數可以設定到期時間。更多資訊,請參見AssumeRole - 擷取扮演角色的臨時身份憑證。返回樣本
{ "AssumedRoleUser": { "AssumedRoleId": "391578752573****:client-002", "Arn": "acs:ram::123456789012****:role/oss-objectmanager/client-002" }, "Credentials": { "AccessKeySecret": "yourAccessKeySecret", "SecurityToken": "yourSecurityToken", "Expiration": "2016-01-13T15:03:39Z", "AccessKeyId": "yourAccessKeyId" }, "RequestId": "98835D9B-86E5-4BB5-A6DF-9D3156ABA567" }
App使用臨時安全性權杖訪問OSS
應用伺服器將臨時安全性權杖傳遞給App。
App使用臨時安全性權杖訪問OSS。
本樣本為您示範如何在Android應用中整合阿里雲OSS Android SDK,並通過臨時安全性權杖訪問OSS,實現將遠程檔案下載至本地裝置的功能。範例程式碼如下:
// yourEndpoint填寫Bucket所在地區對應的Endpoint。以華東1(杭州)為例,Endpoint填寫為https://oss-cn-hangzhou.aliyuncs.com。 String endpoint = "yourEndpoint"; // yourRegion填寫Bucket所在地區。以華東1(杭州)為例,region填寫為cn-hangzhou。 String region = "yourRegion"; // 從STS服務擷取的臨時存取金鑰(AccessKeyID和AccessKeySecret)。 String accessKeyId = "yourAccessKeyId"; String accessKeySecret = "yourAccessKeySecret"; // 從STS服務擷取的臨時安全性權杖(SecurityToken)。 String securityToken = "yourSecurityToken"; OSSCredentialProvider credentialProvider = new OSSStsTokenCredentialProvider(accessKeyId, accessKeySecret, securityToken); ClientConfiguration config = new ClientConfiguration(); config.setSignVersion(SignVersion.V4); // 建立OSSClient執行個體。 OSSClient oss = new OSSClient(getApplicationContext(), endpoint, credentialProvider); oss.setRegion(region); // 構造下載檔案請求。 GetObjectRequest get = new GetObjectRequest("sample-bucket", "2015/01/01/grass.jpg"); OSSAsyncTask task = oss.asyncGetObject(get, new OSSCompletedCallback<GetObjectRequest, GetObjectResult>() { @Override public void onSuccess(GetObjectRequest request, GetObjectResult result) { // 請求成功。 Log.d("asyncGetObject", "DownloadSuccess"); Log.d("Content-Length", "" + result.getContentLength()); try (InputStream inputStream = result.getObjectContent()) { byte[] buffer = new byte[2048]; int len; while ((len = inputStream.read(buffer)) != -1) { // 處理資料 } } catch (IOException e) { e.printStackTrace(); } } @Override // GetObject請求成功,返回GetObjectResult。GetObjectResult包含一個輸入資料流的執行個體。您需要自行處理返回的輸入資料流。 public void onFailure(GetObjectRequest request, ClientException clientExcepion, ServiceException serviceException) { // 請求異常。 if (clientExcepion != null) { // 本地異常,如網路異常等。 clientExcepion.printStackTrace(); } if (serviceException != null) { // 服務異常。 Log.e("ErrorCode", serviceException.getErrorCode()); Log.e("RequestId", serviceException.getRequestId()); Log.e("HostId", serviceException.getHostId()); Log.e("RawMessage", serviceException.getRawMessage()); } } }); // 取消任務。 // task.cancel(); // 等待任務完成。 // task.waitUntilFinished();