使用加密插件加密secrets中的數(shù)據(jù)

眾所周知,kubernetes中提供了一種名為secrets的對象,用于存放集群內(nèi)部使用的各類敏感數(shù)據(jù),比如數(shù)據(jù)庫用戶名、密碼、各種token、證書等等,從而使得敏感信息和普通配置文件有效解耦。但是默認(rèn)情況下secrets信息在etcd中是以base64編碼形式保存的明文,本篇文章說明如何通過插件加密存儲機密數(shù)據(jù)。

加密插件配置

總體來說配置比較簡單,跟著官網(wǎng)的說明做就ok。官方連接:https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/。這里面值得注意的是,kube-apisever的加密插件配置參數(shù)為--encryption-provider-config,在1.13版本之前是--experimental-encryption-provider-config,該參數(shù)在1.14版本之后已經(jīng)被正式廢棄。

配置文件示例:

apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources:
    - secrets
    providers:
    - identity: {}
    - aesgcm:
        keys:
        - name: key1
          secret: c2VjcmV0IGlzIHNlY3VyZQ==
        - name: key2
          secret: dGhpcyBpcyBwYXNzd29yZA==
    - aescbc:
        keys:
        - name: key1
          secret: c2VjcmV0IGlzIHNlY3VyZQ==
        - name: key2
          secret: dGhpcyBpcyBwYXNzd29yZA==
    - secretbox:
        keys:
        - name: key1
          secret: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY=

其中resources可以是多組獨立的配置,每組配置下定義了該組資源的加解密的策略,比如這個配置文件定義了secrets資源的加解密策略。providers定義了加解密的實際提供者,目前k8支持的provider如下所示:

名稱 加密類型 強度 速度 密鑰長度 其它事項
identity N/A N/A N/A 不加密寫入的資源。當(dāng)設(shè)置為第一個 provider 時,資源將在新值寫入時被解密。
aescbc 填充 PKCS#7 的 AES-CBC 最強 32字節(jié) 建議使用的加密項,但可能比 secretbox 稍微慢一些。
secretbox XSalsa20 和 Poly1305 更快 32字節(jié) 較新的標(biāo)準(zhǔn),在需要高度評審的環(huán)境中可能不被接受。
aesgcm 帶有隨機數(shù)的 AES-GCM 必須每 200k 寫入一次 最快 16, 24, 或者 32字節(jié) 建議不要使用,除非實施了自動密鑰循環(huán)方案。
kms 使用信封加密方案:數(shù)據(jù)使用帶有 PKCS#7 填充的 AES-CBC 通過 data encryption keys(DEK)加密,DEK 根據(jù) Key Management Service(KMS)中的配置通過 key encryption keys(KEK)加密 最強 32字節(jié) 建議使用第三方工具進行密鑰管理。為每個加密生成新的 DEK,并由用戶控制 KEK 輪換來簡化密鑰輪換。配置 KMS 提供程序

其中identity就是明文,不加密。其余就是各類加解密算法,建議使用aescbc,足夠用了,其實就是使用CBC模式、PKCS#7填充的aes256加密。這里要注意的是,providers中可以設(shè)置多個加密provider,每個provider可以設(shè)置多個加密的密鑰。

加解密規(guī)則

  • 加密:kube-apiserver默認(rèn)會使用第一個provider的第一個key進行加密(上面這個例子里面就是明文不加密了)
  • 解密:會依次嘗試所有的解密算法,每個算法中會依次嘗試所有的key,如果全部嘗試失敗,則會返回一個錯誤,以阻止客戶端訪問該資源。這么設(shè)置的原因,當(dāng)然也是因為一旦你更換了加密密鑰(或者加密算法),還能保證你原來用老的密鑰(算法)加密的數(shù)據(jù)還可以正常的訪問(加密插件會按照有序列表中的定義挨個嘗試)。

kube-apiserver配置

到這里按照常規(guī)流程你一定想kubectl create -f來創(chuàng)建這個資源了,如果你這么做了,不出意外的話會看到如下的報錯:

error: unable to recognize "encrypt.conf": no matches for kind "EncryptionConfiguration" in version "apiserver.config.k8s.io/v1"

這是因為,kube-apiserver的相關(guān)資源,是不能通過kubectl命令來創(chuàng)建的,官方文檔并沒有明確說明,其實也很好理解,自己怎么創(chuàng)建自己嘛!這個資源,只能是通過配置啟動參數(shù)在kube-apisever啟動的時候來加載。這邊我使用kubeadm安裝的集群,配置文件位置在/etc/kubernetes/manifests,找到kube-apiserver.yaml,這個就是kube-apiserver啟動用的配置文件(用其他方式安裝的也類似,只要找到這個配置文件就可以)。所以說這個加密插件的啟動,目前來說貌似只能在私有集群中實現(xiàn),如果你用的是gke、ake、tke這樣的云服務(wù)商提供的集群就不行了。

