用户操作 OSS 时是需要根据账号的 AccessKeyId 和 AccessKeySecret (后续简称 AK 和 SK )进行权限验证的,这里的 AK 和 SK 包括有多种类型:主账号的 AK 和 SK 、子账号的 AK 和 SK 以及 STS 生成的临时 AK 、 SK 和 Token 。那么他们之间有什么区别呢?具体应该如何配置使用呢?本文将带大家一起认识相关概念。
1. 概念区别
主账号的 AK 和 SK 是主账号对应的权限标识,也就是说主账号的每对 AK和 SK 是拥有账号下的所有权限的,不仅仅可以操作 OSS,还包括 ECS 、 RDS 等其他产品都是可以操作的。因此该对 AK 和 SK 是必须要安全保管的,是不能随便泄露出去的;并且主账号的 AK 和 SK 尽量避免所有账号使用者均知道,建议仅极少数的账号管理者进行控制和知晓。
子账号的 AK 和 SK 是主账号将账号内的部分权限通过赋权的方式提供给子账号,后续子账号即可以使用自己的账号和密码或者 AK 和 SK 操作允许的操作。该子账号的 AK 和 SK 是有永久时效性的,也就是说在主账号没有取消权限之前都是有效的,因此子账号建议提供给公司内部账号的使用者或者开发人员。
STS 生成的临时 AK 、 SK 和 Token 与子账号类似,也是需要通过赋权的方式单独赋权给该 Token 的,但是有一点和子账号的 AK 和 SK 相区别的就是该 Token 是有有效时间的。该 Token 尽可以在有效时间内操作赋予的权限,超过该时间后即需要重新获取新的 Token 才可以正常操作。
2. 获取方法
2.1 主账号的 AK 和 SK
主账号的 AK 和 SK 可以主账号登陆后直接查看到,如图 1 中的截图。主账号可以创建五对 AK 和 SK ,每对 AK 和 SK 都是拥有账号的所有权限的,使用时可直接应用其中的一对操作即可完成。主账号的使用方法最为便捷。
图 1. 主账号 AK 和 SK 示意图
2.2 子账号的 AK 和 SK
子账号的 AK 和 SK 是需要通过访问控制控制台得到的。首先需要创建 RAM 子账号,创建的方法请参考:访问控制创建子账号。
注意:
- 子账号的 AK 对应的 SK 是仅有在创建的时候可以查看到的,后续将无法再显示;因此您需要自行记录好对应的 AK 和 SK 的值。
- 子账号如果需要使用阿里云的控制台登陆的话是需要开启该功能的,请您参考图 2 。
图 2. 子账号开启控制台登陆示意图
在创建完成子账号后该用户需要操作 OSS 就需要将相关的权限赋权给该子账号。授权的方法请您参考:子账号赋权操作。配置完成后即可通过使用该对 AK 和 SK 操作 OSS 了。
2.3 STS 的 AK 、 SK 和 Token
STS 的 Token 相比于上面的两种方式来说更加的具有安全性但同时其获取方法和处理逻辑都会更加复杂。具体的生成步骤包括以下几步:
- 创建生成 Token 的子账号。因为 STS 的 Token 是需要子账号调用 assumerole 接口,因此第一步即是创建 RAM 子账号并且赋权 AliyunSTSAssumeRoleAccess 权限。该权限即是可以调用 assumerole 接口的权限。
图 3. 子账号赋权示意图
- 创建角色。角色是访问控制的一种虚拟身份,当子账号扮演 RAM 角色时即获得 RAM 角色的临时安全令牌,使用这个临时安全令牌就能以角色身份访问被授权的资源。而创建的步骤是创建用户角色(如图 4 )->选择账号,并填写当前 UID (如图 5 )->填写用户角色名称。
图 4. 创建用户角色示意图
图 5. 角色选择账号示意图
- 给角色赋予 OSS 操作权限。由于子账号扮演角色操作 OSS 是需要角色有操作 OSS 的权限的,这里我们先赋予 AliyunOSSFullAccess 权限。配置如图 6 所示。
图 6. 角色赋权示意图
- 调用 STS 的 assumerole 接口,其中包括子账号的 AK 和 SK ,角色的 Arn 以及用户自定义 Policy 权限参数。示例代码如下所示:
public class NewStsServiceSample {
// 目前只有"cn-hangzhou"这个region可用, 不要使用填写其他region的值
public static final String REGION_CN_HANGZHOU = "cn-hangzhou";
// 当前 STS API 版本
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 {
// 创建一个 Aliyun Acs Client, 用于发起 OpenAPI 请求
IClientProfile profile = DefaultProfile.getProfile(REGION_CN_HANGZHOU, accessKeyId, accessKeySecret);
DefaultAcsClient client = new DefaultAcsClient(profile);
// 创建一个 AssumeRoleRequest 并设置请求参数
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);
request.setDurationSeconds((long)900);
// 发起请求,并得到response
final AssumeRoleResponse response = client.getAcsResponse(request);
return response;
} catch (ClientException e) {
throw e;
}
}
public static void main(String[] args) throws MalformedURLException, IOException {
// 只有 RAM用户(子账号)才能调用 AssumeRole 接口
// 阿里云主账号的AccessKeys不能用于发起AssumeRole请求
// 请首先在RAM控制台创建一个RAM用户,并为这个用户创建AccessKeys
String accessKeyId = "";
String accessKeySecret = "";
// RoleArn 需要在 RAM 控制台上获取
String roleArn = "";
// RoleSessionName 是临时Token的会话名称,自己指定用于标识你的用户,主要用于审计,或者用于区分Token颁发给谁
// 但是注意RoleSessionName的长度和规则,不要有空格,只能有'-' '_' 字母和数字等字符
// 具体规则请参考API文档中的格式要求
String roleSessionName = "alice-001";
// 如何定制你的policy?
String policy = "{\n" +
" \"Version\": \"1\", \n" +
" \"Statement\": [\n" +
" {\n" +
" \"Action\": [\n" +
" \"oss:*\"\n" +
" ], \n" +
" \"Resource\": [\n" +
" \"acs:oss:*:*:*\" \n" +
" ], \n" +
" \"Effect\": \"Allow\"\n" +
" }\n" +
" ]\n" +
"}";
// 此处必须为 HTTPS
ProtocolType protocolType = ProtocolType.HTTPS;
try {
final AssumeRoleResponse 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());
}
}
}
5.生成 STS 的 AK 、 SK 和 Token 即可以创建 OSSclient 对象,特别需要注意的是最终生成的 AK 、 SK 和 Token 的权限是角色的权限以及 assumerole 接口的 policy 参数的交集。初始化代码如下所示:
OSSClient Server = new OSSClient(endpoint, response.getCredentials().getAccessKeyId(), response.getCredentials().getAccessKeySecret(),response.getCredentials().getSecurityToken());
3. 权限设置
OSS 针对于所有的 API 接口都分别提供了对应的权限,详细的 OSS 各接口权限请参考: OSS 接口权限,上面提供的示例仅仅是所有的 OSS 权限。用户可以根据具体需要的权限分别设置 Policy 的 Action 。
注意:如果需要子账号可以通过可视化操作 OSS 的话是必须赋予 oss:ListBuckets 权限的,而该权限暂时仅支持赋权给所有的 Bucket ,因此可视化显示仅支持显示所有的 Bucket ,但是具体操作 Bucket 的权限可以根据其他的操作权限控制。
同样 OSS 是可以限制该子账号访问的来源 IP ,在 Policy 中通过 Condition中进行限制,并且可以设置 IP 段限制。具体的示例如下:
"Condition":{
"IpAddress": {
"acs:SourceIp": ["42.120.88.0/24", "42.120.66.0/24"]
}
}
另外用户可以进赋权给特定的子目录设置单独的访问权限,并且根据不同的场景会有不同的设置方法,请参考: OSS 赋权目录示例,其他更多的权限设置常见问题请参考: OSS 赋权常见问题。