【翻译】教程。如何用Azure KeyVault设置外部秘密

在本教程中,我们将配置Azure KeyVault,以便有一个安全的方式来访问秘密,然后配置External-Secrets,以便从我们的秘密管理器中获取信息,这是我们关于External Secrets项目系列的最后一个教程。你可以在这里找到这个系列的其他文章。

在我们开始之前,如果你是这个系列的新手,可能需要快速回顾一下。由Container Solutions和GoDaddy发起的External Secrets是一个开源的Kubernetes运营商,整合了外部秘密管理系统,包括AWS Secrets Manager、HashiCorp Vault、Google Secrets Manager、Azure Key Vault和其他。该项目在CS实验室的指导下进行管理,旨在实现将秘密从外部API同步到Kubernetes。你可以在这里找到全面的项目文件。

开始学习

为了正确地学习本教程,请确保你已经安装了以下工具。

配置

External Secrets支持为Azure KeyVault提供商配置几种认证方法。在本指南中,我们使用的是通过客户端ID和秘密进行认证,因为这不需要任何其他Azure资源。我们将通过以下步骤。

1.设置Azure KeyVault
2.配置外部机密

设置Azure KeyVault

下面的步骤都是要用Azure CLI的。我们首先要做的是设置我们的KeyVault实例。

