作者:張醫博
企業上雲的安全威脅排名
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());
}
}
}