Vault是什么?
如何在云上應(yīng)用中管理和保護(hù)用戶的敏感信息是一個(gè)經(jīng)常令開(kāi)發(fā)者頭疼的問(wèn)題,用戶的密碼口令,證書(shū)秘鑰等私密信息時(shí)常未經(jīng)加密被隨意的放置在配置文件,代碼倉(cāng)庫(kù)或是共享存儲(chǔ)里,而對(duì)于普通的開(kāi)發(fā)者來(lái)說(shuō),設(shè)計(jì)和實(shí)現(xiàn)一套完整的秘鑰管理系統(tǒng)是一個(gè)很大的挑戰(zhàn)。且不論令人生畏的加解密算法,很多的云應(yīng)用仍然將一些敏感配置信息僅僅經(jīng)過(guò)base64等一些簡(jiǎn)單的hash運(yùn)算就放置在某個(gè)公共的配置中心上,而很多時(shí)候這些敏感信息會(huì)從應(yīng)用的某行異常日志或是某段監(jiān)控告警中泄露出去;不僅如此,對(duì)于一個(gè)集中式的秘鑰管理系統(tǒng),如何面向用戶進(jìn)行更細(xì)粒度的訪問(wèn)鑒權(quán)也是一個(gè)難題。
Vault的出現(xiàn)給了上述問(wèn)題一個(gè)解決方案,它是HashiCorp公司(旗下還有Vagrant,Terraform,Consul等知名產(chǎn)品)維護(hù)的開(kāi)源軟件,它的設(shè)計(jì)思想基于云原生背景下動(dòng)態(tài)基礎(chǔ)設(shè)施的特點(diǎn),在云上的不同網(wǎng)絡(luò)層以及不同的服務(wù)之間已經(jīng)很難找到傳統(tǒng)的信任邊界,服務(wù)之間更加強(qiáng)調(diào)以身份(identity)為核心的認(rèn)證和訪問(wèn)控制,而不是像傳統(tǒng)靜態(tài)基礎(chǔ)設(shè)施中以IP、主機(jī)地址作為信任憑證。為此Vault提供了以下幾個(gè)功能點(diǎn):
Secret存儲(chǔ)形式的多樣性,任意的kv形式敏感信息(如數(shù)據(jù)庫(kù)密碼,證書(shū),ssh登錄秘鑰,openapi身份憑證等);
存儲(chǔ)格式的多樣性,支持插件式的存儲(chǔ)引擎擴(kuò)展,可對(duì)接如AWS,Consul,NoSQL,KV,PKI,SSH等多種插件引擎;
支持與各類平臺(tái)的認(rèn)證對(duì)接,可動(dòng)態(tài)生成認(rèn)證憑據(jù)或配置信息;
支持基于Shamir算法的私鑰分割完成Vault后端的加封和解封操作,同時(shí)支持高可用的部署形態(tài);
支持各類secret的動(dòng)態(tài)生成,續(xù)租,撤銷和滾動(dòng)更新;
完備的審計(jì)日志;
完備的CLI和RESTful API
Vault與k8s的集成
Vault松耦合的架構(gòu)使其支持與多種secret引擎和相應(yīng)的存儲(chǔ)后端對(duì)接,同時(shí)支持與多種認(rèn)證服務(wù)器的交互。 本節(jié)我們主要介紹Vault與k8s的集成。
Vault在Kubernetes中的應(yīng)用場(chǎng)景
Vault作為企業(yè)級(jí)的secret管理工具,是一些大客戶在業(yè)務(wù)上云過(guò)程中的安全強(qiáng)需求,尤其是國(guó)外市場(chǎng)。在Kubernetes集群中主要有以下應(yīng)用場(chǎng)景:
作為部署在Kubernetes集群中的應(yīng)用對(duì)外提供秘鑰管理服務(wù),支持與多家主流云廠商秘鑰服務(wù)以及多種secrets形式的對(duì)接,支持多種數(shù)據(jù)庫(kù)服務(wù)的存儲(chǔ)對(duì)接,同時(shí)支持多種認(rèn)證形式的對(duì)接。
作為一個(gè)公共的加密服務(wù)(Encryption as a Service)而不做后端存儲(chǔ)的對(duì)接,幫助用戶應(yīng)用剝離繁瑣的加密加解密邏輯。
面向政府、金融等對(duì)數(shù)據(jù)安全規(guī)格有很高要求的客戶,Vault支持基于Two-man原則利用私鑰分割算法對(duì)后端服務(wù)進(jìn)行加解封,并結(jié)合k8s的高可用部署形態(tài)為企業(yè)提供更加安全可靠的secret管理能力。 當(dāng)然這里只是列舉了一些Vault原生提供的能力,作為一個(gè)在Kubernetes集群上直接運(yùn)行的安全應(yīng)用,任何一個(gè)面向k8s的應(yīng)用工具都可以利用其安全能力。
安裝Vault
Vault支持helm化安裝,在其官方文檔中我們可以找到關(guān)于啟動(dòng)參數(shù)的詳細(xì)配置說(shuō)明,同時(shí)在阿里云容器服務(wù)的應(yīng)用目錄apphub中我們也可以通過(guò)控制臺(tái)在ACK集群中方便的安裝Vault
另外Vault的默認(rèn)安裝也集成了其控制臺(tái)的安裝,通過(guò)負(fù)載均衡服務(wù)或ingress路由的方式我們可以在公網(wǎng)訪問(wèn)其UI,在vault pod的日志中我們可以找到登錄使用的root token,在控制臺(tái)中可以方便的設(shè)定與存儲(chǔ)引擎和認(rèn)證方式的對(duì)接,同時(shí)還可以進(jìn)行基于策略的訪問(wèn)控制配置。
認(rèn)證方式的集成
當(dāng)用戶希望在k8s pod的業(yè)務(wù)邏輯中與Vault服務(wù)端通訊,獲取需要的secrets時(shí),首先Vault會(huì)對(duì)這個(gè)pod中的請(qǐng)求進(jìn)行認(rèn)證,那么這個(gè)pod中的Vault請(qǐng)求認(rèn)證憑據(jù)應(yīng)該如何獲取呢?如上所述,Vault后端支持多種認(rèn)證方式的對(duì)接,對(duì)于Kubernetes,Vault支持基于K8s Service Account Token的認(rèn)證。
使用上,Vault管理員首先需要在后端enable kubernetes的認(rèn)證方式,生成一個(gè)與Vault交互的指定sa,然后通過(guò)CLI或API將sa token和集群ca,公網(wǎng)地址等信息寫(xiě)入到Vault后端中,并配置與vault后端的ACL策略綁定。詳細(xì)步驟請(qǐng)參見(jiàn)官方文檔。
當(dāng)然在pod應(yīng)用中可以并不局限于一定使用基于sa的kubernetes認(rèn)證方式。比如[kubernetes-vault]( https://github.com/Boostport/kubernetes-vault)。該項(xiàng)目使用Vault中的[AppRole](https://www.vaultproject.io/docs/auth/approle.html)認(rèn)證方式,在該認(rèn)證模式中,管理員可以為不同的pod創(chuàng)建不同的Vault原生role模型并綁定到對(duì)應(yīng)的policy上,同時(shí)可以基于role創(chuàng)建secret_id,secret_id對(duì)應(yīng)的token可作為與Vault進(jìn)行認(rèn)證的臨時(shí)憑證。kubernetes-vault利用了AppRole的認(rèn)證交互模式,首先已經(jīng)完成安裝的kubernetes-vault controller會(huì)去Watch集群中所有pod的創(chuàng)建,當(dāng)發(fā)現(xiàn)新建pod的部署模板中有指定annotation的init-container存在時(shí),controller會(huì)根據(jù)模板中指定的vault role id去Vault請(qǐng)求獲取其對(duì)應(yīng)的secret_id并發(fā)送給init-container中kubernetes-vault的客戶端,在應(yīng)用容器啟動(dòng)前kubernetes-vault客戶端用controller返回的secret_id和role_id去Vault請(qǐng)求真正的login token并最終寫(xiě)入到與應(yīng)用pod共享的掛載目錄中;同時(shí)客戶端會(huì)根據(jù)token過(guò)期時(shí)間進(jìn)行定時(shí)的輪轉(zhuǎn),保證其可用性。下圖為kubernetes-vault工作流程圖:
在社區(qū)也存在不少基于k8s與Vault進(jìn)行認(rèn)證對(duì)接的其他方案,其設(shè)計(jì)思路大同小異,基本都采用了通過(guò)init-container或sidecar方式引入一個(gè)額外的客戶端去Vault請(qǐng)求指定認(rèn)證模式下的短時(shí)憑證并共享給業(yè)務(wù)容器使用。 在容器服務(wù)控制臺(tái)的應(yīng)用目錄apphub中,我們同樣可以找到kubernetes-vault,方便開(kāi)發(fā)者使用helm直接在集群指定命名空間一鍵部署。Vault也計(jì)劃在后續(xù)自己的官方版本helm chart中增加配置項(xiàng)以支持上述登錄認(rèn)證secret的動(dòng)態(tài)注入。
Vault與阿里云RAM的集成
當(dāng)我們?cè)趹?yīng)用中需要訪問(wèn)阿里云資源時(shí),需要使用RAM賬號(hào)對(duì)應(yīng)的AK或是STS臨時(shí)credentials作為訪問(wèn)相應(yīng)資源接口的憑證。如果使用賬號(hào)AK,如何使其能夠被應(yīng)用邏輯獲取的同時(shí)保證AK的安全性一直是一個(gè)頭疼的問(wèn)題;如果使用臨時(shí)sts token,由于其時(shí)效性,我們也需要在考慮安全性的同時(shí)思考如何進(jìn)行臨時(shí)訪問(wèn)憑證的輪轉(zhuǎn)。相比較兩種方式,使用sts臨時(shí)憑證的方式肯定在安全上是更為推薦的方式,同時(shí)對(duì)這種動(dòng)態(tài)secret的安全管理也正是Vault的優(yōu)勢(shì)所在。本節(jié)我們來(lái)介紹下Vault與阿里云RAM在認(rèn)證方式和secret管理引擎上的集成。
認(rèn)證方式的集成
首先在認(rèn)證方式上,Vault服務(wù)端的role模型可以與RAM role進(jìn)行一對(duì)一的映射匹配,用戶可以使用Vault提供的OpenAPI或是CLI,通過(guò)傳入扮演RAM role返回的臨時(shí)憑證調(diào)用GetCallerIdentity接口,然后Vault服務(wù)端會(huì)根據(jù)請(qǐng)求返回的角色arn id在其后端存儲(chǔ)中查找是否有對(duì)應(yīng)的權(quán)限策略配置,如果存在則認(rèn)證成功并返回一個(gè)可用于調(diào)用Vault其他后端接口的訪問(wèn)token。
Vault Secret引擎與RAM的集成
當(dāng)我們需要在業(yè)務(wù)應(yīng)用邏輯中使用阿里云資源時(shí),通常需要通過(guò)角色扮演的方式獲取一個(gè)RAM返回的臨時(shí)憑證,然后通過(guò)這個(gè)臨時(shí)憑證完成與RAM的鑒權(quán)過(guò)程。由于憑證的時(shí)效性,我們?cè)诒WC其安全性的同時(shí)還要維護(hù)一個(gè)對(duì)應(yīng)的秘鑰輪轉(zhuǎn)機(jī)制。Vault的secret引擎實(shí)現(xiàn)了與阿里云RAM的對(duì)接插件,幫助我們安全、動(dòng)態(tài)的管理RAM憑證,其主要步驟 如下:
1.開(kāi)啟后端引擎
2.在RAM控制臺(tái)為Vault服務(wù)器創(chuàng)建專屬子賬號(hào)并綁定定制化權(quán)限策略
3.獲取Vault子賬號(hào)對(duì)應(yīng)的AK并通過(guò)Vault CLI/API寫(xiě)入到后端指定路徑下
4.在Vault后端寫(xiě)入業(yè)務(wù)中希望獲取的RAM憑證所對(duì)應(yīng)的策略定義或角色,其中策略定義支持inline和remote策略兩種形式,所謂inline模式是指直接在api請(qǐng)求中寫(xiě)入策略模板,remote模式指寫(xiě)入RAM中存在的策略類型和名稱,比如:
$?vault?write?alicloud/role/policy-based? ????remote_policies='name:AliyunOSSReadOnlyAccess,type:System'? ????remote_policies='name:AliyunRDSReadOnlyAccess,type:System'
角色模式需要用戶指定希望被扮演的角色arn,另外需要Vault子賬號(hào)在該角色的受信實(shí)體里,一個(gè)示例如下:
$?vault?write?alibaba/role/role-based? role_arn='acs:ram::5138828231865461:role/hastrustedactors'
5.在具體的業(yè)務(wù)應(yīng)用中,只需要通過(guò)調(diào)用Vault的creds/policy-based或role-based接口即可動(dòng)態(tài)獲取相應(yīng)的RAM訪問(wèn)憑證,下面是一個(gè)角色扮演返回臨時(shí)token的CLI調(diào)用示例:
$?vault?read?alicloud/creds/role-based Key????????????????Value ---????????????????----- lease_id???????????alicloud/creds/role-based/f3e92392-7d9c-09c8-c921-575d62fe80d9 lease_duration?????59m59s lease_renewable????false access_key?????????STS.L4aBSCSJVMuKg5U1vFDw secret_key?????????wyLTSmsyPGP1ohvvw8xYgB29dlGI8KMiH2pKCNZ9 security_token?????CAESrAIIARKAAShQquMnLIlbvEcIxO6wCoqJufs8sWwieUxu45hS9AvKNEte8KRUWiJWJ6Y+YHAPgNwi7yfRecMFydL2uPOgBI7LDio0RkbYLmJfIxHM2nGBPdml7kYEOXmJp2aDhbvvwVYIyt/8iES/R6N208wQh0Pk2bu+/9dvalp6wOHF4gkFGhhTVFMuTDRhQlNDU0pWTXVLZzVVMXZGRHciBTQzMjc0KgVhbGljZTCpnJjwySk6BlJzYU1ENUJuCgExGmkKBUFsbG93Eh8KDEFjdGlvbkVxdWFscxIGQWN0aW9uGgcKBW9zczoqEj8KDlJlc291cmNlRXF1YWxzEghSZXNvdXJjZRojCiFhY3M6b3NzOio6NDMyNzQ6c2FtcGxlYm94L2FsaWNlLyo= expiration?????????2018-08-15T21:58:00Z
如何在k8s應(yīng)用中使用Vault Secret
在了解了Vault的基本概念以及與Kubernetes的認(rèn)證交互流程后,我們進(jìn)入客戶最為關(guān)心的話題。如何在k8s pod應(yīng)用中方便地獲取Vault服務(wù)端管理的secret。社區(qū)針對(duì)此問(wèn)題也有激烈的討論和不少相關(guān)解決方案,方案主要集中在兩個(gè)方向:
**[定時(shí)同步進(jìn)程](https://github.com/hashicorp/vault/issues/7364)**:使用一個(gè)同步進(jìn)程定時(shí)地從Vault服務(wù)端獲取指定范圍的秘鑰更新并同步到k8s集群中的secret模型,代表的項(xiàng)目有vaultingkube 和[secrets-manager]( https://github.com/tuenti/secrets-manager) 。其主要設(shè)計(jì)思想也不盡相同,以secrets-manager為例,首先用戶可以通過(guò)CRD定義在Vault中關(guān)注的secret數(shù)據(jù)源,然后secrets-manager對(duì)應(yīng)的controller會(huì)在Reconcile函數(shù)中定時(shí)對(duì)比指定管理范圍內(nèi)的k8s secret和vault secret的狀態(tài),如果不一致則進(jìn)行一次調(diào)協(xié)。而用戶在pod應(yīng)用中可以直接引用原生secret模型中的內(nèi)容獲取遠(yuǎn)端Vault服務(wù)器中的秘鑰。 當(dāng)然社區(qū)中也存在一些對(duì)這種秘鑰同步方案的質(zhì)疑,比如認(rèn)為該方案在秘鑰同步的傳輸過(guò)程和用戶pod使用原生secret的rest交互中會(huì)增加攻擊面,但是該方案在部署實(shí)施上比較友好,也得到了很多用戶的支持。
CSI插件形式集成:該方案基于CSI plugin將Vault中的秘鑰通過(guò)volume的形式掛載到pod應(yīng)用中。secrets-store-csi-driver 通過(guò)實(shí)現(xiàn)一套基于CSI規(guī)范的driver機(jī)制可以對(duì)接不同廠商的后端存儲(chǔ),而Vault secret的driver(secrets-store.csi.k8s.com)允許kubelet將各類企業(yè)級(jí)秘鑰存儲(chǔ)中的secret通過(guò)volume掛載,一旦attach動(dòng)作完成,秘鑰數(shù)據(jù)即掛載到了容器對(duì)應(yīng)的文件系統(tǒng)中。在CSI driver的基礎(chǔ)上,不同的秘鑰管理后端可以實(shí)現(xiàn)定制化的provider去對(duì)接CSI driver框架中的規(guī)定接口。provider的功能概括如下:
對(duì)接后端秘鑰管理系統(tǒng),提供秘鑰獲取等必須的接口實(shí)現(xiàn)
適配當(dāng)前CSI driver的接口定義
通過(guò)框架中的回調(diào)函數(shù)無(wú)需調(diào)用Kubernetes API即可將從后端獲取的秘鑰數(shù)據(jù)掛載到指定路徑下
HashiCorp官方也基于此框架實(shí)現(xiàn)了一套對(duì)接Vault的Provider。這里我們以此為例具體來(lái)看下在一個(gè)k8s pod應(yīng)用中如何通過(guò)CSI plugin的方式使用Vault中管理的secret秘鑰。
1 首先我們創(chuàng)建一個(gè)開(kāi)啟了CSI存儲(chǔ)插件的ACK集群,然后參考文檔在集群中部署Vault服務(wù)端,為了便于驗(yàn)證這里我們使用dev模式省去unseal解封等流程,同時(shí)配置provider與Vault交互的認(rèn)證模式和相應(yīng)的訪問(wèn)控制策略
然后通過(guò)cli向Vault后端寫(xiě)入測(cè)試數(shù)據(jù)
2 通過(guò)官方提供的helm方式安裝Secret Store CSI Driver,命令如下:
helm?install?.?-n?csi-secrets-store?--namespace?dev?--set?providers.vault.enabled=true
安裝成功后如下圖所示:
3 在集群中創(chuàng)建secretproviderclasses實(shí)例用于Secret Store CSI Driver與Vault的參數(shù)對(duì)接,一個(gè)示例如下,注意這里的vault服務(wù)端地址可通過(guò)kubectl get service vault獲取。
4 最后我們來(lái)看下如何在應(yīng)用pod中對(duì)接上述provider實(shí)例獲取對(duì)應(yīng)的Vault秘鑰。這里pod對(duì)于上述vault provider的使用分為兩種方式:
1)如果pod運(yùn)行的目標(biāo)集群版本在v1.15.0以上,且集群apiserver和節(jié)點(diǎn)kubelet manifest配置均開(kāi)啟了 CSIInlineVolume=true的feature-gates,則我們可以在pod中的volume字段內(nèi)置聲明需要使用的csi provider實(shí)例。
kind:?Pod apiVersion:?v1 metadata: ??name:?nginx-secrets-store-inline spec: ??containers: ??-?image:?nginx ????name:?nginx ????volumeMounts: ????-?name:?secrets-store-inline ??????mountPath:?"/mnt/secrets-store" ??????readOnly:?true ??volumes: ????-?name:?secrets-store-inline ??????csi: ????????driver:?secrets-store.csi.k8s.com ????????readOnly:?true ????????volumeAttributes: ??????????secretProviderClass:?"vault-foo"
2)如果目標(biāo)集群不支持CSI的Inline Volume特性,我們需要首先創(chuàng)建使用csi的pv和對(duì)應(yīng)的pvc實(shí)例,一個(gè)pv模板示例如下:
apiVersion:?v1 kind:?PersistentVolume metadata: ??name:?pv-vault spec: ??capacity: ????storage:?1Gi ??accessModes: ????-?ReadOnlyMany ??persistentVolumeReclaimPolicy:?Retain ??csi: ????driver:?secrets-store.csi.k8s.com ????readOnly:?true ????volumeHandle:?kv ????volumeAttributes: ??????providerName:?"vault" ??????roleName:?"example-role" ??????vaultAddress:?http://172.21.12.21:8200 ??????vaultSkipTLSVerify:?"true" ??????objects:??| ????????array: ??????????-?| ????????????objectPath:?"/foo" ????????????objectName:?"bar" ????????????objectVersion:?""
在pod實(shí)例模板中引用指定pvc即可在pod中獲取到vault,這里我們?cè)贏CK集群以pv/pvc模式為例創(chuàng)建一個(gè)nginx應(yīng)用容器實(shí)例并在其中掛載上文中我們創(chuàng)建的secretproviderclasses實(shí)例:
相比于secrets-manager等采用secret定時(shí)同步的方式,使用CSI對(duì)接指定Vault secret provider實(shí)例的方式雖然在實(shí)施步驟上比較復(fù)雜,同時(shí)在應(yīng)用中也無(wú)法動(dòng)態(tài)獲取Vault后端secret的變更,但是該方案避免了secret在同步鏈路上頻繁傳輸?shù)陌踩L(fēng)險(xiǎn),同時(shí)也客服了之前describe po可能造成的秘鑰泄露,在整體安全性上要高出不少。大家可以根據(jù)實(shí)際應(yīng)用場(chǎng)景選擇適合自己的方式。
評(píng)論