<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Kubernetes secrets 加密處理的3種方式 | IDCF

          共 24007字,需瀏覽 49分鐘

           ·

          2021-04-14 09:25


          來(lái)源:DevSecOps SIG
          作者:小馬哥 

           前 言 



          Kubernetes 已經(jīng)毫無(wú)爭(zhēng)議地成為了云原生時(shí)代的事實(shí)標(biāo)準(zhǔn),在 Kubernetes 上部署應(yīng)用程序也變得簡(jiǎn)單起來(lái)(無(wú)論是采用 kustomize 還是 helm),雖然對(duì)于敏感信息(比如用戶(hù)名、密碼、token 和證書(shū)等)的處理,Kubernetes 自己提供了 secret 這種方式,但這是一種編碼方式,而非加密方式,如果需要用版本控制系統(tǒng)(比如 git)來(lái)對(duì)所有的文件、內(nèi)容等進(jìn)行版本控制時(shí),這種用編碼來(lái)處理敏感信息的方式就顯得很不安全了(即使是采用私有庫(kù)),這一點(diǎn)在實(shí)現(xiàn) GitOps 時(shí),是一個(gè)痛點(diǎn)。
          基于此,本文介紹三種可以加密 Kubernetes secret 的方式:Sealed Secrets、Helm Secrets 和 Kamus。

          一、Sealed Secrets



          Sealed Secrets 充分利用 kuberntes 的高擴(kuò)展性,通過(guò) CRD 來(lái)創(chuàng)建一個(gè) SealedSecret 對(duì)象,通過(guò)將加密的內(nèi)容存儲(chǔ)在擴(kuò)展 SealedSecret 對(duì)象中,而 SealedSecret 只能夠被運(yùn)行于目標(biāo)集群上的 controller 解密,其他人員和方式都無(wú)法正確解密原始數(shù)據(jù)。
          SealedSecret 對(duì)象同時(shí)又會(huì)生成與其名稱(chēng)相同的 secret 對(duì)象,隨后就可以按照常規(guī)方式使用 secret 對(duì)象了。最后將加密后的文件直接推送至版本控制系統(tǒng)即可,而不用擔(dān)心敏感信息被泄漏。
          1.1 原理
          Sealed Secrets 加解密的原理簡(jiǎn)單來(lái)說(shuō)就是:安裝的時(shí)候 controller 會(huì)生成一對(duì)用于加密的 key,加密時(shí)在客戶(hù)端 kubeseal 的幫助下,將包含敏感信息的 kubernets secrets 內(nèi)容加密轉(zhuǎn)變?yōu)橐粋€(gè)包含有加密信息的 Kubernetes SealedSecrets 對(duì)象;解密時(shí)在 controller 的幫助下將 Kubernetes SealedSecrets 對(duì)象內(nèi)的內(nèi)容進(jìn)行解密,然后生成常規(guī)的 kubernetes secret 對(duì)象。
          1.2 加密(encryption)
          kubeseal 使用位于 cluster controller 生成的 public key 來(lái)加密,將 secrets 對(duì)象的內(nèi)容加密轉(zhuǎn)變成 SealedSecrets 對(duì)象。public key 和 private key 在安裝 controller 的時(shí)候,以 secret(如下的 sealed-secrets-key217vf)的形成存放,可以在安裝 controller 所在的 ns 下面查看。
          $ 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
          1.3 解密(decryption)
          當(dāng)將加密后生成的 SealedSecrets 對(duì)象進(jìn)行部署時(shí)(kubectl apply/create),controller 會(huì)先拿 private key 進(jìn)行解密,然后再生成與 SealedSecrets 同名的 Secret 對(duì)象,而此時(shí)的 Secret 對(duì)象保存的是經(jīng)過(guò) base64 編碼后的信息,隨后可以像正常使用 secret 一樣使用這些信息。
          SealedSecrets 和 Secret 兩者的關(guān)系與 Deployment 和 Pod 之間的關(guān)系類(lèi)似。
          1.4 安裝
          Sealed Secrets 有兩部分組成:
          • 安裝于集群側(cè)的 controller
          • 客戶(hù)端工具 kubeseal
          所以安裝也分兩步,安裝 controller 和 kubeseal??梢韵劝惭b controller,執(zhí)行如下命令即可:
          $ 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
          接著安裝客戶(hù)端工具 kubeseal。這個(gè)可以根據(jù)自己的 OS 來(lái)選用不同的安裝方式,以 MacOs 為例:

          $ brew install kubeseal

          通過(guò)查看 kubeseal 的版本來(lái)確定是否安裝成功:

          $ kubeseal --version
          kubeseal version: v0.14.1
          此時(shí),兩部分均安裝成功,下面可以使用了。
          1.5 使用
          選擇一個(gè)包含有需要加密的 secret 的文件,內(nèi)容如下:
          apiVersion: v1
          data:
          username: eGlhb21hZ2U=
          password: cGFzc3cwcmQ=
          token: MWU0ZGdyNWZncmgzcmZmZ3JodG9ubmhyaHI=
          kind: Secret
          metadata:
          name: seal-test-secret
          namespace: test
          type: Opaque
          將上述內(nèi)容寫(xiě)入一個(gè) yaml 文件,比如 test-secret.yaml,然后執(zhí)行如下命令加密:
          $ kubeseal < test-secret.yaml > test-seal-secret.yaml
          可以查看 test-seal-secret.yaml 文件的內(nèi)容:
          {
          "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"
          }
          }
          }
          可以看到內(nèi)容已經(jīng)得到了加密,接下來(lái)就需要?jiǎng)?chuàng)建 SealedSecret 對(duì)象了:
          $ 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 中以環(huán)境變量的形式引用上述生成的 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 狀態(tài),并查看環(huán)境變量(secret 是以環(huán)境變量的形式注入 pod 內(nèi)的):

          $ 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

          說(shuō)明 secret 注入成功。其他的 secret 類(lèi)型,比如 tls、dockerconfigjson 等都可以用上面的方式進(jìn)行使用。

          最后就可以將包含 secret 信息且經(jīng)過(guò)加密的文件 test-seal-secret.yaml 推送至版本管理系統(tǒng),比如 GitHub。


          二、Helm Secrets



          Helm Secrets 是 Helm 的一個(gè)插件,用來(lái)對(duì)于 Helm Chart 中的敏感信息進(jìn)行加密。

          2.1 原理

          Helm Secrets Plugin 可以使用多種加密方式來(lái)對(duì)敏感信息進(jìn)行加解密(本文介紹 sops)。加密時(shí)使用helm secrets enc 命令對(duì)需要加密的文件內(nèi)容進(jìn)行加密;解密時(shí)helm secrets使用dec加密內(nèi)容進(jìn)行解密,并添加在 values.yaml 文件中,后續(xù)的使用直接取用 values.yaml 文件中的值即可。

          2.2 加密

          使用helm secerts enc 對(duì)位于helm_vars目錄下的secrets文件加密時(shí),helm secrets plugin會(huì)使用 public key 對(duì)內(nèi)容進(jìn)行加密。

          2.3 解密

          使用helm secrets install/upgrade命令對(duì)應(yīng)用程序進(jìn)行安裝或更新的過(guò)程中,需要指定經(jīng)過(guò)加密后的 secret 文件(-f 指定,通常位于 helm_vars目錄下),helm secrets plugin 會(huì)選擇 private key 對(duì)加密的數(shù)據(jù)進(jìn)行解密,解密后的數(shù)據(jù)在 values.yaml 文件中可找到,在 helm chart 的 template 目錄下的 secret 文件只需要引用相關(guān)的值即可(.Values.xxx)。

          2.4 安裝

          安裝的前提條件:

          • helm(>2.3)

          • sops

          sops 是一個(gè)加密文件的編輯器,支持 YAML、JSON、ENV、INI 和二進(jìn)制格式,并使用 AWS KMS、GCP KMS、Azure Key Vault 和 PGP 進(jìn)行加密。

          PGP(Pretty Good Privacy)是一種常用的加密方式。在 1990s(1991 年)由 Phil Zimmermann 所開(kāi)發(fā),現(xiàn)在歸屬于 Symantec 公司,它是商業(yè)軟件,需要付費(fèi)才能使用。而 GPG(GNU Privacy Guard)是一種基于 Open PGP 標(biāo)準(zhǔn)的加密方式。它是開(kāi)源且免費(fèi)的。所以本文的演示將使用 GPG 的方式。

          由于sops采用非對(duì)稱(chēng)加密,所以需要先生成一對(duì)key。使用gpg --full-generate-key并輸入必要的參數(shù)即可生成 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: [email protected]
          Comment: gpg key generation
          You selected this USER-ID:
          "xiaomage (gpg key generation) <[email protected]>"

          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) <[email protected]>
          sub rsa4096 2021-01-08 [E] [expires: 2022-01-08]

          可以查看生成的private keypublic key

          • private 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) <[email protected]>
          ssb rsa4096 2021-01-08 [E] [expires: 2022-01-08]
          • public key 查看

          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) <[email protected]>
          sub rsa4096 2021-01-08 [E] [expires: 2022-01-08]

          在用 sops 加密數(shù)據(jù)之前,先創(chuàng)建一個(gè).sops.yaml文件,寫(xiě)一個(gè)加密的規(guī)則,比如只加密 key 是 username 和 password 的敏感信息,而且需要指定 gpg 的 fingerprint。

          cat << EOF > .sops.yaml
          creation_rules:
          - encrypted_regex: '^(username|password)$'
          pgp: 'B1C77B2CCF5575FAF0DA6B882CA51446C98C9D85'
          EOF

          接著,將下面的敏感信息寫(xiě)入一個(gè)yaml文件:

          cat << EOF > secrets.yaml
          username: xiaomage
          password: passw0rd
          EOF

          現(xiàn)在就可以用 sops 來(lái)加密數(shù)據(jù)了:

          $ 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 的值都被加密了。

          2.5 安裝使用 Helm Secrets plugin

          執(zhí)行以下命令安裝 helm-secrets plugin:

          $ helm plugin install https://github.com/zendesk/helm-secrets

          首先,創(chuàng)建一個(gè)演示用的 helm chart,并在根目錄下創(chuàng)建一個(gè)名為helm_vars的目錄,用來(lái)存放用來(lái)加密的 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

          將需要加密的信息寫(xiě)入secrets.yaml文件里面,比如:

          cat << EOF > secrets.yaml
          secret_data:
          username: xiaomage
          password: passw0rd
          EOF

          使用 helm secrets 來(lái)加密上述文件:

          $ helm secrets enc secrets.test.yaml
          Encrypting secrets.test.yaml
          Encrypted secrets.test.yaml

          查看加密后的文件內(nèi)容:

          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

          需要注意的是,此時(shí)只是加密了需要加密的內(nèi)容,但是這些內(nèi)容該怎么用呢?其實(shí)也比較簡(jiǎn)單,就是:正常用。

          舉例來(lái)說(shuō),在 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}}
          而上面循環(huán)中引用的值.Values.secret_data就是來(lái)自于上面helm_vars目錄下的加密文件。
          怎么做到的呢?簡(jiǎn)單點(diǎn)說(shuō),就是執(zhí)行 helm 的相關(guān)命令(install 或者 upgrade)時(shí),會(huì)利用 sops 的 private key 將 helm_vars 目錄下的加密內(nèi)容解密,并且“存放在”values.yaml 文件中,接下來(lái)的就和正常的 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
          ......

          接下來(lái)可以使用下面命令將前文的 chart 進(jìn)行安裝:

          $ 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 是以環(huán)境變量的形式注入到 pod 里面的,可以查看進(jìn)行驗(yàn)證:

          $ kubectl -n test exec -it test-devsecops-7876ffc8b7-967xr sh
          $ env | grep -E 'username|password'
          username=xiaomage
          password=passw0rd

          可以看到 secret 解密成功,并成功注入 pod。

          最后就可以將加密后的文件上傳至源碼管理系統(tǒng)了(比如用 git push 至 GitHub)。


          三、Kamus



          Kamus 是一款開(kāi)源的采用零信任的 secret 加解密方式為 Kubernetes 應(yīng)用程序安全處理 secrets 的工具。Kamus 提供兩種方式來(lái)對(duì) Kubernetes secrets 進(jìn)行加密,即

          • 使用 init container:將 secrets 加密后存儲(chǔ)為 Kubernetes configmap,然后在應(yīng)用程序的部署中添加一個(gè) init container,通過(guò) init container 將 configmap 中的加密數(shù)據(jù)解密至指定文件,應(yīng)用程序再?gòu)拇宋募x取解密后的 secret 信息。

          • 使用 KamusSecret:創(chuàng)建一個(gè) KamusSecret 對(duì)象(充分利用了 Kubernetes 的擴(kuò)展機(jī)制),此對(duì)象包含了加密之后的數(shù)據(jù),在此對(duì)象創(chuàng)建的過(guò)程中,會(huì)創(chuàng)建一個(gè)同名的 secret 對(duì)象,secret 中的數(shù)據(jù)是經(jīng)過(guò) base64 編碼之后的數(shù)據(jù),可以被 Kubernetes 其他對(duì)象引用。

          3.1 原理

          Kamus 同樣是使用客戶(hù)端工具 kamus-cli 對(duì)于需要加密的數(shù)據(jù)進(jìn)行加密(區(qū)別于 Sealed Secrets 的是,Kamus 的數(shù)據(jù)需要單獨(dú)逐一加密,而不是全部存放在 secret 文件里面一次性加密,下面會(huì)看到),下面依舊以加解密的方式分別闡述。

          3.2 加密

          用 kamus-cli 對(duì)需要加密的數(shù)據(jù)逐一加密時(shí),位于集群上的 controller 會(huì)選擇 public key 并使用 kamus encryptor 對(duì)數(shù)據(jù)進(jìn)行加密,隨后將加密內(nèi)容保存在 configmap 中(以 init container 的方式使用)或者 KamusSecret 中(以 secret 的方式使用)。

          3.3 解密

          當(dāng)將加密后的內(nèi)容進(jìn)行部署時(shí)(kubectl apply/create),位于集群上的 controller 會(huì)選擇 private key,并使用 kamus decryptor 對(duì)于數(shù)據(jù)進(jìn)行解密。

          如果是使用 KamusSecret 存儲(chǔ)的數(shù)據(jù),則 controller 將生成一個(gè)與 KamusSecret 對(duì)象同名的 Secret 對(duì)象,此 Secret 中存放由經(jīng)過(guò) base64 編碼后的信息;

          如果是使用 configmap 的形式,則此 configmap 會(huì)以 volume 的形式掛載到 pod 內(nèi),隨后在 pod 中使用 init container 來(lái)調(diào)用 kamus-decryptor 的 api 將加密信息解密,并存放到指定的文件中,隨后 pod 內(nèi)的應(yīng)用程序可以通過(guò)讀取此文件內(nèi)容來(lái)獲取敏感信息。

          KamusSecret 和 Secret 兩者的關(guān)系與 Deployment 和 Pod 之間的關(guān)系類(lèi)似。

          3.4 安裝

          kamus 的安裝包括 controller 和客戶(hù)端工具 kamus-cli。

          • 安裝 controller

          $ helm repo add soluto https://charts.soluto.io
          $ helm install kamus --namespace kamus soluto/kamus

          檢查 pod 狀態(tài):

          $ 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
          • 安裝客戶(hù)端

          $ npm install -g @soluto-asurion/kamus-cli

          檢查安裝是否成功:

          $ kamus-cli -V
          0.3.0

          3.5 使用

          下面分別以init container和 KamusSecret 的方式來(lái)演示使用方式。

          1)以init container的方式

          首先需要加密 secret。kamus 加密 secret 時(shí)需要和一個(gè) service account 關(guān)聯(lián)起來(lái),此 service account 會(huì)在后續(xù)的應(yīng)用部署中使用,所以先創(chuàng)建一個(gè) service account(本文所有 demo 均在 test ns 下):
          $ kubectl -n test create sa xiaomage
          接著使用客戶(hù)端工具 kamus-cli 來(lái)加密 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 這個(gè)值經(jīng)過(guò)加密后的值,用同樣的方法,可以將 passw0rd 進(jìn)行加密:

          $ 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 這個(gè)值經(jīng)過(guò)加密后的值,將上述兩個(gè)加密后的值放在 configmap 中:
          apiVersion: v1
          kind: ConfigMap
          metadata:
          name: kamus-encrypted-secrets-cm
          namespace: test
          data:
          username: CxujUBK4jgdjt+wP5mXyDA==:+CoXRDJVtW3EZ2FpterVTA==
          password: ChmNEPM8Nj7Huh1YwO5xOA==:r9MHhEyTIEaQ4hw837lA9w==

          接下來(lái),將上述 configmap 以 volume 的方式掛在到 pod 中,隨后使用 init container 來(lái)解密數(shù)據(jù),且將數(shù)據(jù)存放在一個(gè) 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 的地址,可根據(jù)自己的安裝情況自行指定。

          接下來(lái),部署 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

          進(jìn)入 pod 查看解密后的數(shù)據(jù):

          $kubectl -n test exec -it kamus-deploy sh
          $ cat /secrets/config.json
          {
          "password":"passw0rd",
          "username":"username"
          }
          可以看到 secet 已經(jīng)被解密到了 config.json文件中,應(yīng)用程序只需要讀取此文件即可獲得 secret 的相關(guān)數(shù)據(jù)。
          2)以 KamusSecret 的方式
          kamus 對(duì) Kubernetes 進(jìn)行了擴(kuò)展,有了自己支持的 KamusSecret 對(duì)象,將上述加密后的數(shù)據(jù)存放在 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

          創(chuàng)建 KamusSecret 對(duì)象:

          $ 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 生成了一個(gè)和自己同名的 secret,接著查看 secret 的內(nèi)容:

          apiVersion: v1
          data:
          password: cGFzc3cwcmQ=
          username: eGlhb21hZ2U=

          解碼后為:

          password: passw0rd
          username: xiaomage

          此時(shí),可以像正常方式在 pod 中引用此 secret(像前文的 Sealed Secret 章節(jié)所演示的一樣,再次不再贅述)。

          最后就可以將加密后的文件上傳至源碼管理系統(tǒng)了(比如 git push 至 GitHub)。


          寫(xiě)在最后



          其實(shí),安全處理 Kubernetes secret 的方式不僅僅上面的三種形式,還可以利用諸如 vault 等來(lái)管理應(yīng)用程序部署中的敏感信息。但是不同的工具、不同的方式,其背后的思想和思路都差不太多。

          總結(jié)起來(lái),差不多有以下幾點(diǎn):

          • 充分利用 Kubernetes 的擴(kuò)展能力,自定義一個(gè) secret 對(duì)象用來(lái)存儲(chǔ)加密后的數(shù)據(jù)(諸如 Sealed Secrets 的 SealedSecret 對(duì)象;Kamus 的 KamusSecret),讓這些擴(kuò)展的對(duì)象生成對(duì)應(yīng)的 secret 對(duì)象,再正常使用 secret 對(duì)象。

          • 利用外部的敏感信息管理工具(諸如 vault 或者其他云廠商提供的服務(wù))。

          • sops 是一種使用方便的加密工具,也是上述工具實(shí)現(xiàn)加密的秘密武器。

          沒(méi)有一勞永逸的安全,只有永不止步的行動(dòng)。任何改變都是重要的。

          參考

          • https://github.com/bitnami-labs/sealed-secrets

          • https://github.com/Soluto/kamus

          • https://kamus.soluto.io/

          • https://blog.solutotlv.com/can-kubernetes-keep-a-secret/

          • https://en.sokube.ch/post/lightweight-kubernetes-gitops-secrets

          • https://github.com/mozilla/sops#showing-diffs-in-cleartext-in-git


          4月,【冬哥有話說(shuō)】DevOps之庖丁解牛,拆解DevOps的工具及具體實(shí)戰(zhàn)。晚8點(diǎn),第②期,薄濤和魏振龍兩位老師分享《持續(xù)交付中的版本管理與基于Azure DevOps擴(kuò)展框架的插件開(kāi)發(fā)》,關(guān)注公眾號(hào)回復(fù)“解?!笨色@取直播地址

          瀏覽 45
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  人人妻人人操人人屌 | 国产欧美一区二区 | 成人毛片在线大全免费 | 老骚逼视频 | 国产精品无码一区二区三区免费 |