OpenShift 4 - 用 Hashicorp Vault 提升 Secret 敏感信息的安全

发布于:2022-11-28 ⋅ 阅读:(346) ⋅ 点赞:(0)

OpenShift / RHEL / DevSecOps 汇总目录
文本已在 OpenShift 4.10 环境中进行验证。

为什么需要 Vault 保护 Secret

  1. Secret 不被加密,只是被 Base64 编码。
  2. 默认情况下,集群管理员可以看到所有租户的所有秘密。
  3. 当使用时(即作为tempfs安装在运行使用它们的pod的节点上),它们可以被节点管理员看到。
  4. 当使用时,任何有能力远程shell进入容器的人都可以看到它们。

Vault 的功能架构和重要概念

功能架构

Vault 功能架构由存储后端、屏障(Barrier)和 API 三部分构成:

  1. Barrier 提供 Vault 核心功能,包括对数据进行加密/解密,安全保护策略等核心功能。
  2. 存储端只负责保存经过加密的数据。
  3. Barrier 的功能是通过 API 对外提供服务访问。
    在这里插入图片描述

加密秘钥/root秘钥/unseal秘钥

  1. 当 Vault Server 首次启动,它处于 sealed 的状态。Vault 只有被 unsealed 后才可正常使用,这是通过以下初始化过程完成的。
  2. 初始化过程会生成一个加密密钥(Encryption Key),所有保存到存储后端的数据是被 Encryption Key 加密保护的。
  3. 由于 Encryption Key 非常重要,Vault 进而使用 root key(也叫 master key) 加密保护它。
  4. 为了增加安全,缺省时 Vault 会使用 unseal key 加密保护 root key,而 unseal key 又通过 Shamir 算法被分解为 5 个 key shares。只有使用任意 3 个 key shares 才能恢复出 unseal key,进而完成 Vault 的 unsealed 过程。
  5. 可以关闭 Shamir 功能,此时 root key 可以直接充当 unseal key 完成 Vault 的 unsealed 过程。
  6. 在 unsealed 完成后,Vault 就可以开始处理请求了。
  7. 在运行 Vault 的 Pod 重启后都需对 Vault 服务进行 unsealed。
    在这里插入图片描述

在 OpenShift 中安装 Vault

先执行命令创建一个项目。

$ oc new-project vault

安装 helm

执行以下命令安装 helm 客户端。注意:helm 客户端版本不能低于 3.7.0。

curl -OL https://mirror.openshift.com/pub/openshift-v4/x86_64/clients/helm/latest/helm-linux-amd64
chmod +x helm-linux-amd64
sudo mv helm-linux-amd64 /usr/local/bin/helm

安装方法1 - 使用在线 Chat 安装

  1. 执行命令,以 helm 参数方式安装 Vault。
helm repo add hashicorp https://helm.releases.hashicorp.com                        
helm install vault hashicorp/vault --set "global.openshift=true" -n vault
  1. 或者执行命令,以 helm 参数文件方式安装 Vault。
$ cat > override-values.yml << EOF   
global:
  openshift: true
EOF
$ helm install vault hashicorp/vault --values override-values.yml -n vault

安装方法2 - 使用本地 Chat 安装

  1. 执行命令下载 git repository。
$ git clone https://github.com/hashicorp/vault-helm.git && cd vault-helm
  1. 修改 values.yaml 文件中的以下内容,以适配 openshift:
global:
  openshift: true
server:
  route: true
ui:
  enabled: true
  1. 执行命令,安装 Vault
$ helm install vault . -n vault

HA 配置方法

缺省 helm 安装的 Vault 只运行了一个 Pod。如果要运行多个 Pod,可以根据以下文档配置 Vault HA。
https://www.vaultproject.io/docs/platform/k8s/helm/openshift

初始化 Vault

Vault 在非 Dev 模式 初次运行的时候需要手动进行初始化。而运行在 Dev 模式时则不需要,且 Dev 模式也不需要登录就能进行操作。

  1. 查看 Pod 运行状况,确认 vault-0 此时还没有 READY。
$ oc get pod -n vault
NAME                                    READY   STATUS    RESTARTS   AGE
vault-0                                 0/1     Running   0          14m
vault-agent-injector-7694ddd9c8-rt4ks   1/1     Running   0          14m
  1. 查看运行在 Pod 中 vault 服务的状态,此时为 “not initialized”。
$ oc exec -n vault -it vault-0 -- vault operator init -status
Vault is not initialized
  1. 执行命令对 vault 进行初始化。缺省生成 5 个 Unseal Key 用来初始化,以及用来登录 vault 的 Root Token。