tips: kube-apiserver這個pod和普通pod不同,是一個靜態(tài)pod(static pod),也就是直接啟動在特定的node上,由該宿主機的kubelet直接控制。pod不會漂移,配置文件也在宿主機上面,kubelet在啟動時,通過讀取/etc/kubernetes/manifests里面的配置信息,直接拉起pod。事實上如果你使用kubeadm,則會安裝4個靜態(tài)pod,分別是etcd、kube-apiserver、kube-scheduler、kube-controller-manager。不難看出這些就是保障k8集群正常運作的核心組件,其他插件諸如core-dns、kube-proxy、calico等都是以daemonset或者deployment形式運行的普通pod。在修改了/etc/kubernetes/manifests里的配置信息后,kubelet會自動重啟該靜態(tài)pod。

我們在這個配置文件中加入如下信息:

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    component: kube-apiserver
    tier: control-plane
  name: kube-apiserver
  namespace: kube-system
spec:
  containers:
  - command:
    - kube-apiserver
    - --encryption-provider-config=/etc/kubernetes/pki/encrypt.conf
    - --advertise-address=192.168.31.241
    - --allow-privileged=true
    - --authorization-mode=Node,RBAC
.....

其中encryption-provider-config就是配置插件插件啟動時讀取的配置文件所在位置,這邊我們把前面寫的配置文件命名為encrypt.conf,放在/etc/kubernetes/pki目錄下,通過閱讀配置文件,我們可以看到kube-apiserver在啟動的時候會掛載三個宿主機目錄,其中就有/etc/kubernetes/pki。所以你把配置文件放在這里,kube-apiserver啟動的時候就能正確找到這個配置文件了。

加密功能驗證

kube-apisever重啟后,我們就可以嘗試一下,看看加密功能是否生效。這里我們用到的配置文件如下:

kind: EncryptionConfiguration
apiVersion: apiserver.config.k8s.io/v1
resources:
  - resources:
    - secrets
    providers:
    - aescbc:
        keys:
        - name: key1
          secret: SSM5rRRrQ9+8MsA2cHeRfb7KG9rvF/wsqHOgoQAv5bM=
    - identity: {}

這個配置保證了我們新建的secrets資源都會默認(rèn)使用aescbc加密算法,并且使用key1中定義的這個密鑰來加密數(shù)據(jù)。注意identity這個參數(shù)必須要設(shè)置,否則所有我們之前建立的secrets都會無法訪問。具體原因其實上面已經(jīng)講過,大家可以想一下為什么。

現(xiàn)在我們來新建一個serctes資源來驗證一下

kubectl create secret generic secret1 -n default --from-literal=mykey=mydata

之后登陸入容器etcd中

kubectl exec -it etcd-miwifi-r1cm-srv -n kube-system /bin/sh

執(zhí)行etcdctl命令查看剛才建立的secret1密鑰的內(nèi)容,這里要注意的是etcd默認(rèn)的api版本是v2,k8默認(rèn)使用的版本是v3,兩者互不兼容,所以在執(zhí)行的時候需要在命令前顯式的加上ETCDCTL_API=3來告訴etcdctl我要調(diào)用的是v3 api,或者使用環(huán)境變量export指定也可以。由于v3默認(rèn)開啟了ssl認(rèn)證,所以在調(diào)用的時候還需要加上連接認(rèn)證信息,這部分內(nèi)容可以在etcd.yamllivenessProbe這個配置中查看到,把這條命令復(fù)制出來,后面加上secret1的路徑,就可以查看到secret內(nèi)容了

