This topic describes a security pattern that allows a mobile app to use a temporary STS token obtained for a RAM role to access Alibaba Cloud resources directly.
Background
In this scenario, an enterprise develops a mobile app that must upload and download data directly to and from Object Storage Service (OSS). The app runs on end-user mobile devices, which are considered untrusted environments.
The solution must meet the following requirements:
Direct data transfer: To reduce latency and server load, the mobile app must communicate directly with OSS instead of proxying traffic through an application server.
Secure credential management: To mitigate security risks, long-term credentials, such as access keys, must not be embedded in the mobile app.
Risk control: To follow the principle of least privilege, each mobile app must be granted only the minimum permissions necessary to perform its tasks, and only for a limited time.
Solution
When a mobile app (App) connects directly to OSS to upload or download data, it requests credentials from an application server. The application server, acting as a RAM user, assumes a RAM role, calls the STS API AssumeRole operation to obtain an STS token, and passes the STS token to the app. The app uses the STS token to access OSS.

The app requests credentials from the application server.
Use Alibaba Cloud account A to create a RAM role and grant appropriate permissions to the role.
For more information, see Create a RAM role and grant permissions.
Use Alibaba Cloud Account A to create a RAM user for the application server, and allow the application server to assume the RAM role as the RAM user.
For more information, see Create a RAM user and allow it to assume a RAM role.
The application server calls the STS AssumeRole operation to obtain an STS token for the RAM role.
For more information, see Obtain an STS token on an application server.
An application server can further restrict the permissions of an STS token, providing more granular control over the permissions of each App.
For more information, see Limiting the permissions of an STS token.
When an app needs to directly connect to OSS to upload or download data, you can use an STS token to access OSS for direct data transfer.
For more information, see Use an STS token for an app to access OSS.
Create a RAM role and grant permissions
Assume that the ID of the cloud account is 123456789012****.
Use Alibaba Cloud account A to create a RAM role named
oss-objectmanagerwith Cloud Account as the principal.NoteWhen you create the RAM role, select Current Account as the trusted entity. This sets the role's trust policy to allow only principals within the same cloud account to assume the role.
For more information, see Create a RAM role for a trusted Alibaba Cloud account.
After the RAM role is created, you can view its ARN and trust policy on the role details page.
The ARN of the RAM role is
acs:ram::123456789012****:role/oss-objectmanager.The trust policy of the RAM role is as follows.
NoteThis policy specifies that only RAM users under Alibaba Cloud account A can assume the RAM role.
{ "Statement": [ { "Action": "sts:AssumeRole", "Effect": "Allow", "Principal": { "RAM": [ "acs:ram::123456789012****:root" ] } } ], "Version": "1" }
Grant permissions to the RAM role. For the RAM role
oss-objectmanager, grant the management permission for OSSAliyunOSSFullAccess.For more information, see Grant permissions to a RAM role.
Create a RAM user and allow role assumption
Use Alibaba Cloud Account A to create a RAM user named
appserverfor the application server.For more information, see Create a RAM user.
Grant the
AliyunSTSAssumeRoleAccesspermission to the created RAM user. This allows the RAM user to assume a RAM role.For more information, see Grant permissions to a RAM user.
Obtain an STS token
The application server uses a RAM user's AccessKey to call the STS AssumeRole API.
NoteBefore you use Alibaba Cloud CLI, you must install it on your application server and configure it with the RAM user's credentials. For more information, see STS CLI reference.
This example does not specify the
Policyparameter. Therefore, the returned STS token has all the permissions of theoss-objectmanagerRAM role. You can also further restrict the permissions of the STS token. For more information, see Limit the permissions of an STS token.
The following is an example of calling AssumeRole by using the Alibaba Cloud CLI:
aliyun sts AssumeRole --RoleArn 'acs:ram::123456789012****:role/oss-objectmanager' --RoleSessionName 'client-001'The STS service returns an STS token to the application server. The returned STS token contains
AccessKeyId,AccessKeySecret, andSecurityToken.The following code provides a sample response:
{ "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" }NoteThe
SecurityTokenexpires after a specified period. If a mobile app requires access beyond the token's lifetime, it must request a new STS token from the application server before the current one expires.
Limit the permissions of an STS token
When you call AssumeRole, you can include the Policy parameter to pass an inline policy. This policy restricts the permissions of the returned STS token. The resulting permissions are the intersection of the role's permission policy and the inline policy.
The following example grants permission to download only the objects that match the prefix sample-bucket/2015/01/01/*.jpg.
Sample request
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"}]}'NoteBy default, an STS token is valid for 3,600 seconds. You can use the
DurationSecondsparameter to specify a different expiration time. For more information, see AssumeRole.Sample response
{ "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" }
Use an STS token to access OSS
The application server passes the STS token to the App.
The app uses an STS token to access OSS.
This example shows how to integrate the OSS SDK for Android into an Android app and use an STS token to download an object from OSS.
// yourEndpoint: Your bucket's region endpoint. For example, for the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. String endpoint = "yourEndpoint"; // yourRegion: Your bucket's region ID. For example, for the China (Hangzhou) region, set the region ID to cn-hangzhou. String region = "yourRegion"; // The temporary access key ID and access key secret obtained from STS. String accessKeyId = "yourAccessKeyId"; String accessKeySecret = "yourAccessKeySecret"; // The security token obtained from STS. String securityToken = "yourSecurityToken"; OSSCredentialProvider credentialProvider = new OSSStsTokenCredentialProvider(accessKeyId, accessKeySecret, securityToken); ClientConfiguration config = new ClientConfiguration(); config.setSignVersion(SignVersion.V4); // Create an OSSClient instance. OSSClient oss = new OSSClient(getApplicationContext(), endpoint, credentialProvider); oss.setRegion(region); // Construct a request to download the object. GetObjectRequest get = new GetObjectRequest("sample-bucket", "2015/01/01/grass.jpg"); OSSAsyncTask task = oss.asyncGetObject(get, new OSSCompletedCallback<GetObjectRequest, GetObjectResult>() { @Override // This callback is invoked when the GetObject request is successful. // The GetObjectResult object contains an input stream that you must process. 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) { // Process the data that is read from the stream. } } catch (IOException e) { e.printStackTrace(); } } @Override // This callback is invoked when the GetObject request fails. Handle the exception. public void onFailure(GetObjectRequest request, ClientException clientExcepion, ServiceException serviceException) { if (clientExcepion != null) { // Client-side exception, such as a network error. clientExcepion.printStackTrace(); } if (serviceException != null) { // Server-side exception. Log.e("ErrorCode", serviceException.getErrorCode()); Log.e("RequestId", serviceException.getRequestId()); Log.e("HostId", serviceException.getHostId()); Log.e("RawMessage", serviceException.getRawMessage()); } } }); // Cancel the task. // task.cancel(); // Wait for the task to complete. // task.waitUntilFinished();