Experience Dapr - Secret Store
在這年代不管是開發單體應用架構、還是分散式系統,不管怎樣的語言、平台,都要處理這個問題:
機敏性資料,如
資料庫連線
、第三方串接的API Token
…
這些東西不管在哪個年代都要處理,在這個 DevOps、DevSecOps、經常有 資安事件 的年代,實際的解決方案就顯得更重要了,從 Key Management、Secret Management 都是很重要的過程。其實三大公有雲也都有對應的解決方案,像是 AWS Secret Manager, Azure Key Vault, GCP Secret Manager … 經過一些時日,對於 Dapr 的基本概念與實際架構有了初步認識之後,第一個我想了解的就是 Dapr 如何處理 Secret Manager 這件事情?
上一篇整理了 Dapr 概念與設計,本文整理 Dapr 如何透過 Building Block,實際整合各種 Secret Store 的方法,以及實際要注意的事項。
基本概念
在 Dapr 使用 Secret Management 的基本概念如下圖,圖中我標示了使用的次序性:
- (1): Dapr Sidecar 起來後,依據 component 的設定,初始化對應的 secret type.
- (2): Dapr App 初始化後,透過 Dapr API 取得需要的 secret key / value,然後使用。
圖中上方的 Cloud Secret Stores,就是 Dapr 支援的種類,像是 LocalFile, Environment, HashiCorp Vault, Kubernetes secret, AWS Secret Manager, … 等,詳細列表參閱 Secret store component specs。
除了這些功能,另外 Dapr 也支援 Secret scoping 的概念,也就是透過 Dapr Config 決定可以存取的範圍。
基本概念不難懂,來看看實際怎麼使用的過程。
使用 Secret Store
在本機: 開發階段
定義 component,名稱為 webapi-secrets-store
如下:
1 | apiVersion: dapr.io/v1alpha1 |
設定中指定檔案的形式,檔名 webapi_secrets-file.json
,內容如下:
1 | { |
整個目錄結構:
1 | ~$ tree |
接下使用 Dapr CLI 驗證
1 | ## 啟動一個空的 Dapr App |
同樣的流程,再增加一個名為 aws-secret-store
,type 是 secretstores.aws.secretmanager
的 component:
1 | apiVersion: dapr.io/v1alpha1 |
我在 AWS Secret Manager 已經先建立好一個 Key/Value 的 Secret,名稱是 webapi
。同樣使用 Dapr CLI 測試:
1 | curl http://localhost:3500/v1.0/secrets/aws-secret-store/webapi |
Dapr Secrets API 的結構是這樣的:
單一: GET http://localhost:<daprPort>/v1.0/secrets/<secret-store-name>/<name>
全部: GET http://localhost:<daprPort>/v1.0/secrets/<secret-store-name>/bulk
詳細規格參閱 Dapr API: Secrets API Reference
Secret Scoping
幾個常見的使用情境 (Scenarios):
- Scenario 1: Deny access to all secrets for a secret store
- 禁止 App 存取 K8s 的 Secret
- Scenario 2: Allow access to only certain secrets in a secret store
- 只允許存取 secret store 裡的特定的 keys
- 正向表列、白名單列舉
- Scenario 3: Deny access to certain sensitive secrets in a secret store
- 跟 Scenario 2 相反,允許全部,但是特定的 key 不允許存取
官方文件 很完整的說明這三個主要情境的應用範例,同時列舉了 Permission Priority 列表。
問題與思考
思考取得 Secret 的途徑
在這篇文章:系統發生異常時,第一時間如何快速止血? 提到一個重要的思路:
服務邊界與依賴性:把每個 service 的 downstream / upstream or dependency (外部依賴) 搞清楚
同樣的,要知道前面簡單的 Lab 過程中,上下游的關係,也就是:
- 誰需要發起取得 Secret 的請求?
- 誰負責去 Secret Store (這個例子是檔案) 取得 Secret Values?
回來看看啟動 Dapr APP 的 Log:
1 | INFO[0000] Initialized name resolution to standalone app_id=webapi instance=iStar.local scope=dapr.runtime type=log ver=1.1.2 |
這段訊息代表 Dapr Sidecar 已經 初始化
好 Component 相關東西,上面可以看到有我定義好的 aws-secret-store
, webapi-secrets-store
思考的點:
Dapr Sidecar 初始化做了哪一些事?這些是只做一次嗎?
有興趣,可以去爬各種實作的 Source Code, 我爬了以下的部分:
從 Code 不難了解,其實是每次都會直接操作的。了解這要做什麼?往下看。
[TBD] 成本問題:如何降低對外部 Secret Store / Manager 的存取次數
上一個思考,要帶出的問題:
每個 pod 起來時,至少 Dapr Sidecar 就要對 secret store 存取一次,所以大量啟動 pod 時都會對 secret store 多次存取?
實際上,目前 Dapr 只有 Access Control 的設計:How-To: Limit the secrets that can be read from secret stores,但是沒有針對 Secret Access Rate 有對應的控制方式。
這算是尚未滿足需求的。
我想像的是:
- Dapr App 在 K8s 上如果起 10 個 pod
- 每個 Pod 啟動後,Sidecar 都會依據 Component 設定,根 Secret Store 取得資訊,放在 memory
- 如果有一個 Pod 重啟了,那他的 Sidecar 應該會去問其他 Sidecar 是否已經有 Component 的資訊,從中取得現況。
這個過程應該會需要 分散式共識演算法 處理這些資料的 複本同步問題 (Replication)
,也就是 Raft 演算法當中的複製狀態機 (Replicate State Machine, RSM)。實際上 Dapr 的 Placement 裡也有使用 Hashicorp 的 Consul Raft library,但怎麼處理官方文件並沒有細講,但 Source Code 裡有很多線索。這些是我在 Source code: dapr/pkg/placement/raft/ 找到的資訊,需要更近一步的理解。
- GitHub: Consul Raft library
Dapr 在 AWS 使用上的整合
熟悉 AWS 的人都知道 AWS 有很完整的權限控制概念,可以完全 控制反轉 (Inversion of Control, IoC) 控制權,也就是:
機敏資料的控制權,原本在開發者手上,反轉到 AWS 系統管理員
相關的機制有:
- AWS Profile: IAM Credential
- IAM Role for AWS resource unit, such as EC2, Lambda, API Gateway … etc.
- EKS 的 IRSA (IAM Roles for Service Accounts)
最好的實踐,就是利用既有可靠的機制,所以 Dapr 官方文件的 Integration 部分,針對 Cloud Providers 提供了 Authenticating to AWS 的完整說明。
Audit Log
如果是使用 AWS Secret Management,那就返回 AWS Cloudtrail 應該就可以。
方便的代價:支援 local environment variables 很方便,都使用這個就好了?
官方支援 local env 的模式,但 文件 也警告以下訊息:
我個人建議就是不要使用,方便的代價很高,試著打這個 API 就可以拿到所有 env vars:
http://localhost:<daprPort>/v1.0/secrets/<secret-store-name>/bulk
Building Block 怎麼使用 Secret Store?
Secret Store 可以儲存像是 database connection string 這種機敏性資訊,但是其他的 Dapr components 也都有機敏性資料,像是 state store, binding 都是需要這些資訊才能建立連線,那要怎麼使用 secret store 呢?
參閱官方文件:How-To: Reference secrets in components,下一篇筆記會整理實際的心得。
結語
一開始我在想用詞的問題,到底是要用 Secret Store or Secret Management?
官方文件寫的 Secret Store,我會認為只是一個 Storage 的介接 (Adaptor),換言之,並沒有完整考慮 Lifecycle,換言之對於怎麼 Management 並沒有太多著墨。而現階段 Dapr 的設計,稱得上 Management 是 Scoping / Rate Limit 的部分,基本的功能就是處理 Storage 的介接。
知道怎麼用 Secret Store 了,下一步讓應用程式起來通常要處理的就是資料。Dapr 是分散式框架,必須面對的就是 Message Queue,其中 Pub/Sub 是最常見的模式。下一篇整理 Dapr Pub/Sub Component 的基本使用。
延伸閱讀
Dapr 系列文章
- 摘要 Dapr 的設計與概念
- Experience Dapr - Hello World
- Experience Dapr - Run on K8s
- Experience Dapr - Secret Store
- Experience Dapr - Pub/Sub
分散式系統系列文章
- 聊聊分散式系統
- 分散式一致性問題與共識演算法
- CAP Theorem
- Distributed Message Systems
- Eventually Consistent 與 Dynamo NWR 模型
- 淺談分散式交易
- Design Patterns for Distributed Systems
- 分散式系統設計 - 正體中文版翻譯記事
站內文章
Dapr 官方文件
- Secrets API reference
- Use secret scoping
- How-To: Limit the secrets that can be read from secret stores
- How-To: Reference secrets in components
- Authenticating to AWS
- Use the Secrets Store CSI Driver for Kubernetes in an Azure Kubernetes Service (AKS) cluster