$ oc exec -n vault -it vault-0 -- vault operator init
Unseal Key 1: nD9k1rKF117eWzFBvtJtIipGEgfIOOd8c6gzmg6sn4I/
Unseal Key 2: UOUDAX8qfFwo9Tm3NKFs9etH1hUcFusY7HOZNMt2qav0
Unseal Key 3: xzrW4OdERStQFmNxL587vvsHoJAtgEURCOX5AGaaw8+G
Unseal Key 4: R5LYcw1JRkTx7HgJyLG5yJC87QNYLK7tiO1qmCZndBRI
Unseal Key 5: PJFvN6BcYSwSoEn3MgATFk5F3TygkS2bjA0CFtZfring
 
Initial Root Token: hvs.x1zgG8FJrDbTwbsXd3lGff0R
 
Vault initialized with 5 key shares and a key threshold of 3. Please securely
distribute the key shares printed above. When the Vault is re-sealed,
restarted, or stopped, you must supply at least 3 of these keys to unseal it
before it can start servicing requests.
 
Vault does not store the generated root key. Without at least 3 keys to
reconstruct the root key, Vault will remain permanently sealed!
 
It is possible to generate new unseal keys, provided you have a quorum of
existing unseal keys shares. See "vault operator rekey" for more information.
  1. 使用任意 3 个 Unseal Key 对 vault 进行解封。其中最后一次的返回结果可以看到 “Initialized true” 和 “Sealed false”。
$ oc exec -n vault -it vault-0 -- vault operator unseal UOUDAX8qfFwo9Tm3NKFs9etH1hUcFusY7HOZNMt2qav0
$ oc exec -n vault -it vault-0 -- vault operator unseal R5LYcw1JRkTx7HgJyLG5yJC87QNYLK7tiO1qmCZndBRI
$ oc exec -n vault -it vault-0 -- vault operator unseal PJFvN6BcYSwSoEn3MgATFk5F3TygkS2bjA0CFtZfring
Key             Value
---             -----
Seal Type       shamir
Initialized     true
Sealed          false
Total Shares    5
Threshold       3
Version         1.11.3
Build Date      2022-08-26T10:27:10Z
Storage Type    file
Cluster Name    vault-cluster-3410c84e
Cluster ID      42b53221-79a2-0e99-b829-5c03c7e4bd47
HA Enabled      false
 
$ oc exec -n vault -it vault-0 -- vault operator init -status
Vault is initialized
  1. 此时 vault-0 也正常运行了。
$ oc get pod -n vault
NAME                                    READY   STATUS    RESTARTS   AGE
vault-0                                 1/1     Running   0          22m
vault-agent-injector-7694ddd9c8-rt4ks   1/1     Running   0          22m

在 Vault 中创建 Secret

  1. 执行命令进入 vault-0,然后使用 Root Token 登录 vault。
$ oc exec -it vault-0 -- /bin/sh
/ $ vault login hvs.x1zgG8FJrDbTwbsXd3lGff0R
Success! You are now authenticated. The token information displayed below
is already stored in the token helper. You do NOT need to run "vault login"
again. Future Vault requests will automatically use this token.
 
Key                  Value
---                  -----
token                hvs.x1zgG8FJrDbTwbsXd3lGff0R
token_accessor       92NNktwJFOmyJUpIt7dL1Pyz
token_duration       ∞
token_renewable      false
token_policies       ["root"]
identity_policies    []
policies             ["root"]
  1. 执行命令,在路径 demo 中使用 kv 类型的 secret。
/ $ vault secrets enable -path=demo kv-v2
Success! Enabled the kv-v2 secrets engine at: demo/
  1. 查看 secrets 列表。
/ $ vault secrets list
Path          Type         Accessor              Description
----          ----         --------              -----------
cubbyhole/    cubbyhole    cubbyhole_77836f77    per-token private secret storage
demo/         kv           kv_0b4114a4           n/a
identity/     identity     identity_5b7025d2     identity store
sys/          system       system_769e90e6       system endpoints used for control, policy and debugging
  1. 在 demo/secret 中存放 2 个数据。
/ $ vault kv put demo/secret username="db-username" password="db-password"
== Secret Path ==
demo/data/secret
 
======= Metadata =======
Key                Value
---                -----
created_time       2022-09-24T11:20:21.952458161Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            1
  1. 查看在 demo/secret 中存放的数据。
/ $ vault kv get demo/secret
== Secret Path ==
demo/data/secret
 
======= Metadata =======
Key                Value
---                -----
created_time       2022-09-24T11:20:21.952458161Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            1
 
=== Data ===
Key         Value
---         -----
password    db-password
username    db-username
  1. 向 demo/secret 中追加其他数据,注意此时 version 已经变为 2。
/ $ vault kv patch demo/secret k3=v3
== Secret Path ==
demo/data/secret
 
======= Metadata =======
Key                Value
---                -----
created_time       2022-09-24T12:08:08.742365356Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            2
  1. 再次查看在 demo/secret 中存放的数据,确认已有新数据。
/ $ vault kv get demo/secret
== Secret Path ==
demo/data/secret
 
======= Metadata =======
Key                Value
---                -----
created_time       2022-09-24T12:20:21.952458161Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            2
 
