ACK場景下應用程序訪問云資源最佳實踐
在ACK場景下應用程序如何做到無AK訪問后端資源。本方案會提供最佳方案用于指導客戶在ACK場景下更好的使用無AK。
方案概述
對于云上資源的訪問是部署在K8S集群節點上應用的常見需求,比如應用程序中會調用OSS的OpenAPI讀取存儲在指定bucket中的數據。在傳統方式下,應用程序要想訪問其授權范圍內的云上資源,要么使用賬號AK,要么通過訪問ECS meta server扮演指定節點上綁定的RAM角色,獲取STS token作為憑證訪問對應資源服務的OpenAPI。
對于使用固定AK直接訪問阿里云API,往往需要將AK寫入Secret,但存在泄漏風險。云上更推薦使用臨時AK方案,如果使用ECS meta server的實例角色方案且能夠保證節點上運行的應用均來自同一個可信的租戶,那么不同應用共享同一個角色STS token在安全上是可以接受的。而在多租場景下,節點上綁定的角色授權需要滿足來自不同租戶應用的云資源使用需求,這樣在一個租戶應用中只需要訪問meta server的角色token接口就可以輕松獲得節點上所有租戶應用的云資源訪問權限,直接引發跨租戶的越權訪問。
本文檔則介紹了一種針對阿里云ACK應用場景的無AK方案,解決集群上多租戶針對數據面的應用云資源訪問權限隔離的解決方案。
方案優勢
與K8S有很好的兼容性
不需要在集群Node節點上綁定任何的RAM角色,也不需要在集群Node節點上運行額外的Agent。
多租戶最小化授權
在同一套ACK集群上可以同時運行多個業務程序,支持按不同Namespace、不同應用授權。權限管理能夠最小化粒度,避免過度授權。
提供應用使用規范
提供一套標準化的可落地文檔與代碼,用于指導客戶快速切換到無AK實現。
客戶場景
容器場景的AK防泄露
場景描述
如何避免永久訪問密鑰的使用,最好的辦法就是不使用固定AK。這個場景特定當客戶使用容器場景下,如何規避應用程序泄露AK。
適用客戶
- 使用容器的企業客戶
- 單個K8S集群跑了多個租戶業務
- 對AK治理要求高的客戶
客戶案例
客戶背景
某知名快遞企業X,作為國內快遞龍頭企業,每日處理的訂單及包裹數據據達到千萬級別。客戶對云上身份安全非常重視。
客戶痛點(或客戶訴求)
客戶全部的業務跑在一套集群里面,通過不同的Namespace隔離。不同業務應用在不同的Namespace里。有些應用需要操作云資源(如寫日志、提交圖片到OSS等),起初各個應用都是直接把AK/SK硬編碼在應用程序中,后面出現過研發離職之后把代碼帶出去,導致應用對應的AK泄露。客戶希望在ACK場景下有一套最佳AK管理實踐。
實施方案
- 每個應用分配一個單獨的RAM Role,最小化授權。
- 修改Pod部署YAML文件,添加OIDC Token的Volume。
- 應用程序完成改造,由硬編碼AK改變造成臨時AK。
客戶收益
- 應用程序中不再出現硬編碼AK,防止研發將AK泄露。
- 當出現某個臨時Token泄露之后,可以非常快速處理,不需要改代碼重新部署。
方案架構
整個方案涉及到的產品主要是兩塊,一塊是K8S集群,一塊是RAM訪問控制,下面從靜態配置這部分來介紹整個方案。
靜態配置
因為涉及到K8S容器服務和RAM訪問控制,所以配置也在兩邊同時進行:
- 在RAM訪問控制側,需要配置一個新身份提供商(IdP),所以這里需要在RAM訪問控制側添加基于OIDC的身份提供商定義,比如OIDC的issuer url,aud等,同時配置一個該IdP的某一身份能扮演的角色,在角色扮演的授信方限制OIDC的相關身份信息,比如audience,subject等,同時定義該角色能訪問的資源和相關action;
- 在K8S集群側,配置相關OIDC的屬性,比如自身的OIDC標識,頒發ID_Token使用的公私鑰等,同時給目標Pod定義響應的Service Account,把該Pod需要扮演的角色名稱等配置好,這樣在Pod啟動后在對應卷目錄下就可以獲取到動態替換的ID_Token,結合在RAM側定義的角色ARN,通過RAM/STS服務獲取到阿里云臨時安全令牌(Security Token Service,STS),從而最終訪問阿里云其他云產品服務;
從最終實現體來看,就是K8S里的一個Service Account定義,里面包含RoleName和OIDC ID_Token,RoleName映射到RAM里面的角色名稱,然后該角色扮演的授信體,通過ID_Token里的aud,sub來匹配。目前OIDC這部分配置,ACK產品已經能夠實現一鍵配置,無需手工配置。
架構總結
在K8S集群上配置OIDC屬性,使該集群可以對特殊的Service Account產生標準的ID_Token并把這些token注入到使用特殊Service Account的Pod中去,同時RAM訪問控制可以配置集群上的OIDC provider作為標準的IdP,并信任這類IdP頒發出來的ID_Token做為身份代表,進而把這些身份作為授信實體綁定到不同的角色上,最終Pod里的應用可以使用這些ID_Token,去扮演預定義的角色獲取到STS去訪問其他云服務。
方案延展
除了在密鑰本身的優化和提升,對于現有的已經存在的永久密鑰怎么樣更好的使用,提高安全風險防御能力,也是需要考慮和優化的部分。這部分涵蓋的內容,也會有好幾塊,比如密鑰輪轉,密鑰托管等方案。建議可以查閱Landing Zone在身份權限管理的其他方案。
產品費用及名詞
產品費用
產品名稱 |
產品說明 |
產品費用 |
RAM |
訪問控制(RAM)是阿里云提供的一項管理用戶身份與資源訪問權限的服務。使用RAM,您可以創建、管理RAM用戶(例如員工、系統或應用程序),并可以控制這些RAM用戶對資源的操作權限。 |
免費,詳情參見產品定價。 |
STS |
阿里云臨時安全令牌(Security Token Service,STS)是阿里云提供的一種臨時訪問權限管理服務。 |
免費,詳情參見產品定價。 |
容器服務ACK |
阿里云容器服務Kubernetes版(Alibaba Cloud Container Service for Kubernetes,簡稱容器服務ACK)是全球首批通過Kubernetes一致性認證的服務平臺,提供高性能的容器應用管理服務,支持企業級Kubernetes容器化應用的生命周期管理,讓您輕松高效地在云端運行Kubernetes容器化應用。 |
收費,詳情參見產品定價。 |
名詞解釋
名稱 |
說明 |
OIDC |
OIDC是一套業界內比較認可的用于用戶身份認證的協議,在我們生活中比較常見的場景是使用支付寶授權登錄某個三方應用。OIDC使用授權協議(通常為OAuth 2)來進行身份認證,因為可以簡單的理解為OIDC是通過OAuth 2來實現的。 |
OAuth2 |
OAuth2這種授權協議是什么,這里借鑒網上最常見的例子:某人A去機構B,科室C辦事,前臺就會攔住A,檢查A是否預約,之后進行登記,然后給A一個通行證,A就可以正常通行了。這里的前臺檢查是否預約,之后給通行證就是授權的過程。這里面的A就可以看做業務系統(或者說是第三方應用),科室C就是三方軟件想訪問的資源。因此授權協議,就是為了保證第三方在獲取了授權之后,才能訪問資源。 |
AccessKey |
在調用阿里云API時您需要使用AccessKey完成身份驗證。AccessKey包括AccessKey ID和AccessKey Secret,需要一起使用。 |
安全性
Role精細化授權
可以通過創建自定義策略指定RAM角色具體的權限。對于程序訪問場景,某個業務應用程序的邏輯是可以預知的,明確能夠知道程序會訪問云上的哪些資源,做哪些操作。建議在應用維度進行精細化授權。如一個業務程序需要對xxxbucket進行圖片的上傳下載,那么精細化授權后,策略示例如下所示:
{
"Version": "1",
"Statement": [
{
"Effect": "Allow",
"Action": ["oss:GetObject", "oss:PutObject"],
"Resource": "acs:oss:cn-hangzhou:1234567890:xxxbucket/*"
}
]
}
同時,同一個應用的不同環境訪問的資源也不應該相同,建議一個應用的一個環境對應具體的一個Role,避免過度授權,也避免不同環境的業務互相影響。
實際針對K8S場景,不建議測試環境和生產環境混在同一個賬號的同一個集群下。建議測試環境的業務都單獨運行在測試環境賬號下的集群。生產環境的集群則運行在生產環境賬號下的集群。
如果想要獲取進一步精細化授權,也可以限制控制調用端的SourceIp。
STS Token權限范圍
STS Token的權限:默認與指定扮演的角色權限相同。
若在調用AssumeRole接口時不設置Policy參數,則返回的STS Token將擁有指定角色的所有權限。
注意事項
STS服務調用次數是否有上限
AssumeRole接口調用次數上限:6000次/分鐘、100次/秒。一個阿里云賬號及該賬號下的RAM用戶、RAM角色共用該接口調用次數上限。當請求量超過上限時,會觸發流控,影響業務正常運行。客戶需要準確評估應用的調用頻次,如果確實需要提升容量,則可以提交工單申請配額。每個STS Token都有過期時間,建議在有效期內,在客戶端進行緩存,避免每次調用阿里云API都重新生成STS Token造成限流影響業務使用。
STS Token發生泄露時處理
如果通過扮演RAM角色獲取的安全令牌(STS Token)發生泄露,您可以按以下步驟回收所有已經頒發的STS Token。
- 使用阿里云賬號登錄RAM控制臺。
- 移除RAM角色的所有權限策略。具體操作,請參見為RAM角色移除權限。
- 刪除RAM角色。具體操作,請參見刪除RAM角色。刪除RAM角色后,所有通過扮演該RAM角色獲取的且未過期的STS Token都將立即失效。
如果您還需要使用該角色,您可以重新創建同名角色并授權相同的權限策略,使用新創建的角色繼續完成您的任務。
ACK集群版本要求
RRSA功能目前只支持1.22及以上版本的集群(即ACK標準版、ACK Pro版、ASK標準版和ASK Pro版)。
實施步驟
實施準備
- 確保已開通了ACK集群。
- 確保已在ACK集群中創建好相應的K8S資源,包括namespace / serviceaccount。
實施時長
在實施準備工作完成的情況下,本方案實施預計時長:45分鐘。
數據規劃
以下操作過程參考如下數據規劃:
資源對象 |
資源二級類型 |
值 |
ACK |
namespace |
default |
serviceaccount |
app |
|
ram |
role |
ACK-APP-STS-Role |
操作步驟
啟用RRSA功能
本步驟配置容器服務的RRSA功能,若已配置參數可跳過該步驟。
- 登錄容器服務管理控制臺。
- 在控制臺左側導航欄中,單擊集群。
- 在集群列表頁面中,單擊目標集群名稱或者目標集群右側操作列下的詳情。
- 在集群詳情頁面,單擊基本信息頁簽,單擊RRSA OIDC提供商URL右側的啟用RRSA。
- 在彈出的啟用RRSA對話框中,單擊確定。當集群狀態由更新中變為運行中時,說明該集群的RRSA特性已變更完成,RRSA OIDC提供商URL右側會顯示OIDC提供商的URL鏈接。
使用RRSA功能
集群開啟RRSA功能后,按照以下步驟來賦予集群內應用通過RRSA功能獲取訪問云資源OpenAPI的臨時憑證的能力。
- 創建RAM角色
需要為應用所使用的服務賬戶(Service Account)創建一個RAM角色。后續應用將獲取一個扮演這個RAM角色的臨時憑證。在創建角色過程中,需要選擇身份提供商類型為OIDC,身份提供商選擇對應集群ID生成的身份提供商(格式一般為ack-rrsa-$集群ID),限制條件中,oidc:sub
格式為system:serviceaccount:<namespace>:<service_account>
。更多信息,請參見創建可信實體為阿里云賬號的RAM角色。
最終創建出來的RAM角色的信任策略類似如下格式:
{
"Statement": [
{
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"oidc:aud": "sts.aliyuncs.com",
/*替換為當前集群的OIDC提供商URL,該URL可以在集群詳情的基本信息頁簽獲取。*/
"oidc:iss": "",
/*替換為應用所在的命名空間,本示例為:default。*/
/*替換為應用使用的服務賬戶,本示例為:app。*/
"oidc:sub": "system:serviceaccount::"
}
},
"Effect": "Allow",
"Principal": {
"Federated": [
/*替換為阿里云主賬號UID。替換為ACK集群ID。*/
"acs:ram:::oidc-provider/ack-rrsa-"
]
}
}
],
"Version": "1"
}
- 為RAM角色授權。您可以通過為這個RAM角色授權的方式,指定這個RAM角色可以訪問的云資源。更多信息,請參見為RAM角色授權。
注意這個角色,就是應用程序實際扮演的角色,需要賦上對應云資源操作權限。
- 部署應用
部署應用時,需要修改應用的模板內容,自動生成OIDC Token。具體操作,請參見部署服務賬戶令牌卷投影。
模板示例:
apiVersion: v1
kind: Pod
metadata:
name: test-rrsa
spec:
containers:
- image: alpine:3.14
command:
- sh
- -c
- 'sleep inf'
name: test
volumeMounts:
- mountPath: /var/run/secrets/tokens
name: oidc-token
serviceAccountName: build-robot
volumes:
- name: oidc-token # 新增的配置項。
projected:
sources:
- serviceAccountToken:
path: oidc-token
expirationSeconds: 7200 # oidc token過期時間(單位:秒)。
audience: "sts.aliyuncs.com"
注意!
- audience字段的值必須是 sts.aliyuncs.com。
- expirationSeconds 的值必須小于43200(12小時),如果設置的值比該值大,實際的OIDC Token會使用12小時作為過期時間。
您的應用就可以使用容器內掛載的OIDC Token(上面示例中的/var/run/secrets/tokens/oidc-token文件內容)調用STS的AssumeRoleWithOIDC接口來獲取一個扮演前面創建的RAM角色的STS臨時憑證,然后使用臨時憑證訪問云資源OpenAPI。
應用程序使用RRSA OIDC Token認證
目前阿里云官方SDK中,Go、Java、Node.js/TypeScript 已經支持了這種認證方式,無需開發人員手動調用AssumeRoleWithOIDC接口,就可以實現直接獲取到STS Token完成阿里云API調用。
請參考下一個章節,查看對應代碼示例。
故障排除
為什么使用STS時會報錯?
如果一個RAM用戶使用API、CLI或SDK調用AssumeRole獲取STS Token時,出現如下報錯信息:
Error message: You are not authorized to do this action. You should be authorized by RAM.
問題原因和解決方法如下:
- 該RAM用戶缺少允許STS扮演角色的權限策略:請為該RAM用戶添加系統策略(AliyunSTSAssumeRoleAccess)或自定義策略,詳情請參見能否指定RAM用戶具體可以扮演哪個RAM角色。
- RAM角色的信任策略不包含您正在使用的RAM用戶,即RAM角色不允許該RAM用戶扮演:請為RAM角色添加允許該RAM用戶扮演的信任策略,詳情請參見修改RAM角色的信任策略。