关于加密:Kubernetes-secrets-加密处理的几种方式-IDCF

182次阅读

共计 20539 个字符,预计需要花费 52 分钟才能阅读完成。

前言

Kubernetes 曾经毫无争议地成为了云原生时代的事实标准,在 Kubernetes 上部署应用程序也变得简略起来(无论是采纳 kustomize 还是 helm),尽管对于敏感信息(比方用户名、明码、token 和证书等)的解决,Kubernetes 本人提供了 secret 这种形式,但其是一种编码方式,而非加密形式,如果须要用版本控制系统(比方 git)来对所有的文件、内容等进行版本控制时,这种用编码来解决敏感信息的形式就显得很不平安了(即便是采纳公有库),这一点在实现 GitOps 时,是一个痛点。

基于此,本文就介绍三种能够加密 Kubernetes secret 的形式:Sealed Secrets、Helm Secrets 和 Kamus。

一、Sealed Secrets

Sealed Secrets 充分利用 kuberntes 的高扩展性,通过 CRD 来创立一个 SealedSecret 对象,通过将加密的内容存储在扩大 SealedSecret 对象中,而 SealedSecret 只可能被运行于指标集群上的 controller 解密,其余人员和形式都无奈正确解密原始数据。SealedSecret 对象同时又会生成与其名称雷同的 secret 对象,随后就能够依照惯例形式应用 secret 对象了。最初将加密后的文件间接推送至版本控制系统即可,而不必放心敏感信息被透露。

1.1 原理

Sealed Secrets 加解密的原理简略来说就是:装置的时候 controller 会生成一对用于加密的 key,加密时在客户端 kubeseal 的帮忙下,将蕴含敏感信息的 kubernets secrets 内容加密转变为一个蕴含有加密信息的 Kubernetes SealedSecrets 对象;解密时在 controller 的帮忙下将 Kubernetes SealedSecrets 对象内的内容进行解密,而后生成惯例的 kubernetes secret 对象。

上面分加解密两局部(encryption 和 decryption)来介绍 Sealed Secrerts 的工作原理。

1.2 加密(encryption)

kubeseal 应用位于 cluster controller 生成的 public key 来加密,将 secrets 对象的内容加密转变成 SealedSecrets 对象。public key 和 private key 在装置 controller 的时候,以 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)

当将加密后生成的 SealedSecrets 对象进行部署时(kubectl apply/create),controller 会先拿 private key 进行解密,而后再生成与 SealedSecrets 同名的 Secret 对象,而此时的 Secret 对象保留的是通过 base64 编码后的信息,随后能够像失常应用 secret 一样应用这些信息。

SealedSecrets 和 Secret 两者的关系与 Deployment 和 Pod 之间的关系相似。

1.4 装置

Sealed Secrets 有两局部组成:

  • 装置于集群侧的 controller
  • 客户端工具 kubeseal

所以装置也分两步,装置 controller 和 kubeseal。能够先装置 controller,执行如下命令即可:

$ 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

此时,两局部均装置胜利,上面能够应用了。

1.5 应用

抉择一个蕴含有须要加密的 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 Secrets 是 Helm 的一个插件,用来对于 Helm Chart 中的敏感信息进行加密。

2.1 原理

Helm Secrets Plugin 能够应用多种加密形式来对敏感信息进行加解密(本文介绍 sops)。加密时应用 helm secrets enc 命令对须要加密的文件内容进行加密;解密时helm secrets 应用 dec 将加密内容进行解密,并增加在 values.yaml 文件中,后续的应用间接取用 values.yaml 文件中的值即可。

2.2 加密

应用 helm secerts enc 对位于helm_vars 目录下的 secrets 文件加密时,helm secrets plugin会应用 public key 对内容进行加密(可看下文以 sops 为例讲述的 demo)。

2.3 解密

应用 helm secrets install/upgrade 命令对应用程序进行装置或更新的过程中,须要指定通过加密后的 secret 文件(-f 指定,通常位于 helm_vars 目录下),helm secrets plugin 会抉择 private key 对加密的数据进行解密,解密后的数据在 values.yaml 文件中可找到,在 helm chart 的 template 目录下的 secret 文件只须要援用相干的值即可(.Values.xxx)。

2.4 装置

装置的前提条件:

  • helm(>2.3)
  • sops

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 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) <devops@xiaomage.com>
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) <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 的值都被加密了。接下来就是应用这些加密内容了。

2.5 装置应用 Helm Secrets plugin

执行以下命令装置 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

Kamus 是一款开源的采纳零信赖的 secret 加解密形式为 Kubernetes 应用程序平安解决 secrets 的工具。Kamus 提供两种形式来对 Kubernetes secrets 进行加密,即

  • 应用 init container:将 secrets 加密后存储为 Kubernetes configmap,而后在应用程序的部署中增加一个 init container,通过 init container 将 configmap 中的加密数据解密至指定文件,应用程序再从此文件读取解密后的 secret 信息。
  • 应用 KamusSecret:创立一个 KamusSecret 对象(充分利用了 Kubernetes 的扩大机制),此对象蕴含了加密之后的数据,在此对象创立的过程中,会创立一个同名的 secret 对象,secret 中的数据是通过 base64 编码之后的数据,能够被 Kubernetes 其余对象援用。

3.1 原理

Kamus 同样是应用客户端工具 kamus-cli 对于须要加密的数据进行加密(区别于 Sealed Secrets 的是,Kamus 的数据须要独自逐个加密,而不是全副寄存在 secret 文件外面一次性加密,上面会看到),上面仍旧以加解密的形式别离论述。

3.2 加密

用 kamus-cli 对须要加密的数据逐个加密时,位于集群上的 controller 会抉择 public key 并应用 kamus encryptor 对数据进行加密,随后将加密内容保留在 configmap 中(以 init container 的形式应用)或者 KamusSecret 中(以 secret 的形式应用)。

3.3 解密

当将加密后的内容进行部署时(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 之间的关系相似。

3.4 装置

kamus 的装置包含 controller 和 客户端工具 kamus-cli。

  • 装置 controller
$ 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

3.5 应用

上面别离以 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 等来管理应用程序部署中的敏感信息。然而不同的工具、不同的形式,其背地的思维和思路都差不太多。

总结起来,差不多有以下几个点:

  • 充分利用 Kubernetes 的扩大能力,自定义一个 secret 对象用来存储加密后的数据(诸如 Sealed Secrets 的 SealedSecret 对象;Kamus 的 KamusSecret),让这些扩大的对象生成对应的 secret 对象,再失常应用 secret 对象。
  • 利用内部的敏感信息管理工具(诸如 vault 或者其余云厂商提供的服务)。
  • sops 是一种使用方便的加密工具,也是上述工具实现加密的秘密武器。

没有一劳永逸的平安,只有永不止步的口头。任何扭转都是重要的。

参考

https://github.com/bitnami-la…

https://github.com/Soluto/kamus

https://kamus.soluto.io/

https://blog.solutotlv.com/ca…

https://en.sokube.ch/post/lig…

https://github.com/mozilla/so…

起源:DevSecOps SIG

作者:小马哥

4 月每周四晚 8 点,【冬哥有话说】DevOps 之庖丁解牛,拆解 DevOps 的工具及具体实战。公众号留言“解牛”可获取地址

  • 0401《数据库继续交付流水线分享与演示(Azure DevOps+Flyway)》
  • 0408《继续交付中的版本治理与基于 Azure DevOps 扩大框架的插件开发》
  • 0415《微服务,多团队合作中的 API 测试怎么做 – Pact 契约测试》
  • 0422《BoatHouse 端到端流水线展现》

正文完
 0