=== Data ===
Key         Value
---         -----
k3          v3
password    db-password
username    db-username
  1. 对 demo/secret 的数据进行回滚,此时 version 变为 3。
/ $ vault kv rollback -version=1 demo/secret
Key                Value
---                -----
created_time       2022-09-24T12:11:35.640648124Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            3
  1. 再次查看在 demo/secret 中存放的数据,确认又恢复为 2 个数据。
/ $ vault kv get demo/secret
== Secret Path ==
demo/data/secret
 
======= Metadata =======
Key                Value
---                -----
created_time       2022-09-24T12:11:35.640648124Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            3
 
=== Data ===
Key         Value
---         -----
password    db-password
username    db-username

在 OpenShift 应用中使用 Vault 的 Secret

通过 Vault Agent Injector 将 Secret 数据注入到应用 Pod

此种方法是使用 Vault 的 Agent Injector 根据应用部署的 annotation 在应用 pod 中自动生成 sidecar 容器,将带有 Secret 的文件注入挂载到应用 Pod 的 /vault 目录。
在这里插入图片描述

设置访问 Vault Secret 的权限

  1. 在 vault-0 中执行以下命令,允许使用 Kubernetes Auth。
/ $ vault auth enable kubernetes
/ $ vault write auth/kubernetes/config \
    token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
    kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:443" \
    kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
  1. 创建名为 my-vault-app 的 Vault 访问策略,允许读取 “demo/data/secret” 中的数据。
/ $ vault policy write my-vault-app - << EOF
path "demo/data/secret" {
  capabilities = ["read"]
}
EOF
  1. 设置名为 my-vault-app 的 Vault 角色,允许 my-vault-app 命名空间中名为 my-vault-app 的 ServiceAccount 使用 my-vault-app 访问策略。
/ $ vault write auth/kubernetes/role/my-vault-app \
  bound_service_account_names=my-vault-app \
  bound_service_account_namespaces=my-vault-app \
  policies=my-vault-app \
  ttl=24h

从测试应用中访问 Secret

  1. 执行命令创建 my-vault-app 命名空间,然后在其中创建名为 my-vault-app 的 ServiceAccount。
oc new-project my-vault-app
oc create serviceaccount my-vault-app -n my-vault-app
  1. 执行命令部署测试应用,其中包含了生成注入 sidecar 容器的注释。
$ oc apply -f - << EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: vault-demo-app
spec:
  selector:
    matchLabels:
      app: vault-demo-app
  replicas: 1
  template:
    metadata:
      labels:
        app: vault-demo-app
      annotations:
        vault.hashicorp.com/agent-inject: "true" 
        vault.hashicorp.com/role: "my-vault-app" 
        vault.hashicorp.com/agent-inject-secret-db.txt: "demo/data/secret"
        vault.hashicorp.com/agent-inject-template-db.txt: |
          {{- with secret "demo/data/secret" -}}
          username: {{ .Data.data.username }}
          password: {{ .Data.data.password }}
          {{- end -}} 
    spec:
      serviceAccountName: my-vault-app
      containers:
        - name: vault-demo-app
          image: rshrestha13/vault-demo-app
EOF
  1. 确认部署运行的 Pod 中包含了 2 个容器
$ oc get pod
NAME                              READY   STATUS        RESTARTS   AGE
vault-demo-app-7f4d8d7df7-qb9lh   2/2     Running       0          18s
  1. 进入 vault-demo-app 部署对应的 Pod,然后查看通过 sidecar 容器挂载到 /vault/secrets/db.txt 文件中的内容。
$ oc exec -n my-vault-app deploy/vault-demo-app -- cat /vault/secrets/db.txt
Defaulted container "vault-demo-app" out of: vault-demo-app, vault-agent, vault-agent-init (init)
username: db-username
password: db-password[

参考

https://cloud.redhat.com/blog/integrating-hashicorp-vault-in-openshift-4
https://www.vaultproject.io/docs/platform/k8s/helm/openshift
https://learn.hashicorp.com/tutorials/vault/kubernetes-openshift
http://reborncodinglife.com/2022/01/12/install-vault-in-ocp4/
https://medium.com/hybrid-cloud-engineering/vault-integration-into-openshift-container-platform-b57c175a79da
https://cloud.redhat.com/blog/external-secrets-with-hashicorp-vault
https://blog.stderr.at/openshift/2022-08-16-hashicorp-vault/
https://github.com/raif-ahmed/oc4-learn/tree/master/secret-managment/external-secrets
https://github.com/openlab-red/hashicorp-vault-for-openshift
https://github.com/openlab-red/hashicorp-vault-for-openshift/blob/master/articles/Secure%20Cloud%20Native%20App.md
https://www.goglides.dev/bkpandey/how-to-manage-secrets-in-openshiftkubernetes-using-vault-and-external-secrets-1n6k

https://external-secrets.io/v0.6.0-rc1/provider/hashicorp-vault/
https://github.com/raif-ahmed/oc4-learn/tree/master/secret-managment/external-secrets

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到