作者:張醫博
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());
}
}
}