阿里云OSS配置私有Bucket生成STS临时授权Url访问
阿里云提供的 权限管理系统 或 访问控制服务 主要包含两部分,RAM(Resource Access Management)和 STS(Security Token Service),RAM 主要的作用是控制账号系统的权限,你可以使用 RAM 在主账号的权限范围内创建子用户,给不同的子用户分配不同的权限从而达到授权管理的目的。STS 是一个安全凭证(Token)的管理系统,你可以使用 STS 来完成对于临时用户的访问授权。
RAM 和 STS 需要解决的一个核心问题是如何在不暴露主账号的 AccessKey 的情况下安全的授权别人访问,因为一旦主账号的 AccessKey 暴露出去的话会带来极大的安全风险,别人可以随意操作该账号下所有的资源,盗取重要信息等。
RAM 提供一种 长期有效 的权限控制机制,通过分出不同权限的 子账号,将不同的权限分给不同的用户,这样一旦子账号泄露也不会造成全局的信息泄露。但是,由于子账号在一般情况下是长期有效的,因此,子账号的 AccessKey 也是不能泄露的。
相对于 RAM 提供的长效控制机制,STS 提供的是一种 临时访问授权 。通过 STS 可以返回 临时的 AccessKey 和 Token,这些信息可以直接发给临时用户用来访问 OSS 。一般来说,从 STS 获取的权限会受到更加严格的限制,并且拥有时间限制,因此这些信息泄露之后对于系统的影响也很小。
举个例子
当前你的阿里云用户,其在 OSS 下有一个私有的 Bucket,bucket-a 。我们的账户对这个 Bucket 都拥有完全的权限。
为了避免阿里云主账号的 AccessKey 泄露导致安全风险,我们一般会使用 RAM 创建了子账号 如:“testOss”。子账户testOss拥有独立的 AccessKey和AccessKeySecret 。这个时候需要再创建一个新的角色,并且给这个角色赋予Bucket读取的权限。
为了能获取 临时授权,这个时候可以调用 STS 的 AssumeRole 接口,告诉 STS ,子账号 testOss 将要扮演 刚才我们新建的 这个角色,如果成功,STS 会返回一个 临时的 AccessKeyId 、AccessKeySecret 还有 SecurityToken 作为访问凭证。将这个 临时授权凭证 发给需要访问的 临时用户 就可以获得访问 bucket-a的临时权限了,凭证过期的时间可以在调用 AssumeRole 接口的时候指定,最大不超过2小时。
并且将我们临时授权凭使用签名URL进行临时授权,既可以拿到文件访问的临时授权的url。
准备工作
- 创建 RAM 子账号
创建一个 RAM 子账号 oss-test-key,不需要赋予任何权限,因为在扮演角色的时候会自动获得被扮演角色的所有权限。
注意:这里建议给你创建的子账户赋予上传的权限,否则你在上传的时候需要先获取STS授权才能上传,这里我提前赋予了,所以Bucket是私有的情况下,上传是不受影响的,只是访问预览下载链接会被拒绝
进入控制台-选择OSS存储对象-选择Access Key
跳转页面,阿里云会告诉你建议使用子账户Access Key-选择开始使用子用户Access Key
创建用户
创建你的账户信息和显示名称(别忘记勾选Open Api调用访问)
- 创建授权角色
点击角色-创建角色-选择阿里云账户
配置角色名称-完成-为角色授权
选择系统策略-搜索OSS-选择AliyunOSSReadOnlyAccess(只读访问对象存储服务(OSS)的权限),AliyunOSSFullAccess(管理对象存储服务(OSS)权限),AliyunSTSAssumeRoleAccess(调用STS服务AssumeRole接口的权限)
创建成功后之后,可以在角色列表里面看到你刚才创建的角色信息-点击你刚才创建的角色
记录你的RAM角色名称和ARN信息(一会儿会用到)
获取STS临时授权
阿里云OSS官方文档使用STS临时访问凭证SDK:使用STS临时访问凭证访问OSS
public AssumeRoleResponse buildAliyunSTSCredentials() throws ClientException, com.aliyuncs.exceptions.ClientException {
// STS,这里我以杭州举例,具体你的Bucket地域节点是哪里的就填哪里
DefaultProfile.addEndpoint("", "", "Sts", "sts.cn-hangzhou.aliyuncs.com");
//这里需要填充你子账户的accessKeyId与accessKeySecret
IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
DefaultAcsClient client = new DefaultAcsClient(profile);
final AssumeRoleRequest request = new AssumeRoleRequest();
request.setMethod(MethodType.POST);
request.setProtocol(ProtocolType.HTTPS);
//设置临时访问凭证的有效时间为3600秒
request.setDurationSeconds(60 * 60 * 1L);
// 要扮演的角色ID-刚才你创建的角色详情里面ARN
request.setRoleArn("acs:ram::12************41:role/RamTestAppReadOnly");
// 要扮演的角色名称-刚才你创建的角色详情里面角色名称
request.setRoleSessionName("external-username");
// request.setPolicy(policy);
// 生成临时授权凭证
final AssumeRoleResponse response = client.getAcsResponse(request);
// 临时凭据AccessKeyId
String appKey = response.getCredentials().getAccessKeyId();
// 临时凭据AccessKeySecret
String appSecret = response.getCredentials().getAccessKeySecret();
// 临时凭据SecurityToken
String securityToken = response.getCredentials().getSecurityToken();
String expiration = response.getCredentials().getExpiration();
return response;
accessKeyId表示RAM子账号的AccessKeyId;
accessKeySecret表示RAM子账号的AccessKeySecret;
RoleArn表示的是需要扮演的角色ID,角色的ID可以在 角色管理 > 角色详情 中找到;
RoleSessionName是一个用来标示临时凭证的名称,一般来说建议使用不同的应用程序用户来区分;
DurationSeconds指的是临时凭证的有效期,单位是s,最小为900,最大为3600;
Policy表示的是在扮演角色的时候额外加上的一个权限限制;
appKey表示创建的临时凭据AccessKeyId;
appSecret表示创建的临时凭据AccessKeySecret;
SecurityToken 表示创建的临时凭据SecurityToken;
使用签名URL进行临时授权
阿里云OSS官方文档SDK 使用签名URL进行临时授权
// 重写的方法以作参考
public String getAuthorization(AssumeRoleResponse assumeRoleResponse, String fileName) {
// 创建OSSClient实例。填充你的Endpoint与桶名称
// yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
//这里替换成你自己的Endpoint和BucketName即可
String endpoint = properties.getEndpoint();
// 填写Bucket名称,例如examplebucket。
String bucketName = properties.getBucketName();
// 填写Object完整路径,例如exampleobject.txt。Object完整路径中不能包含Bucket名称。
// String objectName = fileName;
if (assumeRoleResponse == null){
return null;
}
// 从STS服务获取的临时访问密钥(AccessKey ID和AccessKey Secret)。
String accessKeyId = assumeRoleResponse.getCredentials().getAccessKeyId();
String accessKeySecret = assumeRoleResponse.getCredentials().getAccessKeySecret();
// 从STS服务获取的安全令牌(SecurityToken)。
String securityToken = assumeRoleResponse.getCredentials().getSecurityToken();
//获取oss client
OSS ossClient = new OSSClient(properties.getEndpoint(), credentialProvider, configuration);
// 设置签名URL过期时间为3600秒(1小时)。
Date expiration = new Date(System.currentTimeMillis() + 3600 * 1000);
// 生成以GET方法访问的签名URL,访客可以直接通过浏览器访问相关内容。
URL url = ossClient.generatePresignedUrl(bucketName, fileName, expiration);
System.out.println(url);
// 关闭OSSClient。
ossClient.shutdown();
return url.toString();
当前返回url就是重新生成带有过期时候的临时授权访问地址
注意:以上方法是将你把你的Bucket设为了私有模式使用,正常公共读与公共读写不需要临时授权访问
总结
其实实现STS临时访问授权的过程就是
- 创建RAM子账号
- RAM子账号授予STS权限
- RAM子账号扮演指定角色
- 拿到临时授权凭证
- 将授权凭生成签名URL进行临时授权访问
其中,如果你的子账户没有赋予上传的权限,那么这时候如果你的Bucket又是私有的话,上传是失效的,所以一开始建议将你创建的ARM子账户赋予一个上传的权限。否则你上传的时候也需要先获取STS授权才能上传。