Kubernetes 已經毫無爭議地成爲了雲原生時代的事實標準,在 Kubernetes 上部署應用程序也變得簡單起來(不管是採用 kustomize 仍是 helm),雖然對於敏感信息(好比用戶名、密碼、token 和證書等)的處理,Kubernetes 本身提供了 secret 這種方式,但其是一種編碼方式,而非加密方式,若是須要用版本控制系統(好比 git)來對全部的文件、內容等進行版本控制時,這種用編碼來處理敏感信息的方式就顯得很不安全了(即便是採用私有庫),這一點在實現 GitOps 時,是一個痛點。git
基於此,本文就介紹三種能夠加密 Kubernetes secret 的方式:Sealed Secrets、Helm Secrets 和 Kamus。github
Sealed Secrets 充分利用 kuberntes 的高擴展性,經過 CRD 來建立一個 SealedSecret 對象,經過將加密的內容存儲在擴展 SealedSecret 對象中,而 SealedSecret 只可以被運行於目標集羣上的 controller 解密,其餘人員和方式都沒法正確解密原始數據。SealedSecret 對象同時又會生成與其名稱相同的 secret 對象,隨後就能夠按照常規方式使用 secret 對象了。最後將加密後的文件直接推送至版本控制系統便可,而不用擔憂敏感信息被泄漏。redis
Sealed Secrets 加解密的原理簡單來講就是:安裝的時候 controller 會生成一對用於加密的 key,加密時在客戶端 kubeseal 的幫助下,將包含敏感信息的 kubernets secrets 內容加密轉變爲一個包含有加密信息的 Kubernetes SealedSecrets 對象;解密時在 controller 的幫助下將 Kubernetes SealedSecrets 對象內的內容進行解密,而後生成常規的 kubernetes secret 對象。docker
下面分加解密兩部分(encryption 和 decryption)來介紹 Sealed Secrerts 的工做原理。數據庫
kubeseal 使用位於 cluster controller 生成的 public key 來加密,將 secrets 對象的內容加密轉變成 SealedSecrets 對象。public key 和 private key 在安裝 controller 的時候,以 secret(以下的 sealed-secrets-key217vf)的造成存放,能夠在安裝 controller 所在的 ns 下面查看。npm
$ kubectl -n kube-system get secret | grep sealed-secret sealed-secrets-controller-token-qv2n5 kubernetes.io/service-account-token 3 6d4h sealed-secrets-key2l7vf kubernetes.io/tls 2 6d4h
當將加密後生成的 SealedSecrets 對象進行部署時(kubectl apply/create),controller 會先拿 private key 進行解密,而後再生成與 SealedSecrets 同名的 Secret 對象,而此時的 Secret 對象保存的是通過 base64 編碼後的信息,隨後能夠像正常使用 secret 同樣使用這些信息。json
SealedSecrets 和 Secret 二者的關係與 Deployment 和 Pod 之間的關係相似。
Sealed Secrets 有兩部分組成:segmentfault
因此安裝也分兩步,安裝 controller 和 kubeseal。能夠先安裝 controller,執行以下命令便可:api
$ kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.14.1/controller.yaml
隨後查看 kube-system ns 下面的 controller pod:安全
$ kubectl -n kube-system get pods | grep seal sealed-secrets-controller-64b74f67b-4wtj7 1/1 Running 0 153m
接着安裝客戶端工具 kubeseal。這個能夠根據本身的 OS 來選用不一樣的安裝方式,以 MacOs 爲例:
$ brew install kubeseal
經過查看 kubeseal 的版原本肯定是否安裝成功:
$ kubeseal --version kubeseal version: v0.14.1
此時,兩部分均安裝成功,下面可使用了。
選擇一個包含有須要加密的 secret 的文件,內容以下:
apiVersion: v1 data: username: eGlhb21hZ2U= password: cGFzc3cwcmQ= token: MWU0ZGdyNWZncmgzcmZmZ3JodG9ubmhyaHI= kind: Secret metadata: name: seal-test-secret namespace: test type: Opaque
將上述內容寫入一個 yaml 文件,好比 test-secret.yaml,而後執行以下命令加密:
$ kubeseal < test-secret.yaml > test-seal-secret.yaml
能夠查看 test-seal-secret.yaml 文件的內容:
{ "kind": "SealedSecret", "apiVersion": "bitnami.com/v1alpha1", "metadata": { "name": "seal-test-secret", "namespace": "test", "creationTimestamp": null }, "spec": { "template": { "metadata": { "name": "seal-test-secret", "namespace": "test", "creationTimestamp": null }, "type": "Opaque" }, "encryptedData": { "password": "AgCHLFSlGFpX2B9QDhWbMTfT83aopXMisR5XnUPZNcbvvnQzqgyG8fBVknT8LCNF5ExtUCCcNLsvWRrZY+9BJqf5dlBl6DkLV1acuPicP0vuGaUQwmc5BY/5Bj53Oj9uMYLNdVHoQ3E6kQgeJPa5v4rvwRXsB0EneYPcT88KyMg+tn4OY9JH+hpg2XMXZudyyZsocE852J5nfN4P7WZQYaG2eIBqRSQvQXUflQQvZ5wBCkTvmaZYfxz+Lxuf3wDWdSlPjcgSVnn5tWNP7u0ErdVy8LwTL5HzJdcoSviDysTq3VVA8W9Nmn0CM3QS0R0Nbi3JfalUdxfBMK+yb7t6Z72oJyoxGfCa07iKnkM37SSw4vl1nXiYy3FMWuzDtWLVk6XzjBZR2ChoeClqbGDg8KeSWZg/rO3Xku98vCmCa004OetJKBMc9Db3q+gX53ThdU70VvRol9rLPFBPHB8NTjD+Bu0Ss4XzIzZzi8J+Ov5xE7G8LnPLSZtZQyD/qGZK4n7pU1YNLROJ+fz1W5edPdpb5szUOqs1bpFfGleUiPZo1sGA0f1EsDvJShptgtT44YzGRkkgrP1LGp2AVIpnt9meE5WNCoSEPZJVx7wWMV9CHMOyyUi8zi+oG/S2NkI3rc2sC8AFp0DqP9m/HaX1GG+6vw9oHAbhxpR4v3mDyBIq+/8UEMtkybIEDQGHqyQ5CfRow+A80cA4Hw==", "token": "AgBRi4NZunaJtHyP5aAoWmGtEXBipbFIb/n4ep8wdg+eka5xbDeLZwNCLofbUL+u0pP/CHSJeWl62mVPJhZdOKE+Su0b8a78im0+xsochaMQf0AI1GGL/Fo08HI8paP8k404gwAtonocIFSis3YooU0nyVD+lYH+k09FGABI+RmVLc2XkuIr96TTL4xsdSM5L0Ks2SFQKcQ42JfFWtNdXz6lr/IODsZop0/xAk6ffbsGGmCUjwusUU3Wp0MR25ntYT8ySuO6W7xkfGozEFzztteBJs28SHLf5HUi6BbYVnsZibrFF3BZP5aNnBg2TIgo3+dbX6EPHM904By3Z9XTBxsQfH6p1VoyUf0EGKZnUnJFezFtN9m2tyKbV/Z/5vCh9kVp6Yn/BE/AwGAH7kqqjPtHTnZiq+Xy1UwV4/eHkxGAvSAR3Z6wTQCt/rwqGrQi2eGpIcyjxTwlPYaVjfx3L+1tnBR966lGLnhwX0I6b6whXAm3hRb1AhYFnuyF/CoG/PEmQsMU5GfkroQkb5LL+UeCYKbjvMvgCe2hFxfh3dcGJ9E3dad9W0rSKrPd5t/dR1kDtItHau36+G9PSVyqRD1yt0MS2vLLUQu7t2RhiIPrl20fkbnum9JAfmLlgliHIiQPHASL32CXB6EzsgqRX6w8TmWNOSvlR7LU8JZtd4Gmiw9wGBh7JEGodkaH6lc5ndQluykC18RUXtuLft+S4dnQCApHX6FoIGZjug==", "username": "AgCgBQc/fhGqB0YBGfXzhybC6YXJeLkOZyi7Z7Y+HjfnYSg4Q/Zh8Kn7UEbq9CwEl+CtagARjKmLfhIcAqFWS8+h8j4A2xNq7gzLnv+eCo0vFDPTddDVvdb6ixmRvF5rzD1gZ2vxWzlWVqk7x0wt8wCE90S0yu40j+JOaqH35Ir3kb4NgTMXk6Yqlidw06r3P2cqbZ0jBleOFf5eRfiu0ZquU5PJ/J7t9Pecx9S8mlitTtFPlvpVprNPB+XPSz2uwcwNW9i5OBUgR3PXsOjILLog8SiWYyk7bHaWnJtZ+JVEi9isy4EiwyrDY5kHRK2kB9Nnf6a9zz2krP7W+w9a3qXJkv8GP9D2+FN9Pj+2WP4r0hz7JL0i5q9bcc5HgBKP946u87z2lEjv2ioUAghaG/zwol3q+tKv0i6pPe0guGRCdpMlXa1Z1deOBJvxJXanTrIwi7dVc/bCsRGMRyYwD6hWhe1JjxgBjc/YbbBj8JJVdHrc2tGYFBU9qG2Kv3cAZMRrMXvKUkTK8JiMVzN0/DHEtdNv1PW4U3hlAqt5b62WahyzdHNVqHycwe+Ogz0BfTdohlxftv5qQYx0SEynXaIY+WltRnCnYrY1Kg1/DmsWYCGy++TO+6cEEwISPe/FM1peidsXVf5S3DCUQWE6aMK/6XDzukZoTjor/8JPkHc56Pk1Paty0yrP+YdL5R5m3IERzHoD" } } }
能夠看到內容已經獲得了加密,接下來就須要建立 SealedSecret 對象了:
$ kubectl -n test apply -f test-seal-secret.yaml
接着查看 SealedSecret 和 secret:
$ kubectl -n test get SealedSecret,secret sealedsecret.bitnami.com/seal-test-secret 4s secret/seal-test-secret Opaque 3 3s
在以下的 Deployment 中以環境變量的形式引用上述生成的 secret:
apiVersion: apps/v1 kind: Deployment metadata: labels: app: devops name: devops spec: replicas: 1 selector: matchLabels: app: devops template: metadata: labels: app: devops spec: restartPolicy: Always containers: - name: devops image: dllhb/devopsday:v0.6 imagePullPolicy: Always envFrom: - secretRef: name: test-secret ports: - containerPort: 9999 name: http protocol: TCP
使用下面命令部署:
$ kubectl -n test apply -f test-deploy.yaml deployment.apps/devops created
查看 pod 狀態,並查看環境變量(secret 是以環境變量的形式注入 pod 內的):
$ kubectl -n test get pods devops-b48df6659-gmjtr 1/1 Running 0 21s $ kubectl -n test exec -it devops-b48df6659-gmjtr sh env | grep -E "username|password|token" username=xiaomage token=1e4dgr5fgrh3rffgrhtonnhrhr password=passw0rd
說明 secret 注入成功。其餘的 secret 類型,好比 tls、dockerconfigjson 等均可以用上面的方式進行使用。
最後就能夠將包含 secret 信息且通過加密的文件 test-seal-secret.yaml 推送至版本管理系統,好比 GitHub。
Helm Secrets 是 Helm 的一個插件,用來對於 Helm Chart 中的敏感信息進行加密。
Helm Secrets Plugin 可使用多種加密方式來對敏感信息進行加解密(本文介紹 sops)。加密時使用helm secrets enc
命令對須要加密的文件內容進行加密;解密時helm secrets
使用dec
將加密內容進行解密,並添加在 values.yaml 文件中,後續的使用直接取用 values.yaml 文件中的值便可。
使用helm secerts enc
對位於helm_vars
目錄下的secrets
文件加密時,helm secrets plugin
會使用 public key 對內容進行加密(可看下文以 sops 爲例講述的 demo)。
使用helm secrets install/upgrade
命令對應用程序進行安裝或更新的過程當中,須要指定通過加密後的 secret 文件(-f 指定,一般位於 helm_vars
目錄下),helm secrets plugin
會選擇 private key 對加密的數據進行解密,解密後的數據在 values.yaml 文件中可找到,在 helm chart 的 template 目錄下的 secret 文件只須要引用相關的值便可(.Values.xxx
)。
安裝的前提條件:
sops 是一個加密文件的編輯器,支持 YAML、JSON、ENV、INI 和二進制格式,並使用 AWS KMS、GCP KMS、Azure Key Vault 和 PGP 進行加密。
PGP(Pretty Good Privacy)是一種經常使用的加密方式。在 1990s(1991 年)由 Phil Zimmermann 所開發,如今歸屬於 Symantec 公司,它是商業軟件,須要付費才能使用。而 GPG(GNU Privacy Guard)是一種基於 Open PGP 標準的加密方式。它是開源且免費的。因此本文的演示將使用 GPG 的方式。
因爲sops採用非對稱加密,因此須要先生成一對key。使用gpg --full-generate-key
並輸入必要的參數便可生成 key,以下:
$ gpg --full-generate-key gpg (GnuPG) 2.2.12; Copyright (C) 2018 Free Software Foundation, Inc. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Please select what kind of key you want: (1) RSA and RSA (default) (2) DSA and Elgamal (3) DSA (sign only) (4) RSA (sign only) Your selection? 1 RSA keys may be between 1024 and 4096 bits long. What keysize do you want? (3072) 4096 Requested keysize is 4096 bits Please specify how long the key should be valid. 0 = key does not expire <n> = key expires in n days <n>w = key expires in n weeks <n>m = key expires in n months <n>y = key expires in n years Key is valid for? (0) 1y Key expires at Sat Jan 8 12:12:10 2022 UTC Is this correct? (y/N) y GnuPG needs to construct a user ID to identify your key. Real name: xiaomage Email address: devops@xiaomage.com Comment: gpg key generation You selected this USER-ID: "xiaomage (gpg key generation) <devops@xiaomage.com>" Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O We need to generate a lot of random bytes. It is a good idea to perform some other action (type on the keyboard, move the mouse, utilize the disks) during the prime generation; this gives the random number generator a better chance to gain enough entropy. We need to generate a lot of random bytes. It is a good idea to perform some other action (type on the keyboard, move the mouse, utilize the disks) during the prime generation; this gives the random number generator a better chance to gain enough entropy. gpg: key 8BA2C5716B5C007F marked as ultimately trusted gpg: revocation certificate stored as '/root/.gnupg/openpgp-revocs.d/BCEB5797691E6C95E33A465D8BA2C5716B5C007F.rev' public and secret key created and signed. pub rsa4096 2021-01-08 [SC] [expires: 2022-01-08] BCEB5797691E6C95E33A465D8BA2C5716B5C007F uid xiaomage (gpg key generation) <devops@xiaomage.com> sub rsa4096 2021-01-08 [E] [expires: 2022-01-08]
能夠查看生成的private key
和public key
:
gpg -K(gpg --list-secret-keys) /root/.gnupg/pubring.kbx ------------------------ sec rsa4096 2021-01-08 [SC] [expires: 2022-01-08] BCEB5797691E6C95E33A465D8BA2C5716B5C007F uid [ultimate] xiaomage (gpg key generation) <devops@xiaomage.com> ssb rsa4096 2021-01-08 [E] [expires: 2022-01-08]
gpg -k(gpg --list-keys) gpg: checking the trustdb gpg: marginals needed: 3 completes needed: 1 trust model: pgp gpg: depth: 0 valid: 2 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 2u gpg: next trustdb check due at 2022-01-08 /root/.gnupg/pubring.kbx ------------------------ pub rsa4096 2021-01-08 [SC] [expires: 2022-01-08] BCEB5797691E6C95E33A465D8BA2C5716B5C007F uid [ultimate] xiaomage (gpg key generation) <devops@xiaomage.com> sub rsa4096 2021-01-08 [E] [expires: 2022-01-08]
在用 sops 加密數據以前,先建立一個.sops.yaml
文件,寫一個加密的規則,好比只加密 key 是 username 和 password 的敏感信息,並且須要指定 gpg 的 fingerprint。
cat << EOF > .sops.yaml creation_rules: - encrypted_regex: '^(username|password)$' pgp: 'B1C77B2CCF5575FAF0DA6B882CA51446C98C9D85' EOF
接着,將下面的敏感信息寫入一個yaml文件:
cat << EOF > secrets.yaml username: xiaomage password: passw0rd EOF
如今就能夠用 sops 來加密數據了:
$ sops -e secrets.yaml username: ENC[AES256_GCM,data:s6pInMY3eGM=,iv:5Q7JsntVoKjseD3ApWcgmYeedmGXj2A1/PyGCNFHGdE=,tag:vInq3NBLxvVWXsoVUD46Rw==,type:str] password: ENC[AES256_GCM,data:Ua7de2w6Jgw=,iv:qYIjTW1D0dh20NA8FGu4XEGI16kvYGAWIk4iu3r/Gdg=,tag:b33tpsP1vCgqlpyCEDP88Q==,type:str] sops: kms: [] gcp_kms: [] azure_kv: [] hc_vault: [] lastmodified: '2021-02-06T12:08:57Z' mac: ENC[AES256_GCM,data:QHHDRSO2PyJt0/OA67ex0R39gEjWEnwg0MSnBac8QtLNh3ncY+9D8IZw/WqVnbcaiPta2Pem96yJZTZP4pum9ZX446iRKldsAXNqS4+tmlfowpMWI+1DgOa1QCkhSDH9U/2URA1dzyn3cZLPFzb5Ai6YUEQ93sRjlPI+kHXl16c=,iv:jhFM/uJSeChikUv777qgYVDFCHQhQeXlUSjiHx5X8Ow=,tag:6QTo5CsXQoqr0fK1B947ug==,type:str] pgp: - created_at: '2021-02-06T12:08:51Z' enc: | -----BEGIN PGP MESSAGE----- hQIMA/AYjF0OZ4PLAQ/+LRc5vgpRhOez8q9up8t+3OVM5QdnMwSYiuwLvjfInqqk K19jUfUhwXDGGtSMlTotYlTWqWCiSm7sYeqFB0/Lx9lCZY5BhCrVnK7u7m8azpWU osCQNmJehflqqnBmn82nblOGnDjM/FYkcnz4+NHUPNyYV5tWjzw9s8i/WhDeuNrf IPnGKRCGJunWlHDP3yWMo7bnCNU/TmuRiSpf7lQLsp/U71M5t1X8RajatO7DPecq caq3VZ+Ynx0Qcgyt+aHugZw5Sw9oFOT4WVqwLlC/NKvrjtY8pCQ1HtY5/agLHrDw Hn2Phz1aQ+l4EAarphXCiYAFw/LHD2tisbQoApXe5tud9CjiyMu/14qhQalLgQxA yGcMmhEH7Ke4bubaA0ZPo8hBXAkxfdeicSzB/e1IkUP4LtlQiwPldDcDShB6MROH sK3RpELhSaNdfQZxqDVN0CgjRS0/AjboWejjrLQHD1hVcUDAU2WTyfvIaSxKpHIx ONo5sTvzYOjU/BRTLn0EujRP414xadOtt+4gEQDrGacYAokuiK2ev0dinHo32EWY j/vsb0o3whNRpBEGMZTUrl9HSkt58FQZsmu5JnL3ZYKiujHFoQS/aOcxD0slUxhC PoCnce6PgmB78RHOLHaXkTrORc+6oMpCGN8/K1hjXE+eH/kk4jv8yVLwmbg9XjLS XgFTcQYs6nVTSoWVea62kRN4qlC/XTJ6D91HXRX5UyB3qrZ3k+w9TOlM9quYYI/B E0FqbFVSKT3ekPQqF91a7tV01FIxpfr4Mvzy2+8xsXiAQtDm52PSlk9eovkAMqU= =nafU -----END PGP MESSAGE----- fp: B1C77B2CCF5575FAF0DA6B882CA51446C98C9D85 encrypted_regex: ^(username|password)$ version: 3.6.1
能夠看到 username 和 password 的值都被加密了。接下來就是使用這些加密內容了。
執行如下命令安裝 helm-secrets plugin:
$ helm plugin install https://github.com/zendesk/helm-secrets
首先,建立一個演示用的 helm chart,並在根目錄下建立一個名爲helm_vars的目錄,用來存放用來加密的 secret,以下所示:
$ tree . └── devsecops ├── Chart.yaml ├── charts ├── helm_vars │ ├── secrets.yaml │ ├── tls.crt │ └── tls.key ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ ├── deployment.yaml │ ├── hpa.yaml │ ├── ingress.yaml │ ├── secrets.yaml │ ├── service.yaml │ ├── serviceaccount.yaml │ └── tests │ └── test-connection.yaml └── values.yaml
將須要加密的信息寫入secrets.yaml文件裏面,好比:
cat << EOF > secrets.yaml secret_data: username: xiaomage password: passw0rd EOF
使用 helm secrets 來加密上述文件:
$ helm secrets enc secrets.test.yaml Encrypting secrets.test.yaml Encrypted secrets.test.yaml
查看加密後的文件內容:
secret_data: username: ENC[AES256_GCM,data:O/1pyNsL3Gc=,iv:HZ0MrGWaBxM37cIkp/JdsA5gRzw6aJFfBR19rno3h5I=,tag:2SiMs46lonnwECc8RHfT/Q==,type:str] password: ENC[AES256_GCM,data:l15XlhZ4CsM=,iv:TMbV6+Rh2wGpMlHi7zJsHWM6IxMK2hBuMKsD82p8LiY=,tag:N4Kbftl//B1U2R9Khsduzg==,type:str] sops: kms: [] gcp_kms: [] azure_kv: [] hc_vault: [] lastmodified: '2021-02-07T06:19:15Z' mac: ENC[AES256_GCM,data:dSXjEbKyBXVtqqSqshGXKUwDJcMVZrDf2GxFj0Oor3FDnNeS+bTY4Yubv1J0XlzU6yxO0Y87NzVN84unkF/Ph95JJV2opk6a0VTtaxKYOFUVneyY5WQ2glHEntX+aEq1lJkW1Sd34i/tvWeSABemIX4M2xcIOdIaCHgzk//vi9w=,iv:febius/ashzpdfKStJnQYVG/3FrVaYw102q87P9+egQ=,tag:/MUXrxhhOk6F8MS5wi7cLQ==,type:str] pgp: - created_at: '2021-02-07T06:19:08Z' enc: | -----BEGIN PGP MESSAGE----- hQIMA7Oc9Dk1ccccARAAk7l23omTBRThnP7YC5AHdqzEO8Lapxc8ycWg5tsbM8eE JaRFn4u3/+dQdpL6xlHv1wu0kmrZUgG8P41WmNDIKb2GtAlHQk+bjjV2IU0lCEj7 9UZXuAyhxHtVjHMBnzjppFh+6L0nH2K5AGaJWATwhO9M6CqmdCFnWJx7vAPfVQZF Li9zqHK/YsbwgEWKs0bVvJ1btB7u4J5olKagYaZhaFaLzwjbtXmEqDUpfmPkooNr 7kPSVe8IMv/+MUaJY6uYNTBGWGrije4bY4A+hA/dUj4yN0gqqd796oc9GuN1MJSO cAAoiTW2Vrw3OdyP7PIJVuxlS9gXnxtBOjo+p/Ij91ELq+DnC+6bGS9UIeF+Y1RD h4siwx7I7hzk9tp+tXmsfdJit+usK6raPzYkcBgZVF8woKZsp2/qxloYyIFJ0sbK MO67+dcAg+AX0M0/u33t1BAMTt/LJ1V2ZQUl+yzjRSKfZ2bCmd/skkE3VZx2ls44 LMngWZG7EzE39Onw9PB3ukXD7W+X+BThc2AJzVotrpDWbSI2/anoM9TMJjYfBjyU xBuTuoviT5ENdm14bGomww9G+Ean3dyC2vWoHhY2KfuPlSxZ6mDIDm5zAPkZZl5A QHjtaPT5qymPCpqy2X3yvK76zyJhfWYFIHguOy3JlDxiONC9DH1M6OVWoC69pPzS XgEtII9fTeLXFU5Jy9gJa5nNKEQY87OkSXl3TFAiQ9OmgDbuUHZuvQzlecsKwR2s mS7P7Z3Bb+eRakQ41Gzw4B7wmOrm2w0t4guVJDNIP/gQB0XBO1XZj4RsbMKn070= =yQ2R -----END PGP MESSAGE----- fp: B1C77B2CCF5575FAF0DA6B882CA51446C98C9D85 encrypted_regex: ^(data|username|password|.dockerconfigjson|token|token1|key|crt)$ version: 3.6.1
須要注意的是,此時只是加密了須要加密的內容,可是這些內容該怎麼用呢?其實也比較簡單,就是:正經常使用。舉例來講,在 helm chart 中,正經常使用 secret 的方式以下:
apiVersion: v1 kind: Secret metadata: name: test labels: app: devsecops type: Opaque data: {{- range $key, $value := .Values.secret_data}} {{ $key }} : {{ $value | b64enc | quote}} {{- end}}
而上面循環中引用的值.Values.secret_data
就是來自於上面helm_vars
目錄下的加密文件。
怎麼作到的呢?簡單點說,就是執行 helm 的相關命令(install 或者 upgrade)時,會利用 sops 的 private key 將 helm\_vars 目錄下的加密內容解密,而且「存放在」values.yaml 文件中,接下來的就和正常的 helm chart 使用是同樣的了。在 chart中的 deployment.yaml 文件中引用 secret:
...... containers: - name: {{ .Chart.Name }} image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} envFrom: - secretRef: name: test ......
接下來可使用下面命令將前文的 chart 進行安裝:
$ helm secrets install test . --namespace test -f helm_vars/secrets.yaml -f values.yaml
須要注意的是,在上面的命令中,必須指定helm_vars/secrets.yaml文件。
接着查看生成的pod、secret:
$ kubectl -n test get pods,secret pod/test-devsecops-7876ffc8b7-967xr 1/1 Running 0 6s secret/test Opaque 2 8s
因爲上面的 secret 是以環境變量的形式注入到 pod 裏面的,能夠查看進行驗證:
$ kubectl -n test exec -it test-devsecops-7876ffc8b7-967xr sh $ env | grep -E 'username|password' username=xiaomage password=passw0rd
能夠看到 secret 解密成功,併成功注入 pod。
最後就能夠將加密後的文件上傳至源碼管理系統了(好比用 git push 至 GitHub)。
Kamus 是一款開源的採用零信任的 secret 加解密方式爲 Kubernetes 應用程序安全處理 secrets 的工具。Kamus 提供兩種方式來對 Kubernetes secrets 進行加密,即
Kamus 一樣是使用客戶端工具 kamus-cli 對於須要加密的數據進行加密(區別於 Sealed Secrets 的是,Kamus 的數據須要單獨逐一加密,而不是所有存放在 secret 文件裏面一次性加密,下面會看到),下面依舊以加解密的方式分別闡述。
用 kamus-cli 對須要加密的數據逐一加密時,位於集羣上的 controller 會選擇 public key 並使用 kamus encryptor 對數據進行加密,隨後將加密內容保存在 configmap 中(以 init container 的方式使用)或者 KamusSecret 中(以 secret 的方式使用)。
當將加密後的內容進行部署時(kubectl apply/create),位於集羣上的 controller 會選擇 private key,並使用 kamus decryptor 對於數據進行解密,若是是使用 KamusSecret 存儲的數據,則 controller 會將生成一個與 KamusSecret 對象同名的 Secret 對象,此 Secret 中存放由通過 base64 編碼後的信息;若是是使用 configmap 的形式,則此 configmap 會以 volume 的形式掛載到 pod 內,隨後在 pod 中使用 init container 來調用 kamus-decryptor 的 api 將加密信息解密,並存放到指定的文件中,隨後 pod 內的應用程序能夠經過讀取此文件內容來獲取敏感信息。
KamusSecret 和 Secret 二者的關係與 Deployment 和 Pod 之間的關係相似。
kamus 的安裝包括 controller 和 客戶端工具 kamus-cli。
$ helm repo add soluto https://charts.soluto.io $ helm install kamus --namespace kamus soluto/kamus
檢查 pod 狀態:
$ kubectl -n kamus get pods NAME READY STATUS RESTARTS AGE kamus-controller-55d959895d-hdklf 1/1 Running 0 9m30s kamus-decryptor-5974b6ff47-5pkbr 1/1 Running 0 7m34s kamus-decryptor-5974b6ff47-c4jt4 1/1 Running 0 7m34s kamus-encryptor-f75dd457-fwp8r 1/1 Running 0 9m28s kamus-encryptor-f75dd457-p9rnx 1/1 Running 0 9m29s
$ npm install -g @soluto-asurion/kamus-cli
檢查安裝是否成功:
$ kamus-cli -V 0.3.0
下面分別以init container和 KamusSecret 的方式來演示使用方式。
1)以init container的方式
首先須要加密 secret。kamus 加密 secret 時須要和一個 service account 關聯起來,此 service account 會在後續的應用部署中使用,因此先建立一個 service account(本文全部 demo 均在 test ns 下):
$ kubectl -n test create sa xiaomage
接着使用客戶端工具 kamus-cli 來加密 secret(username 的值爲 xiaomge,password 的值爲 passw0rd):
$ kamus-cli encrypt --secret xiaomage --service-account xiaomage --namespace test --kamus-url http://localhost:9999 --allow-insecure-url [info kamus-cli]: Encryption started... [info kamus-cli]: service account: xiaomage [info kamus-cli]: namespace: test [warn kamus-cli]: Auth options were not provided, will try to encrypt without authentication to kamus [info kamus-cli]: Successfully encrypted data to xiaomage service account in test namespace [info kamus-cli]: Encrypted data: CxujUBK4jgdjt+wP5mXyDA==:+CoXRDJVtW3EZ2FpterVTA==
返回的CxujUBK4jgdjt+wP5mXyDA==:+CoXRDJVtW3EZ2FpterVTA==
就是 xiaomage 這個值通過加密後的值,用一樣的方法,能夠將 passw0rd 進行加密:
$ kamus-cli encrypt --secret passw0rd --service-account xiaomage --namespace test --kamus-url http://localhost:9999 --allow-insecure-url [info kamus-cli]: Encryption started... [info kamus-cli]: service account: xiaomage [info kamus-cli]: namespace: test [warn kamus-cli]: Auth options were not provided, will try to encrypt without authentication to kamus [info kamus-cli]: Successfully encrypted data to xiaomage service account in test namespace [info kamus-cli]: Encrypted data: ChmNEPM8Nj7Huh1YwO5xOA==:r9MHhEyTIEaQ4hw837lA9w==
返回的ChmNEPM8Nj7Huh1YwO5xOA==:r9MHhEyTIEaQ4hw837lA9w==
就是 passw0rd 這個值通過加密後的值,將上述兩個加密後的值放在 configmap 中:
apiVersion: v1 kind: ConfigMap metadata: name: kamus-encrypted-secrets-cm namespace: test data: username: CxujUBK4jgdjt+wP5mXyDA==:+CoXRDJVtW3EZ2FpterVTA== password: ChmNEPM8Nj7Huh1YwO5xOA==:r9MHhEyTIEaQ4hw837lA9w==
接下來,將上述 configmap 以 volume 的方式掛在到 pod 中,隨後使用 init container 來解密數據,且將數據存放在一個 config.json 文件中:
apiVersion: v1 kind: Pod metadata: namespace: test name: kamus-pod spec: serviceAccountName: xiaomage automountServiceAccountToken: true initContainers: - name: "kamus-init" image: "soluto/kamus-init-container:latest" imagePullPolicy: IfNotPresent env: - name: KAMUS_URL value: http://kamus-decryptor.kamus.svc.cluster.local/ volumeMounts: - name: encrypted-secrets mountPath: /encrypted-secrets - name: decrypted-secrets mountPath: /decrypted-secrets args: ["-e","/encrypted-secrets","-d","/decrypted-secrets", "-n", "config.json"] containers: - name: kamus-test image: dllhb/devopsday:v0.6 imagePullPolicy: IfNotPresent volumeMounts: - name: decrypted-secrets mountPath: /secrets volumes: - name: encrypted-secrets configMap: name: kamus-encrypted-secrets-cm - name: decrypted-secrets emptyDir: medium: Memory
須要注意的是,須要指定 kamus 的地址,即 decryptor 的地址,可根據本身的安裝狀況自行指定。
接下來,部署 configmap 和 pod 並查看:
$ kubectl -n test apply -f configmap.yaml $ kubectl -n test apply -f kamus-deploy.yaml $ kubectl -n test get pods,cm NAME READY STATUS RESTARTS AGE pod/kamus-pods 1/1 Running 0 4h3m NAME DATA AGE configmap/kamus-encrypted-secrets-cm 2 30s
進入 pod 查看解密後的數據:
$kubectl -n test exec -it kamus-deploy sh $ cat /secrets/config.json { "password":"passw0rd", "username":"username" }
能夠看到 secet 已經被解密到了 config.json文件中,應用程序只須要讀取此文件便可得到 secret 的相關數據。
2)以 KamusSecret 的方式
kamus 對 Kubernetes 進行了擴展,有了本身支持的 KamusSecret 對象,將上述加密後的數據存放在 KamusSecret 中:
apiVersion: "soluto.com/v1alpha2" kind: KamusSecret metadata: name: kamus-test namespace: test type: Opaque stringData: username: CxujUBK4jgdjt+wP5mXyDA==:+CoXRDJVtW3EZ2FpterVTA== password: ChmNEPM8Nj7Huh1YwO5xOA==:r9MHhEyTIEaQ4hw837lA9w== serviceAccount: xiaomage
建立 KamusSecret 對象:
$ kubectl -n test apply -f kamus-secrets.yaml
查看生成的 KamusSecret 和 Secret:
$ kubectl -n test get KamusSecret,secret NAME AGE kamussecret.soluto.com/kamus-test 60s NAME TYPE DATA AGE secret/kamus-test Opaque 2 59s
能夠看到 KamusSecret 生成了一個和本身同名的 secret,接着查看 secret 的內容:
apiVersion: v1 data: password: cGFzc3cwcmQ= username: eGlhb21hZ2U=
解碼後爲:
password: passw0rd username: xiaomage
此時,能夠像正常方式在 pod 中引用此 secret(像前文的 Sealed Secret 章節所演示的同樣,再次再也不贅述)。
最後就能夠將加密後的文件上傳至源碼管理系統了(好比 git push 至 GitHub)。
其實,安全處理 Kubernetes secret 的方式不只僅上面的三種形式,還能夠利用諸如 vault 等來管理應用程序部署中的敏感信息。可是不一樣的工具、不一樣的方式,其背後的思想和思路都差不太多。
總結起來,差很少有如下幾個點:
沒有一勞永逸的安全,只有永不止步的行動。任何改變都是重要的。
參考
https://github.com/bitnami-la...
https://github.com/Soluto/kamus
https://blog.solutotlv.com/ca...
https://en.sokube.ch/post/lig...
https://github.com/mozilla/so...
來源:DevSecOps SIG
做者:小馬哥
4月每週四晚8點,【冬哥有話說】DevOps之庖丁解牛,拆解DevOps的工具及具體實戰。公衆號留言「解牛」可獲取地址