一個(gè)可運(yùn)行的軟件項(xiàng)目通常包括兩個(gè)要素:代碼和密鑰醒串。我們通常會使用無版本控制的FTP和有版本控制的SVN、git等成熟的工具進(jìn)行代碼管理家厌;而在我參加的大大小小、許許多多的項(xiàng)目中椎工,密鑰管理似乎缺乏成熟或標(biāo)準(zhǔn)的實(shí)踐饭于。本文將歷數(shù)一下筆者在各個(gè)使用過的密鑰管理實(shí)踐并分析他們的優(yōu)缺點(diǎn)。最后給大家推薦一款密鑰管理工具:vault维蒙。
在軟件項(xiàng)目開發(fā)中掰吕,密鑰常常應(yīng)用于下面四個(gè)場景:
- 本地開發(fā):通常包括開發(fā)環(huán)境的數(shù)據(jù)庫密碼、用于訪問第三方API的token颅痊、一些私有程序包倉庫的憑證等殖熟。
- CICD流水線:比如Push Docker鏡像的Docker倉庫的訪問憑證、用于部署的云服務(wù)憑證(AWS Secret等)斑响、用于訪問K8S集群的token等
- 運(yùn)行線上服務(wù):線上服務(wù)啟動(dòng)所需的數(shù)據(jù)庫密碼菱属、API Token等等,同時(shí)可能需要管理用于多套環(huán)境的不同密鑰舰罚。
- 線上運(yùn)維:線上發(fā)生事故時(shí)纽门,需要在本地登入堡壘機(jī)(跳板機(jī))的SSH Key或集群的訪問憑證。
本地開發(fā):“薪火相傳”的密鑰文件
當(dāng)我們加入一個(gè)團(tuán)隊(duì)時(shí)营罢,通常會有一個(gè)Readme文檔告訴你項(xiàng)目代碼庫的下載鏈接赏陵。除此之外它會告訴你需要向團(tuán)隊(duì)“前輩”索要密鑰文件,不然你的代碼是不能在本地啟動(dòng)的饲漾。同時(shí)有人告訴你瘟滨,這個(gè)密鑰文件千萬不要加入到git倉庫中。
這種“薪火相傳”的密鑰管理方式能颁,是最原始也是最常見的方式。它常常會伴隨這樣幾個(gè)問題:
- 密鑰更換或者引入新的密鑰后倒淫,團(tuán)隊(duì)其它成員因?yàn)闆]有得到最新的密鑰文件伙菊,導(dǎo)致服務(wù)在本地起不來。
比如你會聽到這樣的對話:
- A: “我拉了一下最近的代碼,怎么就跑不起來了镜硕?”
- 坐在旁邊的B突然想起了什么:“好吧运翼,我想起來了!我改了一下數(shù)據(jù)庫密碼兴枯,忘記告訴你了血淌,我把最新的密鑰發(fā)給你〔破剩”或者“我新加了一個(gè)功能因?yàn)槭褂肁PI-KEY要訪問消息隊(duì)列悠夯,我在自己本地的環(huán)境變量里面加上了這個(gè)KEY,忘記告訴你們了”
- 隨后B把最新的密鑰文件傳給了A躺坟。幾天后沦补,同在項(xiàng)目的C也遇到了同樣的問題……
- 誤提交到代碼倉庫問題:
相信已經(jīng)不止一次地聽人提醒:千萬不要將密鑰文件明文提交到git。但是密鑰泄露在代碼倉庫的問題依舊時(shí)有發(fā)生咪橙。
本地開發(fā):將密鑰加密后存放在Git倉庫
密鑰和代碼一樣夕膀,在團(tuán)隊(duì)項(xiàng)目中同樣需要進(jìn)行共享、同步美侦。密鑰放在git倉庫中本來是可以解決團(tuán)隊(duì)協(xié)作問題的产舞,只不是不能被明文存儲。那么菠剩,如果是將密鑰加密后再提交到git倉庫呢易猫?
git-crypt便是這樣一款可將git倉庫中的密鑰文件進(jìn)行透明加密和解密的工具。它可以將密鑰文件在push時(shí)加密赠叼,在pull下來后解密擦囊。更多介紹和使用說明可以參考:https://github.com/AGWA/git-crypt。
借助git版本控制工具嘴办,它可以實(shí)現(xiàn):
- 使用git進(jìn)行密碼共享
- 密鑰的版本控制
- 用戶權(quán)限管理
問題:
- 密碼可能在多個(gè)服務(wù)中使用瞬场,怎么同步?
持續(xù)集成流水線中的密鑰管理
在現(xiàn)在的Web項(xiàng)目的CI/CD流程中涧郊,通常會將項(xiàng)目代碼經(jīng)過構(gòu)建打包生成docker鏡像(制品)贯被;在部署階段,不同環(huán)境會采用相同的docker鏡像妆艘,但是會使用不同的環(huán)境變量(比如集群彤灶、域名、數(shù)據(jù)庫地址密碼等)傳入到docker的運(yùn)行時(shí)批旺,從而完成在不同環(huán)境的部署幌陕。
環(huán)境(變量)在不同的CI/CD中有不同形式,比如的Jenkins的Credential汽煮、GoCD的Environment搏熄、CircleCI的Context棚唆。
如果將所有的部署與運(yùn)行時(shí)所需要的密鑰數(shù)據(jù)都保存到pipeline上,會導(dǎo)致下面的問題
- 過多的密碼字段心例,將密碼作為環(huán)境變量一個(gè)個(gè)傳遞到服務(wù)十分復(fù)雜
- pipeline存環(huán)境變量一般加密后難以解密宵凌,如果你設(shè)置完自己都忘記了,那這個(gè)環(huán)境就徹底忘了
解決的辦法一般是在pipeline上保存盡量少的密鑰字段止后,我們通過一次認(rèn)證就可以具備獲取所有密鑰數(shù)據(jù)的權(quán)限瞎惫。
密碼即服務(wù):Hashicorp Vault
在云和基礎(chǔ)設(shè)施自動(dòng)化時(shí)代,我們應(yīng)該知道一家名為Hashcorp的公司译株,其代表作有知名的terraform瓜喇、consul、packer古戴、vagrant欠橘。vault也是這家公司的產(chǎn)品之一,它通過API將密碼以服務(wù)的方式暴露出去现恼。它可以提供:
- 中心化的密碼服務(wù)
- 更安全的加密存儲
- 密碼的服務(wù)化
- 豐富的第三方集成:實(shí)現(xiàn)認(rèn)證的擴(kuò)展肃续、多平臺密鑰管理
服務(wù)化后的vault可以做到
- 與Github身份認(rèn)證集成,比如你可以做到只允許在特定git organization下的用戶才能獲取密鑰
- 簽發(fā)臨時(shí)的SSH證書:比如你只允許一個(gè)30分鐘內(nèi)有效的SSH KEY來登錄堡壘機(jī)
- 生成臨時(shí)的AWS KEY:比如你只能用一個(gè)30分鐘內(nèi)有效的AWS憑證
- 定期更換數(shù)據(jù)庫密碼叉袍,因?yàn)閿?shù)據(jù)庫長期不更換會加大泄露的風(fēng)險(xiǎn)
- OTP:基于時(shí)間的臨時(shí)密碼
- 密碼權(quán)限策略:只允許特定的微服務(wù)讀取或者寫入指定的密鑰
- 密碼的revoke(同事下項(xiàng)目了怎么辦始锚?)
項(xiàng)目實(shí)踐
- 不在本地持久化存儲密鑰,每次獲取密鑰應(yīng)該通過腳本實(shí)時(shí)獲取并保存在console的會話級的環(huán)境變量里喳逛。
- 密鑰是有時(shí)效瞧捌,定期輪換
- 密鑰獲取者是有身份的