TENANT_ID=$(az account show --query tenantId | tr -d \") RESOURCE_GROUP="MyKeyVaultResourceGroup" LOCATION="westus" az group create --location $LOCATION --name $RESOURCE_GROUP VAULT_NAME="eso-vault-example" az keyvault create --name $VAULT_NAME --resource-group $RESOURCE_GROUP

之后,我们可以在KeyVault内创建一个秘密。

SECRET_NAME="example-externalsecret-key" SECRET_VAlUE="这就是我们现在的秘密" az keyvault secret set --name $SECRET_NAME --vault-name $VAULT_NAME --value "$SECRET_VAlUE"

下一步是创建一个应用程序,External Secrets将用来访问KeyVault实例。我们还用应用程序的凭证创建一个秘密。

APP_NAME="ExtSectret Query App" APP_ID=$(az ad app create --display-name "$APP_NAME" --query appId | tr -d /") SERVICE_PRINCIPAL=$(az ad sp create --id $APP_ID --az ad app permission add --id $APP_ID --api-permissions f53da476-18e3-4152-8e01-ec403e6edc0=Scope --api cfa8b339-82a2-471a-a3c9-0fc0be7a4093 APP_PASSWORD="ThisisMyStrongPassword" az ad app credential reset --id $APP_ID --password "$APP_PASSWORD" az keyvault set-policy --name $VAULT_NAME --object-id $SERVICE_PRINCIPAL --secret-permissions get kubectl create secret generic azure-secret-sp --from-literal=ClientID=$APP_ID --from-literal=ClientSecret=$APP_PASSWORD

配置外部秘密

设置完Azure KeyVault后,下一步是创建一个SecretStore 和一个ExternalSecrets 来获取我们之前创建的example-external secret-key对象。

cat << EOF | kubectl apply -f - apiVersion: external-secrets.io/v1alpha1 kind: SecretStore metadata: name: azure-backend spec: provider: azurekv: tenantId:$TENANT_ID vaultUrl:"https://$VAULT_NAME.vault.azure.net" authSecretRef: clientId: name: azure-secret-sp key:clientID clientSecret: name: azure-secret-sp key:ClientSecret --- apiVersion: external-secrets.io/v1alpha1 kind:ExternalSecret metadata: name: azure-example spec: refreshInterval: 1h secretStoreRef: kind: SecretStore name: azure-backend target: name: azure-secret data: - secretKey: foobar remoteRef: key: example-externalsecret-key EOF

就这样了!我们可以检查我们的Secret是否已经在Kubernetes中被创建。

kubectl get secret azure-secret -o jsonpath='{.data.foobar}' | base64 -d 这就是我们的秘密了。

我们还可以检查ExternalSecrets的状态信息。

kubectl get es NAME STORE REFRESH INTERVAL STATUS azure-example azure-backend 1h SecretSynced

部署一个准入控制器来限制ExternalSecrets的访问

在写这篇文章的时候,你可能已经注意到Azure Key Vault不支持对秘密阅读的细化权限。对于生产环境来说,这种行为往往是不可接受的,特别是在有多个团队和坚实的治理的组织中。

缓解这种情况的一个方法是,为每个团队使用不同的Azure KeyVault实例。要做到这一点,我们只需遵循相同的程序,并创建一个新的SecretStore,指向新提供的凭证。

然而,根据特定公司的拓扑结构,这种解决方案要求我们为每个团队的每个命名空间创建SecretStore和Secrets凭证,这有两个问题:在任何规模的情况下都变得不切实际,而且还会带来安全问题,如将应用凭证暴露给开发人员。

一个更好的解决方法是创建或使用自定义接纳控制器来验证任何ExternalSecrets清单的创建,并防止使用该特定命名空间中不允许使用的特定键。

在本指南中,我们将使用OPA Gatekeeper作为我们的准入控制器,但类似的行为也可以通过Kyverno实现。我们将安装Gatekeeper,并配置它来验证ExternalSecret的命名空间是否允许ExternalSecret想要访问的远程引用。你可以看一下下面的图片,以便更好地了解它。

Azure Gatekeeper overview diagram第一步是按照他们的安装指南,在我们的集群中安装Gatekeeper。

kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/release-3.7/deploy/gatekeeper.yaml

下一步是配置Gatekeeper来跟踪命名空间资源。这将被用作读取我们将要创建的重合注释的方式。

cat << EOF | kubectl apply -f - apiVersion: config.gatekeeper.sh/v1alpha1 kind:配置元数据: 名称: config 命名空间。"gatekeeper-system" spec: sync: syncOnly: - group:"" 版本。"v1" kind: "Namespace" EOF

然后,我们创建一个约束模板,以阻止任何即将到来的、与注解提供的给定重码不匹配的请求。

apiVersion: templates.gatekeeper.sh/v1beta1 kind:ConstraintTemplate 元数据: name: esovalidatesecretreference 注释: description: >- 验证所有秘密引用是否与CSS上的重码匹配。 spec: crd: spec: names: kind:EsoValidateSecretReference验证:openAPIV3Schema:类型:对象属性:注解:类型:字符串描述: >-注解验证要应用的重码目标: - 目标:admission.k8s.gatekeeper.sh rego:| 违反[{"msg": msg}] { namespace := input.review.object.metadata.namespace target := data.involution.cluster["v1"]["Namespace"][namespace] not target.metadata.annotations[input.parameters.annotation] msg := sprintf("namespace %v not allowed to receive secrets(missing annotation %v)",[namespace, input.违反[{"msg": msg}] { namespace := input.review.object.metadata.namespace secretrefs := input.review.object.spec.dataFrom[_].key target := data.cory.cluster["v1"]["namespace"][namespace] regex := target.命名空间]} violation[{"msg": msg}] { namespace := input.review.object.metadata.namespace secretrefs := input.review.object.spec.data[_].remoteRef.key target := data.catalogue.cluster["v1"]["namespace"][namespace] regex := target.metadata.annotations[input.parameters.annotation] not re_match(regex, secretrefs) msg := sprintf("Data key remote ref %v not allowed in namespace %v", [secretrefs, namespace] ) }

这个约束模板包含三个违规条款。

第一个子句检查命名空间是否包含适当的注释(如果不包含,则失败),第二个子句防止dataFrom的任何键与提供的正则表达式不同,而第三个子句防止data.remoteRef的任何键与提供的正则表达式不同。

在创建了我们的约束模板后,下一步是定义一个使用它的约束。

cat << EOF | kubectl apply -f - apiVersion: constraints.gatekeeper.sh/v1beta1 kind:EsoValidateSecretReference元数据: name: validate-css-with-regex-on-path spec: match: kinds: - apiGroups: ["External-secrets.io"] kinds:["External-secret"] 参数:注释。"external-secrets.io/match-regex" EOF

有了这个约束,要想在给定的命名空间中创建一个ExternalSecret,必须发生三件事。

1.该命名空间必须包含注释"external-secrets.io/match-regex"
2.其所有的data.remoteRef.key值必须符合指定的正则表达式。
3.其所有的dataFrom.key值必须符合指定的正则表达式。

我们可以通过用下面的正则表达式注释命名空间default 来测试它,它允许任何以key-team-1开头的秘密密钥。

kubectl annotate ns default external-secrets.io/match-regex="^key-team-1.*"

现在,让我们尝试创建与之前相同的ExternalSecrets

cat <<EOF | kubectl apply -f - apiVersion: external-secrets.io/v1alpha1 kind:ExternalSecret metadata: name: opa-example spec: refreshInterval: 1h secretStoreRef: kind: SecretStore name: azure-backend target: name: azure-secret data: - secretKey: foobar remoteRef: key: example-externalsecret-key EOF Error from server ([validate-css-with-regex-onpath] Data key remote ref example-externalsecret-key not allowed in namespace default) : error when creating "STDIN": admission webhook "validation.gatekeeper.sh "拒绝了请求:[validate-css-with-regex-on-path] Data key remote ref example-externalsecret-key not allowed in namespace default

正如我们所看到的,这个清单不再被授权使用,因为它引用了一个未经授权的远程参考钥匙,尽管我们刚刚从我们的例子中改变了名称

让我们在Azure KeyVault中添加一个新的秘密,并改变ExternalSecrets的定义。

az keyvault secret set --name "key-team-1-database" --vault-name $VAULT_NAME --value "database-dns" cat << EOF | kubectl apply -f - apiVersion: external-secrets.io/v1alpha1 kind:ExternalSecret metadata: name: opa-example spec: refreshInterval:"15s" secretStoreRef: name: azure-backend kind: SecretStore target: name: example-sync data: - secretKey: foobar remoteRef: key: key-team-1-database EOF externalsecret.external-secrets.io/opa-example created

这就是了!一旦安装了准入控制器,就可以为ExternalSecrets对象添加基于属性的访问控制。应用这些配置可以让我们在不给集群管理团队增加更大负担的情况下对我们的秘密进行细化控制。

如果你需要对你的特定设置进行特殊配置,也可以配置ExternalSecrets可以引用哪些SecretStores/ClusterSecretStores。请参考Gatekeeper策略库中的例子,了解如何做到这一点。

总结

在这最后一篇文章中,我们看到了如何配置外部秘密以允许使用Azure KeyVault提供商。

总结一下我们所做的一切。

  • 设置Azure Keyvault
  • 配置外部机密
  • 使用OPA守门员来进一步添加访问控制规则

我希望你们都喜欢读这个系列的文章,就像我喜欢写这个系列的文章一样!

Download our free eBook: WTF is the External Secrets Operator

猜你喜欢

转载自blog.csdn.net/community_717/article/details/128745010