使用ExternalSecret在EKS中将Vault的数据(kv)作为密钥加载进来
外部秘密是指的是什么?

通常情况下,在使用EKS的ExternalSecret时,我们通常会从SecretManager中获取值,但这次是从Vault中获取值的验证记录。
安装外部密钥操作员
按照官方网站的“入门指南”,安装外部密钥操作员。
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。
我也要安装Vault。请参考官方步骤获取详细信息,这里只是简单记录一下我完成的步骤。
helm repo add hashicorp https://helm.releases.hashicorp.com
helm show values hashicorp/vault > vault-values.yaml
helm upgrade -i -f vault-values.yaml vault -n vault --create-namespace hashicorp/vault
将vault-values.yaml文件更改为使用Ingress。
在Vault启动后执行解封操作。如果不进行解封操作,Pod将持续抛出以下错误,并无法完成启动。
2022-08-04T03:28:40.124Z [INFO] core: seal configuration missing, not initialized
2022-08-04T03:28:45.090Z [INFO] core: security barrier not initialized
可以通过使用`vault operator init`命令来获取解封(unseal)所需的密钥和令牌。
kubectl exec -ti vault-0 -n vault -- vault operator init
這個初始的根令牌會用於不同的用途,所以需要備份保存。使用 unseal key 來進行解封。
kubectl exec -ti vault-0 -n vault -- vault operator unseal
进行3次解封操作后,将获得以下的输出,使Vault可用。
Key Value
--- -----
Seal Type shamir
Initialized true
Sealed false
Total Shares 5
Threshold 3
Version 1.10.3
Storage Type file
Cluster Name vault-cluster-44f5b753
Cluster ID d4b134d3-6888-37a1-dba4-3b7063a61a80
HA Enabled false
Vault的设置
在这里,将样本数据投入到Vault内,并创建访问策略。
此处的描述基本上是参考以下信息的。
-
- https://www.vaultproject.io/docs/auth/kubernetes
- https://learn.hashicorp.com/tutorials/vault/agent-kubernetes
从本地PC使用vault命令访问Helm Vault的入口点。
export VAULT_ADDR=https://vault.mydomain.info
vault login
由於默認情況下未啟用KeyValue引擎,所以將其啟用。
vault secrets enable kv
输入Key和Value的示例数据。
vault kv put kv/mysecret password=himitsu
确认。
$ vault kv get kv/mysecret
====== Data ======
Key Value
--- -----
password himitsu
接下来要创建政策。
cat <<EOF > /tmp/vault_sample_policy.hcl
path "*" {
capabilities = ["read", "list"]
}
EOF
分配策略。按照教程,将策略命名为myapp-kv-ro。
vault policy write myapp-kv-ro /tmp/vault_sample_policy.hcl
创建一个可以操作Kubernetes中资源的ServiceAccount。这次根据教程在默认的Namespace中创建了该账户。由于在权限上遇到了一些问题,所以我将其设为了cluster-admin,但我认为可以更细化权限。
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
name: vault-auth
namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: role-tokenreview-binding
namespace: default
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: vault-auth
namespace: default
EOF
启用Kubernetes的身份验证,并添加认证信息。
vault auth enable kubernetes
export SA_SECRET_NAME=$(kubectl get secrets --output=json \
| jq -r '.items[].metadata | select(.name|startswith("vault-auth-")).name')
export SA_JWT_TOKEN=$(kubectl get secret $SA_SECRET_NAME \
--output 'go-template={{ .data.token }}' | base64 --decode)
export SA_CA_CRT=$(kubectl config view --raw --minify --flatten \
--output 'jsonpath={.clusters[].cluster.certificate-authority-data}' | base64 --decode)
export K8S_HOST=$(kubectl config view --raw --minify --flatten \
--output 'jsonpath={.clusters[].cluster.server}')
vault write auth/kubernetes/config \
token_reviewer_jwt="$SA_JWT_TOKEN" \
kubernetes_host="$K8S_HOST" \
kubernetes_ca_cert="$SA_CA_CRT" \
issuer="https://kubernetes.default.svc.cluster.local"
只要没有问题,应该会得到以下信息作为vault write auth/kubernetes/config的结果。
Success! Data written to: auth/kubernetes/config
接下来创建一个角色。角色名称为hoge。
vault write auth/kubernetes/role/hoge \
bound_service_account_names=vault-auth \
bound_service_account_namespaces=default \
policies=myapp-kv-ro \
ttl=24h
此外,如果您更改了ServiceAccount的名称、Namespace或策略名称,请相应地修改并执行。
vault write auth/kubernetes/login role=hoge jwt=$SA_JWT_TOKEN iss=https://kubernetes.default.svc.cluster.local
将Vault的Secrets部署到EKS上。
使用SecretStore资源与Vault进行连接。
cat << EOF | kubectl apply -f -
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: vault-backend
spec:
provider:
vault:
server: "https://vault.mydomain.info"
path: "kv"
version: "v1"
namespace: "default"
auth:
kubernetes:
mountPath: "kubernetes"
role: "hoge"
serviceAccountRef:
name: "vault-auth"
EOF
另外,如果將版本設置為”v2″,在創建ExternalSecret時可能會出現以下錯誤,導致Secret無法成功創建。我也遇到了這個問題,卡在這裡一段時間。
"cannot read secret data from Vault: Error making API request.\n\nNamespace: default\nURL: GET https://vault.mydomain.info/v1/kv/data/mysecret\nCode: 404.
因此,我参考了这篇文章并进行了v1的修改,以避免这个问题。
※补充:
通过GUI创建KV时成为v2版本,通过CLI创建也是v2版本。通过GUI创建的人需要选择v2版本或不指定版本。
确认状态。
$ kubectl get secretstore
NAME AGE STATUS
vault-backend 8s Valid
另外,如果有设置错误等问题,就会出现以下情况。
$ kubectl get secretstore.external-secrets.io/vault-backend
NAME AGE STATUS
vault-backend 9m50s InvalidProviderConfig
在这种情况下,如果忘记设置ServiceAccount,则external-secrets的Pod内会出现类似于Code: 500. Errors: * service account name not authorized的错误。请根据错误信息确认发生了什么。
接下来,将ExternalSecret作为Kubernetes的Secret资源进行导入。
cat <<EOF | kubectl apply -f -
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: vault-example
spec:
secretStoreRef:
name: vault-backend
kind: SecretStore
target:
name: vault-example-secret
data:
- secretKey: fuga
remoteRef:
key: mysecret
property: password
EOF
spec.target.name是创建的Secret的名称,spec.data.secretKey是创建的Secret中的Key。spec.data.remoteRef用于设置Vault端的路径(去除SecretStore指定的路径部分)和Key-Value的key(属性)。
如果在创建上述资源后,状态变为SecretSynced,则表示一切正常。
$ kubectl get externalsecret
NAME STORE REFRESH INTERVAL STATUS
vault-example vault-backend 1h SecretSynced
可以察觉到已创建了Secret,并且可以从Vault中提取值。
$ kubectl get secret vault-example-secret -o jsonpath={.data.fuga} | base64 -d
himitsu