/ # ETCDCTL_API=3 etcdctl --endpoints=https://[127.0.0.1]:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt --key=/etc/kubernetes/pki/etcd/healthcheck-client.key get /registry/secrets/default/secret1  | hexdump -C
00000000  2f 72 65 67 69 73 74 72  79 2f 73 65 63 72 65 74  |/registry/secret|
00000010  73 2f 64 65 66 61 75 6c  74 2f 73 65 63 72 65 74  |s/default/secret|
00000020  31 0a 6b 38 73 3a 65 6e  63 3a 61 65 73 63 62 63  |1.k8s:enc:aescbc|
00000030  3a 76 31 3a 6b 65 79 31  3a d5 62 9c a5 45 d3 76  |:v1:key1:.b..E.v|
00000040  50 b5 4f 44 66 22 a6 37  2d 95 87 e9 93 65 72 a4  |P.ODf".7-....er.|
00000050  2d 97 b1 b6 44 b0 8e 7c  27 ba 99 61 86 56 a7 97  |-...D..|'..a.V..|
00000060  21 03 eb 46 93 a9 ba f7  c1 63 fe 5c 34 12 9d 54  |!..F.....c.\4..T|
00000070  ba 3e 73 d5 71 b4 b9 28  ac 0e 66 6e a2 09 44 48  |.>s.q..(..fn..DH|
00000080  cf c6 da 4a 24 6d 49 06  dd f4 e6 85 ff ab e0 e3  |...J$mI.........|
00000090  ed 59 07 98 c2 3e 33 9e  91 f7 9a 9e d1 7f db 65  |.Y...>3........e|
000000a0  f8 60 40 2d 7c 86 1a f2  8b 37 67 c8 83 d3 5e 7b  |.`@-|....7g...^{|
000000b0  fa 51 35 f1 ee d7 51 28  81 a3 9b bd 6d 80 bb e7  |.Q5...Q(....m...|
000000c0  b8 0e 4b 85 0e 90 f3 50  41 0a                    |..K....PA.|

注意在數(shù)據(jù)頭部出現(xiàn)k8s:enc:aescbc:v1:,說明數(shù)據(jù)已經(jīng)被正確加密,使用的是aescbc算法,使用的密鑰為key1

接下來我們看下kube-apiserver在讀取的時候是否正確解密了,執(zhí)行下面的命令

[root@MiWiFi-R1CM-srv manifests]# kubectl get secrets secret1 -o yaml
apiVersion: v1
data:
  mykey: bXlkYXRh
kind: Secret
metadata:
  creationTimestamp: "2019-08-16T15:12:14Z"
  name: secret1
  namespace: default
  resourceVersion: "549592"
  selfLink: /api/v1/namespaces/default/secrets/secret1
  uid: 3a74e0fd-c038-11e9-95ca-0800279f163b
type: Opaque

得到mykey的base64編碼數(shù)據(jù)bXlkYXRh,將其decode一下

[root@MiWiFi-R1CM-srv manifests]# echo -n "bXlkYXRh" | base64 --decode
mydata

沒錯,正是我們設(shè)置的sercets機密數(shù)據(jù),試驗成功!

總結(jié)

通過kubernetes提供的加密插件,使得etcd中存放的secrets數(shù)據(jù)都以密文的形式存放,這無異大大提高了數(shù)據(jù)安全性。但是要明確一點,加密插件只是加密了etcd中保存的數(shù)據(jù),這意味著你執(zhí)行kubectl get secrets mysecret -o yaml這樣的命令看到的仍然是明文,在容器內(nèi)部注入的secrets文件或者環(huán)境變量看到的也是明文,原因當(dāng)然是kube-apiserver在從etcd中取出數(shù)據(jù)的時候已經(jīng)幫你自動解密了。如果你有全程加密的需求(比如說想在容器內(nèi)看到的也是密文),這顯然是kubernetes這種平臺層的工具做不到的,因為這已經(jīng)涉及到了應(yīng)用的改造。

其實就目前的實際使用場景看,如果你有將etcd直接暴露給集群內(nèi)第三方服務(wù)使用或者直接暴露給外部服務(wù)使用的需求(一般非常少),那么你最好使用加密插件,否則會面臨機密數(shù)據(jù)泄漏的風(fēng)險。而如果etcd僅供k8s的系統(tǒng)組件來使用的話,由于kubernetes本身已經(jīng)有比較完善的rbac機制,那么你只要做好kube-apiserver的權(quán)限管理即可,例如:

  • etcd啟用安全連接機制,嚴(yán)格禁止非系統(tǒng)組件的直接訪問
  • kubectl客戶端工具只能在master節(jié)點上由系統(tǒng)管理員操作
  • 各服務(wù)內(nèi)的serviceaccount做好權(quán)限管理,禁止直接訪問secrets資源

那么其實也未必需要加密,k8s默認(rèn)提供的secrets策略已經(jīng)完全能夠滿足要求(畢竟你即使在etcd中加密了,有kubectl權(quán)限的和有訪問secrets權(quán)限的賬號還是可以看到明文)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,250評論 6 530
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 97,923評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,041評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,475評論 1 308
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,253評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,801評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,882評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,023評論 0 285
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,530評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,494評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,639評論 1 366
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,177評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 43,890評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,289評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,552評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,242評論 3 389
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,626評論 2 370

推薦閱讀更多精彩內(nèi)容