作者:張醫博
RAM 背景由來
給予 AWS 上的 Code space (代碼與軟體管理平台)系統資料和備份資料一并被攻擊者删除。
企業上雲的安全威脅排名

part1 - 雲賬号及其安全
雲平台上多租戶隔離的基本主體
- 1、阿裡雲現在所有雲産品彼此之前都是隔離,主賬号和 RAM 子賬号也都是隔離的,彼此不能互訪
- 2、同一個主賬号 UID 下,不同的雲産品預設不能互訪,需要在主賬号授權的跨産品授權的權限下才能通路
- 3、未經過主賬号授權的情況下,其他主賬号 uid 是不能通路使用者自己的雲産品和控制台。
認識雲賬戶
- 1、統一出賬
- 2、統一開票
- 3、共享信譽額度
雲賬戶安全
- 1、雲賬戶安全就是要保護雲資源以防止未授權通路,即便是同個雲賬号下的不通産品也不能互訪,除非雲賬号自身允許
- 2、認識雲賬号憑證(Credentials)
- 2.1、登陸密碼驗證(password)
- 2.2、mfa 多因素驗。
- 2.3、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 而已。
1、三闆斧就是 effect ,action,resource ,這三個是一組,包含在一個 {} 内,第二條語句要用 "," 隔開寫在第二個 {} 内
2、effect :隻有 Allow 和 Deny
3、action :可以寫多條時要用 [] 包括,比如 ["acs:ecs:cn-hangzhou:1982222:instance/i-zxxxxesd" , "acs:oss:cn-beijing:1299:bucket/prefix/objet"]
4、action :填寫的是你要限制對應的産品的 API 名稱,寫多個時要用 [] 包括主,比如 [ “ecs:CreateInstance”,"ecs:StopInstance"]
5、product:填寫産品名稱 slb、ecs 、oss、vpc 等。
6、regionID:cn-shanghai、cn-hangzhou 等
7、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 應運而生。
臨時、最小粒度、可控
- 1、臨時: sts 的令牌有效期是 900-3600 秒,一但過期将失去效力。
- 2、最小粒度:sts 隻能操作角色扮演了政策的對應産品,簡單說就是,把使用者想授權的各類雲産品抽象出各種角色,給每個角色賦予不通的權限,ram 子賬号扮演了哪種角色就可以有哪種權限,及時 sts 資訊洩露,客戶隻要删除 sts 角色即可,或者将角色和 ram 子賬号解綁,盜取者也沒有用了,而且并不影響使用者其他使用 ak sk 的服務端業務。
- 3、可控:生成 sts 是放在使用者自己的伺服器上是以安全可用。
sts 建立、代碼實踐
由于 sts 也要建立 ram 子賬号存在與 part3 重複的地方,是以建立 ram 子賬号的位置我就不示範了。
- 建立角色,選擇使用者角色,目前賬号,如果選擇其他雲賬号是給其他 雲賬号下的 子賬号授權通路自己的雲産品,要區分概念。這裡我們給自己的雲賬号授權,是以預設。
- 給角色建立一條自定義政策或者系統政策都行
- 給角色綁定我們剛才自定義的 policy
- 讓 ram 有權調用角色,這樣 ram 子賬号就有了角色對應的産品政策,是以要讓角色和 ram 關聯
- 1、最後一部利用服務端的代碼,填入我門剛才建立 ram 、角色時得到的所有資訊,就能生成 sts 令牌
- 2、rolearn 就是我們在建立角色時控制台看到的。
- 3、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());
}
}
}