使用外部秘密操作者和保险库进行组合利用
“External Secret Operator是指外部秘密运营商。”
外部秘密运营商(ESO)是一种用于在Kubernetes上管理外部秘密的软件。以下文章列举了一些特点,但我认为最重要的是在实施GitOps时变得更容易管理秘密。您可以实现GitOps而无需将秘密信息提交到GitHub。
我们将使用Hashicorp Vault作为外部的秘密管理器。
前提条件
-
- Vaultを知っている
- Kubernetesを知っている
环境
-
- Windows11 (wsl2)
-
- Kubernetes version 1.25.3 (kind構築)
- Vault version 1.12
验证
这次要做的事情
-
- ESOインストール
-
- Vault のKubernetes authを利用する認証設定
- 動作確認
安装ESO
ESO的安装非常简单,只需执行以下helm命令即可。
helm repo add external-secrets https://charts.external-secrets.io
helm install external-secrets \
external-secrets/external-secrets \
-n external-secrets \
--create-namespace \
--set installCRDs=true
准备秘密数据
我会将测试数据注册到Vault中。
这次只需确认ESO的功能,所以我注册了”my-value=mysecret”。
/ $ vault secrets enable -path=eso -version=2 -description="This secret engine is used the ESO to get secrets" kv
Success! Enabled the kv secrets engine at: eso/
/ $ vault kv put eso/foo my-value=mysecret
== Secret Path ==
eso/data/foo
======= Metadata =======
Key Value
--- -----
created_time 2023-02-04T10:19:04.717624389Z
custom_metadata <nil>
deletion_time n/a
destroyed false
version 1
Kubernetes验证准备完成。
ESO可以使用的认证方式有5种。
-
- token-based
-
- appRole
-
- kubernetes-native
-
- ldap
- jwt/oidc
这次我们将验证最容易使用的Kubernetes auth。原因将在最后稍作说明。
在验证过程中,我们参考了以下页面。
https://cloud.redhat.com/blog/vault-integration-using-kubernetes-authentication-method#:~:text=Kubernetes%20Auth%20Method%20The%20Kubernetes%20authentication%20method%20can,%2Fvar%2Frun%2Fsecrets%2Fkubernetes.io%2Fserviceaccount%2Ftoken%20and%20is%20sent%20to%20Vault%20for%20authentication.
「system:auth-delegator」是Kubernetes的默认角色。
kubectl create sa vault-auth -n vault
kubectl create clusterrolebinding k8s-auth-client-for-vault --clusterrole=system:auth-delegator --serviceaccount=vault:vault-auth
在进行Kubernetes身份验证时,Vault所需的有以下三个方面。
-
- Service Account的令牌
-
- kubernetes API服务器的端点
- Kubernetes集群的CA证书
首先,我们需要创建以下资源以获取Service Account的密钥。
kubectl apply -f vault-auth.yaml -n vault
apiVersion: v1
kind: Secret
metadata:
name: vault-auth
annotations:
kubernetes.io/service-account.name: "vault-auth"
type: kubernetes.io/service-account-token
2号和3号可以分别从Kubernetes配置文件中获取,所以现在已经准备好了。
在进行格式化的同时,获取以下数值。
请注意,Service Account的令牌和CA证书是通过base64编码的,所以需要注意。如果搞错了,身份验证将无法成功。
token_reviewer_jwt=$(kubectl get secret -n vault -o jsonpath='{.data.token}' vault-auth | base64 -d)
kubernetes_host=https://kubernetes.default.svc.cluster.local # vault がKubernetes API Serverにアクセスするために必要
kubernetes_ca_cert=$(kubectl config view -o jsonpath='{.clusters[].cluster.certificate-authority-data}' --minify=true --raw | base64 -d)
Kubernetes授權配置
使用下列命令在Kubernetes中启用身份验证。
将角色名称设置为”eso-vault”,策略是先前创建的角色。
vault auth enable -description="k8s secret engine for vault" kubernetes
vault write auth/kubernetes/config \
token_reviewer_jwt=$token_reviewer_jwt \
kubernetes_host=$kubernetes_host \
kubernetes_ca_cert=$kubernetes_ca_cert
vault write auth/kubernetes/role/eso-vault \
bound_service_account_names=vault-auth \
bound_service_account_namespaces=vault \
policies=default,eso-vault-client \
ttl=15m
ESO准备就绪。
我会设置 ESO 请求的角色。
vault policy write eso-vault-client eso-vault-client.hcl
path "eso/data/*" {
capabilities = ["read"]
}
确认动作。 如果返回以下结果,就可以了。
/ $ vault write auth/kubernetes/login role=eso-vault jwt=$token_reviewer_jwt
Key Value
--- -----
token hvs.CAESIKQznRS1XNprF8eQjF_zZFlL8Da9jCHRmhCvTE3F5aP9Gh4KHGh2cy5IMGo1SHd0eU9ldzhIc00wZEJ2WG1MZGs
token_accessor dmRuQwUOUugmuXzqPEIwzVxl
token_duration 1m
token_renewable true
token_policies ["default" "eso-vault-client"]
identity_policies []
policies ["default" "eso-vault-client"]
token_meta_role eso-vault
token_meta_service_account_name vault-auth
token_meta_service_account_namespace vault
token_meta_service_account_secret_name vault-auth
token_meta_service_account_uid d35d56fd-24f3-45b8-a1e9-20b15a08f172

