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的工具及具体实战。公众号留言“解牛”可获取地址