このトピックでは、モバイルアプリが RAM ロール用に取得した一時的な STS トークンを使用して、Alibaba Cloud リソースに直接アクセスできるセキュリティパターンについて説明します。
背景情報
このシナリオでは、企業が開発したモバイルアプリが Object Storage Service (OSS) との間でデータを直接アップロードおよびダウンロードする必要があります。このアプリはエンドユーザーのモバイルデバイス上で動作し、その環境は信頼できないものと見なされます。
このソリューションは、以下の要件を満たす必要があります。
直接データ転送:遅延とサーバー負荷を軽減するため、モバイルアプリはアプリケーションサーバを経由せずに OSS と直接通信する必要があります。
認証情報の安全な管理:セキュリティリスクを軽減するため、AccessKey などの長期的な認証情報をモバイルアプリに埋め込んではいけません。
リスク制御:最小権限の原則に従い、各モバイルアプリにはタスクを実行するために必要な最小限の権限のみを、限定された期間だけ付与する必要があります。
ソリューション
モバイルアプリ(App)が OSS に直接接続してデータをアップロードまたはダウンロードする際、アプリはアプリケーションサーバから認証情報をリクエストします。アプリケーションサーバは RAM ユーザーとして動作し、RAM ロールを引き受け、STS API の AssumeRole 操作を呼び出して STS トークンを取得し、その STS トークンをアプリに渡します。アプリはこの STS トークンを使用して OSS にアクセスします。

アプリがアプリケーションサーバから認証情報をリクエストします。
Alibaba Cloud アカウント A を使用して RAM ロールを作成し、適切な権限をロールに付与します。
詳細については、「RAM ロールの作成と権限の付与」をご参照ください。
Alibaba Cloud アカウント A を使用してアプリケーションサーバ用の RAM ユーザーを作成し、アプリケーションサーバが RAM ユーザーとして RAM ロールを引き受けられるようにします。
詳細については、「RAM ユーザーの作成と RAM ロールの引き受け許可」をご参照ください。
アプリケーションサーバが STS の AssumeRole 操作を呼び出し、RAM ロール用の STS トークンを取得します。
詳細については、「アプリケーションサーバでの STS トークンの取得」をご参照ください。
アプリケーションサーバは、STS トークンの権限をさらに制限できます。これにより、各アプリの権限をより細かく制御できます。
詳細については、「STS トークンの権限の制限」をご参照ください。
アプリが OSS に直接接続してデータをアップロードまたはダウンロードする必要がある場合、STS トークンを使用して OSS にアクセスし、直接データ転送を実現できます。
詳細については、「アプリでの OSS へのアクセスに STS トークンを使用する」をご参照ください。
RAM ロールの作成と権限の付与
クラウドアカウントの ID は 123456789012**** であると仮定します。
Alibaba Cloud アカウント A を使用して、プリンシパルとして [クラウドアカウント] を指定し、
oss-objectmanagerという名前の RAM ロールを作成します。説明RAM ロールを作成する際は、信頼できるエンティティとして 現在のアカウント を選択してください。これにより、ロールの信頼ポリシーが同じクラウドアカウント内のプリンシパルのみがロールを引き受けられるように設定されます。
詳細については、「信頼できる Alibaba Cloud アカウント向けの RAM ロールの作成」をご参照ください。
RAM ロールの作成後、ロール詳細ページで ARN および信頼ポリシーを確認できます。
RAM ロールの ARN は
acs:ram::123456789012****:role/oss-objectmanagerです。RAM ロールの信頼ポリシーは次のとおりです。
説明このポリシーは、Alibaba Cloud アカウント A 下の RAM ユーザーのみが RAM ロールを引き受けられることを指定しています。
{ "Statement": [ { "Action": "sts:AssumeRole", "Effect": "Allow", "Principal": { "RAM": [ "acs:ram::123456789012****:root" ] } } ], "Version": "1" }
RAM ロールに権限を付与します。
oss-objectmanagerという RAM ロールに対して、OSS の管理権限AliyunOSSFullAccessを付与します。詳細については、「RAM ロールへの権限の付与」をご参照ください。
RAM ユーザーの作成とロールの引き受け許可
Alibaba Cloud アカウント A を使用して、アプリケーションサーバ用に
appserverという名前の RAM ユーザーを作成します。詳細については、「RAM ユーザーの作成」をご参照ください。
作成した RAM ユーザーに
AliyunSTSAssumeRoleAccess権限を付与します。これにより、RAM ユーザーが RAM ロールを引き受けられるようになります。詳細については、「RAM ユーザーへの権限の付与」をご参照ください。
STS トークンの取得
アプリケーションサーバが RAM ユーザーの AccessKey を使用して、STS AssumeRole API を呼び出します。
説明Alibaba Cloud CLI を使用する前に、アプリケーションサーバに CLI をインストールし、RAM ユーザーの認証情報を設定する必要があります。詳細については、「STS CLI リファレンス」をご参照ください。
この例では
Policyパラメーターを指定していません。そのため、返される STS トークンはoss-objectmanagerRAM ロールのすべての権限を持ちます。STS トークンの権限をさらに制限することも可能です。詳細については、「STS トークンの権限の制限」をご参照ください。
次に、Alibaba Cloud CLI を使用して AssumeRole を呼び出す例を示します。
aliyun sts AssumeRole --RoleArn 'acs:ram::123456789012****:role/oss-objectmanager' --RoleSessionName 'client-001'STS サービスが STS トークンをアプリケーションサーバに返します。返された 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は指定された期間後に有効期限切れになります。モバイルアプリがトークンの有効期限を超えてアクセスを必要とする場合は、現在のトークンの有効期限が切れる前にアプリケーションサーバから新しい STS トークンをリクエストする必要があります。
STS トークンの権限の制限
AssumeRole を呼び出す際に、Policy パラメーターを含めてインラインポリシーを渡すことができます。このポリシーにより、返される STS トークンの権限が制限されます。結果として得られる権限は、ロールの権限ポリシーとインラインポリシーの共通部分(交差)となります。
次の例では、プレフィックス 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"}]}'説明デフォルトでは、STS トークンの有効期間は 3,600 秒です。
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" }
STS トークンを使用して OSS にアクセスする
アプリケーションサーバが STS トークンをアプリに渡します。
アプリが STS トークンを使用して OSS にアクセスします。
この例では、Android アプリに OSS SDK for Android を統合し、STS トークンを使用して OSS からオブジェクトをダウンロードする方法を示します。
// yourEndpoint: バケットのリージョンエンドポイント。たとえば、中国 (杭州) リージョンの場合は、エンドポイントを https://oss-cn-hangzhou.aliyuncs.com に設定します。 String endpoint = "yourEndpoint"; // yourRegion: バケットのリージョン ID。たとえば、中国 (杭州) リージョンの場合は、リージョン ID を cn-hangzhou に設定します。 String region = "yourRegion"; // STS から取得した一時的な Access Key ID および Access Key Secret。 String accessKeyId = "yourAccessKeyId"; String accessKeySecret = "yourAccessKeySecret"; // STS から取得したセキュリティトークン。 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 // GetObject リクエストが成功したときに呼び出されるコールバック。 // GetObjectResult オブジェクトには処理が必要な入力ストリームが含まれます。 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 リクエストが失敗したときに呼び出されるコールバック。例外を処理します。 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();