从ESO网站引用,https://external-secrets.io/v0.7.2/provider/hashicorp-vault/。
首先,我们将每个设置都以yaml格式编写。
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
name: vault-backend-k8s-auth
labels:
service: secret-manager
version: 1.0.0
env: prd
spec:
provider:
vault:
server: http://vault.vault.svc.cluster.local:8200 # 接続先のVault Cluster
path: eso
version: v2
auth:
kubernetes:
# Path where the Kubernetes authentication backend is mounted in Vault
mountPath: kubernetes # 有効にしたkubernetes auth。今回はデフォルトなのでkubernetes
# A required field containing the Vault Role to assume.
role: eso-vault # 作成したvaultのrole名
# Optional service account field containing the name
# of a kubernetes ServiceAccount
serviceAccountRef:
name: vault-auth
namespace: vault
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: vault-eso-example
spec:
refreshInterval: 15s
secretStoreRef:
name: vault-backend-k8s-auth # 利用するSecretStoreの名前
kind: ClusterSecretStore
target:
name: output-secret # 作成するsecretの名前
data:
- secretKey: foobar # 作成するSecretのKeyの名前
remoteRef:
# vault kv put eso/foo my-value=mysecretで作成したシークレットを取得する設定
key: eso/foo
property: my-value
如果使用没有报错,就可以了。获取Secret的动机需要大约10秒钟。
kubectl apply -f ./secret-store-k8s-es.yaml
kubectl apply -f ./secret-store-k8s-ss.yaml
root@mypc02:/mnt/e/work/eso# kc get clustersecretstores.external-secrets.io,externalsecrets.external-secrets.io
NAME AGE STATUS CAPABILITIES READY
clustersecretstore.external-secrets.io/vault-backend-k8s-auth 26m Valid ReadWrite True
NAME STORE REFRESH INTERVAL STATUS READY
externalsecret.external-secrets.io/vault-eso-example vault-backend-k8s-auth 15s SecretSynced True
确认行动
最后,获取Secret并确认其值。
root@mypc02:/mnt/e/work/eso# kc get secret
NAME TYPE DATA AGE
output-secret Opaque 1 76s
root@mypc02:/mnt/e/work/eso# kc get secret output-secret -o yaml | grep data: -A1
data:
foobar: bXlzZWNyZXQ=
root@mypc02:/mnt/e/work/eso# echo bXlzZWNyZXQ= | base64 -d
mysecret
最后
为了成功避免在本次中将Kubernetes的Secret信息提交到GitHub上,我们进行了ESO的验证。虽然在实际应用中可能有一些需要考虑的地方,但我觉得它非常易用。由于一开始没有考虑选择kubernetes auth的原因,所以我会稍后提及。但由于未经验证,所以无法确定是否正确,请仅作为参考。
首先,我们排除了ldap和jwt/oidc,因为它们不适用于M2M身份验证。
对于基于令牌的认证,我对其为静态认证方式以及ttl和max-ttl的更新有些担忧。根据ttl和max-ttl的设定,可能需要定期手动更新,这让我感到有些不便。
虽然approle是一种动态认证方式,但我仍然认为它需要更新ttl和max-ttl,需要另外实现更新的机制。
谢谢您阅读完以上内容,到此为止。