作者:张医博
企业上云的安全威胁排名
part1 - 云账号及其安全
云平台上多租户隔离的基本主体
- 阿里云现在所有云产品彼此之前都是隔离,主账号和 RAM 子账号也都是隔离的,彼此不能互访。
- 同一个主账号 UID 下,不同的云产品默认不能互访,需要在主账号授权的跨产品授权的权限下才能访问。
- 未经过主账号授权的情况下,其他主账号 uid 是不能访问用户自己的云产品和控制台。
认识云账户
- 统一出票
- 统一出账
- 共享信誉额度
云账户安全
• 云账户安全就是要保护云资源以防止未授权访问,即便是同个云账号下的不通产品也不能互访,除非云账号自身允许
• 认识云账号凭证(Credentials)
o 登陆密码验证(password)
o mfa 多因素验证
o api 访问问(ak/sk)
part2 - 用户身份管理与访问控制
谁是 user
1、用户自己登陆
2、用户授权自己的 ram 子账号登陆。
3、用户授权别人加的 ram 账号登陆
RAM 核心功能
集中用户管理
• 所有的用户都可以在控制台上统一的可视化界面处理,统一的 api 接入
谁是应用
1、比如阿里云提供的工具,类似 oss 的 brower
2、客户的应用程序代码(app、服务端程序)通过 sts 或者 云账号的 ak/sk
3、ecs 的 meta 网关信息也可以操作
https://www.alibabacloud.com/help/zh/doc-detail/54579.htm
阿里云RAM的特色
ABAC模型:AttributeBasedAccessControl . 这种是我们常用的自定义 policy 需要自己写控制语句
ABACvsACL: 就是我们常用系统策略,权限粒度小,都是一个管理权限或者只读、只写的权限。
一个实际的授权场景
{
"Version":"1",
"Statement":[ {
"Effect":"Allow", "Action":"ecs:StopInstance", "Resource":"acs:ecs:cn-hangzhou:*:*", "Condition":{
"StringEquals":{ "ecs:tag/env":"production"
}, "Bool":{
"acs:MFAPresent":"true" },
"IpAddress":{ "acs:SourceIp":"42.120.88.0/24"
} }
} ]
}
以上策略意思是 针对 42.120.88.0,允许操作 production 组内的 ecs 实例进行停止操作。
为了方便我们给他分开三块看,这样会比较清晰。
第一块:固定的外层语法不变,即使有多条策略也是在者一个 statement 内部,用 "," 分开。
{
"Sersion":"1"
"Statement":[
"这里是第二块"
]
}
第二块:我们简称三板斧,因为内容是固定的,只不过变化 value 而已。
• 三板斧就是 effect ,action,resource ,这三个是一组,包含在一个 {} 内,第二条语句要用 "," 隔开写在第二个 {} 内
• effect :只有 Allow 和 Deny
• action :可以写多条时要用 [] 包括,比如 ["acs:ecs:cn-hangzhou:1982222:instance/i-zxxxxesd" , "acs:oss:cn-beijing:1299:bucket/prefix/objet"]
• action :填写的是你要限制对应的产品的 API 名称,写多个时要用 [] 包括主,比如 [ “ecs:CreateInstance”,"ecs:StopInstance"]
• product:填写产品名称 slb、ecs 、oss、vpc 等。
• regionID:cn-shanghai、cn-hangzhou 等
• uid:云账号 uid
{
"Sersion":"1"
"Statement":[
{
"Effect":"Allow / deny",
"Resource":"acs:product:regionid:uid:*",
"Action:":"apiname"
},
{
"设置并行的第二条语句"
}
]
}
Part 3: 最佳实践
下面我实际操作如果新建 ram 子账号、授权策略
• 新建账户
• 系统策略
• 自定义策略
• 使用 RAM 子账号 ak sk
App 安全天使 STS
为什么说是安全天使
当前端上的 APP 不可能直接使用客户的 ak sk ,风险性极高,一但恶意攻击者那到你 APP 数据包,揭秘出源码中的 ak sk ,您的云产品将暴露,任何人都可以操作您子账号下所有授权的产品,即使删除 ak sk 也可能导致服务端的其他业务出现链接异常,由此 sts 应运而生。
临时、最小粒度、可控
• 临时: sts 的令牌有效期是 900-3600 秒,一但过期将失去效力。
• 最小粒度:sts 只能操作角色扮演了策略的对应产品,简单说就是,把用户想授权的各类云产品抽象出各种角色,给每个角色赋予不通的权限,ram 子账号扮演了哪种角色就可以有哪种权限,及时 sts 信息泄露,客户只要删除 sts 角色即可,或者将角色和 ram 子账号解绑,盗取者也没有用了,而且并不影响用户其他使用 ak sk 的服务端业务。
• 可控:生成 sts 是放在用户自己的服务器上所以安全可用。
sts 创建、代码实践
由于 sts 也要新建 ram 子账号存在与 part3 重复的地方,所以建立 ram 子账号的位置我就不演示了。
• 新建角色,选择用户角色,当前账号,如果选择其他云账号是给其他 云账号下的 子账号授权访问自己的云产品,要区分概念。这里我们给自己的云账号授权,所以默认。
• 给角色创建一条自定义策略或者系统策略都行
• 给角色绑定我们刚才自定义的 policy
• 让 ram 有权调用角色,这样 ram 子账号就有了角色对应的产品策略,所以要让角色和 ram 关联
• 最后一部利用服务端的代码,填入我门刚才建立 ram 、角色时得到的所有信息,就能生成 sts 令牌
• rolearn 就是我们在创建角色时控制台看到的。
• rolesession 就是角色名称
public class StsServiceSample {
public static void main(String[] args) {
String endpoint = "sts.aliyuncs.com";
String accessKeyId = "<access-key-id>";
String accessKeySecret = "<access-key-secret>";
String roleArn = "<role-arn>";
String roleSessionName = "session-name";
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" +
"}";
try {
// 添加endpoint(直接使用STS endpoint,前两个参数留空,无需添加region ID)
DefaultProfile.addEndpoint("", "", "Sts", endpoint);
// 构造default profile(参数留空,无需添加region ID)
IClientProfile profile = DefaultProfile.getProfile("", accessKeyId, accessKeySecret);
// 用profile构造client
DefaultAcsClient client = new DefaultAcsClient(profile);
final AssumeRoleRequest request = new AssumeRoleRequest();
request.setMethod(MethodType.POST);
request.setRoleArn(roleArn);
request.setRoleSessionName(roleSessionName);
request.setPolicy(policy); // Optional
final AssumeRoleResponse response = client.getAcsResponse(request);
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());
System.out.println("RequestId: " + response.getRequestId());
} catch (ClientException e) {
System.out.println("Failed:");
System.out.println("Error code: " + e.getErrCode());
System.out.println("Error message: " + e.getErrMsg());
System.out.println("RequestId: " + e.getRequestId());
}
}
}