1. Introduction
1.导言
In this tutorial, we’ll explore different ways to access secrets stored in Hashicorp’s Vault from an application running on Kubernetes.
在本教程中,我们将探索从 Kubernetes 上运行的应用程序访问存储在 Hashicorp Vault 中的秘密的不同方法。
2. Quick Recap
2.快速回顾
We’ve already covered Hashicorp’s Vault in earlier tutorials, where we’ve shown how to install and populate it with secrets. In a nutshell, Vault provides a secure storage service for application secrets, which can be either static or dynamically generated.
我们已经在 较早的 教程中介绍过 Hashicorp 的 Vault,并在其中演示了如何安装和填充秘密。简而言之,Vault 为应用程序秘密提供安全存储服务,这些秘密可以是静态生成的,也可以是动态生成的。
To access Vault services, an application must authenticate itself using one of the available mechanisms. When the application runs in a Kubernetes environment, Vault can authenticate it based on its associated service account, thus eliminating the need for separate credentials.
要访问 Vault 服务,应用程序必须使用其中一种可用机制进行身份验证。当应用程序在 Kubernetes 环境中运行时,Vault 可根据其关联的服务帐户对其进行身份验证,因此无需单独的凭证。
In this scenario, the Kubernetes service account is bound to a Vault role, which defines the associated access policy. This policy defines which secrets an application can have access to.
在这种情况下,Kubernetes 服务账户与 Vault 角色绑定,后者定义了相关的访问策略。该策略定义了应用程序可以访问的机密。
3. Providing Secrets to Applications
3.为应用程序提供秘密
In Kubernetes environments, a developer has multiple options to get a Vault-managed secret, which can be classified as more or less intrusive. “Intrusive”, in this context, relates to the level of awareness the application has about the origin of the secrets.
在 Kubernetes 环境中,开发人员有多种选择来获取 Vault 管理的秘密,这些选择可分为侵扰性较强或较弱两种。在这种情况下,”侵入 “与应用程序对秘密来源的认知程度有关。
Here’s a summary of the methods we’ll cover:
以下是我们将介绍的方法摘要:
- Explicit retrieval using Vault’s API
- Semi-explicit retrieval using Spring Boot’s Vault support
- Transparent support using Vault Sidecar
- Transparent support using Vault Secret CSI Provider
- Transparent support using Vault Secret Operator
4. Authentication Setup
4.身份验证设置
In all those methods, the test application will use Kubernetes authentication to access Vault’s API. When running inside Kubernetes, this would be automatically provided. However, to use this kind of authentication from outside the cluster, we need a valid token associated with a service account.
在所有这些方法中,测试应用程序将使用 Kubernetes 身份验证来访问 Vault 的 API。在 Kubernetes 内部运行时,会自动提供这种验证。不过,要在集群外部使用这种身份验证,我们需要一个与服务账户关联的有效令牌。
One way to achieve this is to create a service account token secret. Secrets and service accounts are namespace-scoped resources, so let’s start by creating a namespace to hold them:
实现这一目标的方法之一是创建服务帐户令牌秘密。秘密和服务账户都是命名空间范围内的资源,因此我们首先要创建一个命名空间来存放它们:
$ kubectl create namespace baeldung
Next, we create the service account:
接下来,我们创建服务账户:
$ kubectl create serviceaccount --namespace baeldung vault-test-sa
Finally, let’s generate a token valid for 24 hours and save it to a file:
最后,让我们生成一个有效期为 24 小时的令牌,并将其保存到文件中:
$ kubectl create token --namespace baeldung vault-test-sa --duration 24h > sa-token.txt
Now, we need to bind the Kubernetes service account with a Vault role:
现在,我们需要将 Kubernetes 服务账户与 Vault 角色绑定:
$ vault write auth/kubernetes/role/baeldung-test-role \
bound_service_account_names=vault-test-sa \
bound_service_account_namespaces=baeldung \
policies=default,baeldung-test-policy \
ttl=1h
5. Explicit Retrieval
5.显式检索
In this scenario, the application gets the required secrets directly using Vault’s REST API or, more likely, using one of the available libraries. For Java, we’ll use the library from the spring-vault project, which leverages the Spring Framework for low-level REST operations:
在这种情况下,应用程序会直接使用 Vault 的 REST API 获取所需的秘密,或者更有可能使用其中一个可用库。对于 Java,我们将使用 spring-vault 项目中的库,该库利用 Spring 框架进行底层 REST 操作:
<dependency>
<groupId>org.springframework.vault</groupId>
<artifactId>spring-vault-core</artifactId>
<version>2.3.4</version>
</dependency>
The latest version of this dependency is available on Maven Central.
该依赖项的最新版本可在 Maven Central 上获取。
Please make sure to pick a version that is compatible with Spring Framework’s main version: spring-vault-core 3.x requires Spring 6.x, while spring-vault-core 2.x requires Spring 5.3.x.
请确保选择与 Spring Framework 主版本兼容的版本:spring-vault-core 3.x 需要 Spring 6.x,而 spring-vault-core 2.x 需要 Spring 5.3.x。
The main entry point to access Vault’a API is the VaultTemplate class. The library provides the EnvironmentVaultConfiguration helper class that simplifies the process of configuring a VaultTemplate instance with the required access and authentication details. To use it, the recommended way is to import it from one of the @Configuration classes of our application:
访问 Vault’a API 的主要入口是 VaultTemplate 类。该库提供的EnvironmentVaultConfiguration辅助类简化了使用所需访问和身份验证详细信息配置VaultTemplate实例的过程。要使用该类,建议从我们应用程序的 @Configuration 类中导入:
@Configuration
@PropertySource("vault-config-k8s.properties")
@Import(EnvironmentVaultConfiguration.class)
public class VaultConfig {
// No code!
}
In this case, we’re also adding the vault-config-k8s property source, where we’ll add the required connection details. At a minimum, we need to inform Vault’s endpoint URI and authentication mechanism to use. Since we’ll be running our application outside of a cluster during development, we also need to supply the location of the file holding the service account token:
在这种情况下,我们还要添加 vault-config-k8s 属性源,我们将在其中添加所需的连接详细信息。至少,我们需要告知 Vault 要使用的端点 URI 和身份验证机制。由于在开发过程中将在集群外运行应用程序,我们还需要提供保存服务帐户令牌的文件位置:
vault.uri=http://localhost:8200
vault.authentication=KUBERNETES
vault.kubernetes.role=baeldung-test-role
vault.kubernetes.service-account-token-file=sa-token.txt
We can now inject a VaultTemplate wherever we need to access Vault’s API. As a quick example, let’s create a CommandLineRunner @Bean that lists the contents of all secrets:
现在,我们可以在任何需要访问 Vault API 的地方注入 VaultTemplate 。举个简单的例子,让我们创建一个 CommandLineRunner @Bean 来列出所有秘密的内容:
@Bean
CommandLineRunner listSecrets(VaultTemplate vault) {
return args -> {
VaultKeyValueOperations ops = vault.opsForKeyValue("secrets", VaultKeyValueOperationsSupport.KeyValueBackend.KV_2);
List<String> secrets = ops.list("");
if (secrets == null) {
System.out.println("No secrets found");
return;
}
secrets.forEach(s -> {
System.out.println("secret=" + s);
var response = ops.get(s);
var data = response.getRequiredData();
data.entrySet()
.forEach(e -> {
System.out.println("- key=" + e.getKey() + " => " + e.getValue());
});
});
};
}
In our case, Vault has a KV Version 2 secrets engine mounted on /secrets path, so we’ve used the opsForKeyValue method to get a VaultKeyValueOperations object that we’ll use to list all secrets. Other secret engines also have dedicated operations objects that offer tailor-made methods to access them.
在我们的例子中,Vault 在 /secrets 路径上安装了 KV 第 2 版秘密引擎,因此我们使用 opsForKeyValue 方法获得了一个 VaultKeyValueOperations 对象,我们将使用该对象列出所有秘密。其他秘密引擎也有专门的操作对象,提供量身定制的方法来访问它们。
For secret engines that do not have a dedicated VaultXYZOperations façade, we can use generic methods to access any path:
对于没有专用 VaultXYZOperations 外观的秘密引擎,我们可以使用通用方法访问任何路径:
- read(path): Reads data from the specified path
- write(path, data): Writes data at the specified path
- list(path): Returns a list of entries under the specified path
- delete(path): Remove the secret at the specified path
6. Semi-Explicit Retrieval
6.半明确检索
In the previous method, the fact that we’re directly accessing Vault’a API introduces a strong coupling that may pose a few hurdles. For instance, this means developers will need a Vault instance or create mocks during development time and when running CI pipelines.
在前一种方法中,我们直接访问 Vault’a API 的事实引入了一种强耦合,可能会带来一些障碍。例如,这意味着开发人员在开发期间和运行 CI 管道时将需要一个 Vault 实例或创建模拟。
Alternatively, we can use the Spring Cloud Vault library in our projects to make Vault’s secret lookup transparent to the application’s code. This library makes this possible by exposing a custom PropertySource to Spring, which will be picked up and configured during the application bootstrap.
另外,我们可以在项目中使用 Spring Cloud Vault 库,使 Vault 的秘密查找对应用程序的代码透明。该库通过向 Spring 公开自定义 PropertySource 来实现这一点,Spring 将在应用程序引导过程中获取并配置该源。
We call this method “semi-explicit” because, while it is true that the application’s code is unaware of Vault’s usage, we still must add the required dependencies to the project. The easiest way to achieve this is by using the available starter library:
我们称这种方法为 “半显式”,因为虽然应用程序的代码确实不知道Vault的用途,但我们仍必须将所需的依赖关系添加到项目中。最简单的方法是使用可用的启动库:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-vault-config</artifactId>
<version>3.1.3</version>
</dependency>
The latest version of this dependency is available on Maven Central.
该依赖项的最新版本可在 Maven Central 上获取。
As before, we must pick a version compatible with Spring Boot’s main version used by our project. Spring Boot 2.7.x requires version 3.1.x, while Spring Boot 3.x requires version 4.x.
与之前一样,我们必须选择一个与我们项目使用的 Spring Boot 主版本兼容的版本。Spring Boot 2.7.x 需要 3.1.x 版本,而 Spring Boot 3.x 需要 4.x 版本。
To enable Vault as a property source, we must add a few configuration properties. A common practice is to use a dedicated Spring profile for this, which allows us to switch from Vault-based secrets to any other source quickly.
要启用 Vault 作为属性源,我们必须添加一些配置属性。通常的做法是为此使用专用的 Spring 配置文件,这样我们就可以快速从基于 Vault 的秘密切换到任何其他来源。
For Kubernetes, this is what a typical configuration properties file looks like:
对于 Kubernetes,这是一个典型的配置属性文件:
spring.config.import=vault://
spring.cloud.vault.uri=http://vault-internal.vault.svc.cluster.local:8200
spring.cloud.vault.authentication=KUBERNETES
spring.cloud.vault.kv.backend=secrets
spring.cloud.vault.kv.application-name=baeldung-test
This configuration enables Vault’s KV backend to be mounted at the secrets path on the server. The library will use the configured application name as the path under this backend from where to pick secrets.
此配置可将 Vault 的 KV 后端挂载到服务器上的secrets路径。库将使用配置的应用程序名称作为从该后端提取秘密的路径。
The spring.config.import property is also needed to enable Vault as a property source. Please notice this property was introduced in Spring Boot 2.4, along with the deprecation of the bootstrap context initialization. When migrating applications based on older versions of Spring Boot, this is something to pay special attention to.
还需要使用 spring.config.import 属性来启用 Vault 作为属性源。请注意,该属性是在 Spring Boot 2.4 中引入的,同时废弃了引导上下文初始化。在迁移基于旧版本 Spring Boot 的应用程序时,需要特别注意这一点。
The complete list of available configuration properties is available on Spring Cloud Vault’s documentation.
Spring Cloud Vault 的文档中提供了可用配置属性的完整列表。
Now, let’s show how to use this with a simple example that gets a configuration value from Spring’s Environment:
现在,让我们通过一个从 Spring 的环境中获取配置值的简单示例来演示如何使用它:
@Bean
CommandLineRunner listSecrets(Environment env) {
return args -> {
var foo = env.getProperty("foo");
Assert.notNull(foo, "foo must have a value");
System.out.println("foo=" + foo);
};
}
When we run this application, we can see the secret’s value in the output, confirming that the integration is working.
当我们运行这个应用程序时,我们可以在输出中看到秘密的值,从而确认集成正在运行。
7. Transparent Support Using Vault Sidecar
7.使用 Vault Sidecar 提供透明支持
If we don’t want to or can’t change the code of an existing application to get its secrets from Vault, using Vault’s sidecar method is a suitable alternative. The only requirement is that the application is already capable of picking values from environment variables and configuration files.
如果我们不想或无法更改现有应用程序的代码以从 Vault 获取秘密,那么使用 Vault 的 sidecar 方法是一个合适的替代方案。唯一的要求是应用程序已经能够从环境变量和配置文件中获取值。
The sidecar pattern is a common practice in the Kubernetes landscape, where an application delegates some specific functionality to another container running on the same pod. A popular application of this pattern is the Istio service mesh, used to add traffic control policies and service discovery, among other functionalities, to existing applications.
sidecar 模式是 Kubernetes 环境中的一种常见做法,即应用程序将某些特定功能委托给在同一 pod 上运行的另一个容器。这种模式的一个流行应用是 Istio 服务网格,用于向现有应用添加流量控制策略和服务发现等功能。
We can use this approach with any Kubernetes workload type, such as a Deployment, Statefulset, or Job. Moreover, we can use a Mutating Webhook to automatically inject a sidecar when a pod is created, thus relieving users from manually adding it to the workload’s specification.
我们可以将这种方法用于任何 Kubernetes 工作负载类型,例如 部署、Statefulset 或 工作。此外,我们还可以使用 Mutating Webhook,在创建 pod 时自动注入侧载,从而使用户无需手动将其添加到工作负载的规范中。
The Vault sidecar uses annotations present in the metadata section of the workload’s pods template to instruct the sidecar which secrets to pull from Vault. Those secrets are then put in a file stored in a shared volume between the sidecar and any other container in the same pod. If any of those secrets is dynamic, the sidecar also takes care of keeping track of its renewal, re-rendering the file when needed.
Vault 侧卡使用工作负载 pod 模板元数据部分中的注释来指示侧卡从 Vault 提取哪些机密。然后,这些机密会被放入一个文件,存储在侧卡和同一 pod 中任何其他容器的共享卷中。如果这些秘密中的任何一个是动态的,那么侧卡还会负责跟踪其更新情况,并在需要时重新渲染文件。
7.1. Sidecar Injector Deployment
7.1.侧卡喷油器的部署
Before we use this method, firstly, we need to deploy Vault’s Sidecar Injector component. The easiest way to do it is to use Hashicorp’s provided helm chart, which, by default, already adds the injector as part of regular Vault deployment on Kubernetes.
在使用此方法之前,我们首先需要部署 Vault 的 Sidecar 注入器组件。最简单的方法是使用 Hashicorp 提供的 helm chart ,默认情况下,它已将注入器添加为 Kubernetes 上常规 Vault 部署的一部分。
If this is not the case, we must upgrade the existing helm release with a new value for the injector.enabled property:
如果不是这种情况,我们必须为 injector.enabled 属性设置新值,以升级现有的 helm 版本:
$ helm upgrade vault hashicorp/vault -n vault --set injector.enabled=true
To verify that the injector was properly installed, let’s query the available WebHookConfiguration objects:
要验证注入器是否已正确安装,让我们查询可用的 WebHookConfiguration 对象:
$ kubectl get mutatingwebhookconfiguration
NAME WEBHOOKS AGE
vault-agent-injector-cfg 1 16d
7.2. Annotating Deployments
7.2.注释部署
A secret injection is “opt-in”, meaning that no changes will occur unless the injector finds specific annotations as part of a workload’s metadata. This is an example of a deployment manifest using the minimal set of required annotations:
秘密注入是 “选择性注入”,这意味着除非注入器找到作为工作负载元数据一部分的特定注释,否则不会发生任何更改。这是一个使用最小所需注释集的部署清单示例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: baeldung
spec:
selector:
matchLabels:
app: nginx
replicas: 1
template:
metadata:
labels:
app: nginx
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/agent-inject-secret-baeldung.properties: "secrets/baeldung-test"
vault.hashicorp.com/role: "baeldung-test-role"
vault.hashicorp.com/agent-inject-template-baeldung.properties: |
{{- with secret "secrets/baeldung-test" -}}
{{- range $k, $v := .Data.data }}
{{$k}}={{$v}}
{{- end -}}
{{ end }}
spec:
serviceAccountName: vault-test-sa
automountServiceAccountToken: true
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
When we deploy this manifest to the cluster, the injector will patch it and inject the Vault agent sidecar container configured as follows:
当我们将此清单部署到群集时,注入器将对其进行修补,并注入配置如下的 Vault 代理侧载容器:
- Auto-login using baeldung-test-role
- Secrets located under the secrets/baeldung-test path will be renderer to a file named baeldung.properties under the default secret directory (/vault/secrets)
- File content generated using the provided template
There are many more annotations available, which we can use to customize the location and template used to render the secrets. The full list of supported annotations is available on Vault’s documentation.
还有更多可用的注释,我们可以用它们来定制用于呈现秘密的位置和模板。Vault 的文档中提供了所支持注释的完整列表。
8. Transparent Support Using Vault Secret CSI Provider
8.使用 Vault Secret CSI 提供商的透明支持
A CSI (Container Storage Interface) provider allows a vendor to extend the types of volumes supported by a Kubernetes cluster. The Vault CSI Provider is an alternative to the use of a sidecar that allows Vault secrets to be exposed to a pod as a regular volume.
CSI(容器存储接口)提供商允许供应商扩展 Kubernetes 集群支持的卷类型。Vault CSI 提供商是使用侧卡的替代方案,它允许将 Vault 秘密作为常规卷暴露给 pod。
The main advantage here is that we don’t have a sidecar attached to each pod, so we need fewer resources (CPU/Memory) to run our workload. While not very resource-hungry, the sidecar cost scales with the number of active pods. In contrast, the CSI uses a DaemonSet, which means there’s one pod for each node in the cluster.
这样做的主要好处是,我们不需要为每个 pod 安装侧载,因此运行工作负载所需的资源(CPU/内存)更少。虽然对资源的要求不高,但侧载成本会随着活动 pod 数量的增加而增加。相比之下,CSI 使用的是 DaemonSet,这意味着集群中的每个节点都有一个 pod。
8.1. Enabling the Vault CSI Provider
8.1.启用 Vault CSI 提供商
Before we can install this provider, we must check whether the CSI Secret Store Driver is already present in the target cluster:
在安装该提供程序之前,我们必须检查 CSI Secret Store Driver 是否已存在于目标群集中:
$ kubectl get csidrivers
The result should include the secrets-store.csi.k8s.io driver:
结果应包括 secrets-store.csi.k8s.io 驱动程序:
NAME ATTACHREQUIRED PODINFOONMOUNT ...
secrets-store.csi.k8s.io false true ...
If this is not the case, it’s just a matter of applying the appropriate helm chart:
如果情况并非如此,只需应用适当的舵表即可:
$ helm repo add secrets-store-csi-driver https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts
$ helm install csi-secrets-store secrets-store-csi-driver/secrets-store-csi-driver \
--namespace kube-system\
--set syncSecret.enabled=true
The project’s documentation also describes other installation methods, but unless there are some specific requirements, the helm method is the preferred one.
项目文件中还介绍了其他安装方法,但除非有特殊要求,否则舵方法是首选。
Now, let’s move on to the Vault CSI Provider installation itself. Once again, we’ll use the official Vault helm chart. The CSI provider is not enabled by default, so we need to upgrade it using the csi.enabled property:
现在,让我们来看看 Vault CSI Provider 安装本身。我们将再次使用官方的Vault掌舵图。CSI提供程序默认未启用,因此我们需要使用csi.enabled属性对其进行升级:
$ helm upgrade vault hashicorp/vault -n vault –-set csi.enabled=true
To verify that the driver was correctly installed, we’ll check that its DaemonSet is running fine:
为了验证驱动程序是否安装正确,我们将检查其 DaemonSet 是否运行正常:
$ kubectl get daemonsets –n vault
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
vault-csi-provider 1 1 1 1 1 <none> 15d
8.2. Vault CSI Provider Usage
8.2.Vault CSI 提供商的使用
Configuring a workload with vault secrets using the Vault CSI Provider requires two steps. Firstly, we define a SecretProviderClass resource that specifies the secret and keys to retrieve:
使用 Vault CSI Provider 配置带有保险库秘密的工作负载需要两个步骤。首先,我们定义一个SecretProviderClass资源,指定要检索的秘密和密钥:
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
name: baeldung-csi-secrets
namespace: baeldung
spec:
provider: vault
parameters:
roleName: 'baeldung-test-role'
objects: |
- objectName: 'baeldung.properties'
secretPath: "secrets/data/baeldung-test"
Notice the spec.provider property, which must be set to vault. This is required so the CSI Driver knows which of the available providers to use. The parameters section contains information used by the provider to locate the requested secrets:
请注意 spec.provider 属性,它必须设置为 vault。这是必需的,以便 CSI 驱动程序知道要使用哪个可用提供程序。参数部分包含提供程序用于查找所请求秘密的信息:
- roleName: Vault role used during login, which defines the secrets the application will have access to
- objects: The value is a YAML-formatted string (hence the “|”) with an array of secrets to retrieve
Each entry in the objects array is an object with three properties:
objects 数组中的每个条目都是一个具有三个属性的对象:
- secretPath: Vault’s path for the secret
- objectName: Name of the file that will contain the secret
- objectKey: Key within Vault’s secret that provides the content to put into the file. If omitted, the file will contain a JSON object with all values
Now, let’s use this resource in a sample deployment workload:
现在,让我们在示例部署工作负载中使用该资源:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-csi
namespace: baeldung
spec:
selector:
matchLabels:
app: nginx-csi
replicas: 1
template:
metadata:
labels:
app: nginx-csi
spec:
serviceAccountName: vault-test-sa
automountServiceAccountToken: true
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
volumeMounts:
- name: vault-secrets
mountPath: /vault/secrets
readOnly: true
volumes:
- name: vault-secrets
csi:
driver: 'secrets-store.csi.k8s.io'
readOnly: true
volumeAttributes:
secretProviderClass: baeldung-csi-secrets
In the volumes section, notice how we use a CSI definition pointing to our previously defined SecretStorageClass.
在 volumes 部分,请注意我们是如何使用 CSI 定义来指向先前定义的 SecretStorageClass. 的。
To validate this deployment, we can open a shell into the main container and check the presence of the secret under the specified mount path:
要验证这一部署,我们可以在主容器中打开 shell,检查指定挂载路径下是否存在秘密:
$ kubectl get pods -n baeldung -l app=nginx-csi
NAME READY STATUS RESTARTS AGE
nginx-csi-b7866bc69-njzff 1/1 Running 0 19m
$ kubectl exec -it -n baeldung nginx-csi-b7866bc69-njzff -- /bin/sh
# cat /vault/secrets/baeldung.properties
{"request_id":"eb417a64-b1c4-087d-a5f4-30229f27aba1","lease_id":"","lease_duration":0,
"renewable":false,
"data":{
"data":{"foo":"bar"},
... more data omitted
9. Transparent Support Using Vault Secrets Operator
9.使用 Vault Secrets 操作员的透明支持
The Vault Secrets Operator adds Custom Resource Definitions (CRDs) to a Kubernetes cluster, which we can use to populate regular secrets with values pulled from a Vault instance.
Vault Secrets 操作员将自定义资源定义 (CRD) 添加到 Kubernetes 集群,我们可以使用它来用从 Vault 实例中提取的值填充常规机密。
Compared to the CSI method, the operator’s main advantage is that we don’t need to change anything on existing workloads to move from standard secrets to Vault-backed ones.
与 CSI 方法相比,操作员的主要优势在于,我们不需要改变现有工作负载上的任何东西,就能从标准机密转移到金库支持的机密。
9.1. Vault Secrets Operator Deployment
9.1.金库秘钥操作员部署
The operator has its own chart that deploys all required artifacts into the cluster:
操作员有自己的图表,将所有需要的工件部署到集群中:
$ helm install --create-namespace --namespace vault-secrets-operator \
vault-secrets-operator hashicorp/vault-secrets-operator \
--version 0.1.0
Now, let’s check the new CRDs:
现在,让我们检查一下新的 CRD:
$ kubectl get customresourcedefinitions | grep vault
vaultauths.secrets.hashicorp.com 2023-09-13T01:08:11Z
vaultconnections.secrets.hashicorp.com 2023-09-13T01:08:11Z
vaultdynamicsecrets.secrets.hashicorp.com 2023-09-13T01:08:11Z
vaultpkisecrets.secrets.hashicorp.com 2023-09-13T01:08:11Z
vaultstaticsecrets.secrets.hashicorp.com 2023-09-13T01:08:11Z
As of this writing, the operator defines those CRDs:
截至本报告撰写之时,运营商对这些 CRD 进行了定义:
- VaultConnection: Defines Vault connection details such as its address, TLS certificates, etc
- VaultAuth: Authentication details used by a specific VaultConnection
- Vault<type>Secret: Defines a mapping between Kubernetes and Vault secrets, where <type> can be Static, Dynamic, or PKI, and corresponds to the secret type.
9.2. Vault Secrets Operator Usage
9.2.金库密钥操作员的使用
Let’s walk through a simple example to show how to use this Operator. Firstly, we need to create a VaultConnection resource pointing to our Vault instance:
让我们通过一个简单的示例来演示如何使用该操作符。首先,我们需要创建一个指向 Vault 实例的 VaultConnection 资源:
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultConnection
metadata:
namespace: baeldung
name: vault-local
spec:
address: http://vault.vault.svc.cluster.local:8200
Next, we need a VaultAuth resource with the authentication details we’ll use to access secrets:
接下来,我们需要一个 VaultAuth 资源,其中包含用于访问机密的身份验证详细信息:
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultAuth
metadata:
namespace: baeldung
name: baeldung-test
spec:
vaultConnectionRef: vault-local
method: kubernetes
mount: kubernetes
Kubernetes:
role: baeldung-test-role
serviceAccount: vault-test-sa
Those are the key properties we must fill in:
这些都是我们必须填写的关键属性:
- spec.vaultConnectionRef: name of the VaultConnection resource we’ve just created
- spec.method: set to kubernetes as we’ll use this authentication method
- spec.kubernetes.role: Vault role to use when authenticating
- spec.kubernetes.serviceAccount: Service account to use when authenticating
Now, let’s define a VaultStaticSecret to map secrets from secrets/baeldung-test on Vault to a secret named baeldung-test:
现在,让我们定义一个 VaultStaticSecret 来将 Vault 上 secrets/baeldung-test 中的秘密映射到名为 baeldung-test 的秘密:
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultStaticSecret
metadata:
namespace: baeldung
name: baeldung-test
spec:
vaultAuthRef: baeldung-test
mount: secrets
type: kv-v2
path: baeldung-test
refreshAfter: 60s
hmacSecretData: true
destination:
create: true
name: baeldung-test
Finally, we can use kubectl to confirm that the secret was correctly created:
最后,我们可以使用 kubectl 来确认秘密是否已正确创建:
$ kubectl get secret -n baeldung baeldung-test
NAME TYPE DATA AGE
baeldung-test Opaque 3 24h
10. Method Comparison
10.方法比较
As we’ve seen, Kubernetes-based applications have no shortage of alternatives to access secrets from Vault. To help choose which one is best suited for a given use case, we’ve put together a short comparison of each method’s features/characteristics:
正如我们所见,基于 Kubernetes 的应用程序不乏从 Vault 访问机密的替代方法。为了帮助选择最适合特定用例的方法,我们对每种方法的功能/特点进行了简短比较:
Feature/Characteristic | Explicit | Semi-Explicit | Injector | CSI | Operator |
---|---|---|---|---|---|
Requires code changes | Yes | No (deps only) | No | No | No |
Access to Vault’s API | Full control | Read only | Partial (e.g., no admin APIs access) | Limited | Limited |
Extra resources needed | No | No | Yes, one extra container per pod | Yes, one per node | Yes, one per cluster |
Transparent to existing applications | No | No | Partial (requires extra annotations) | Partial (requires extra volumes) | None |
Requires cluster changes | No | No | Yes | Yes | Yes |
11. Conclusion
11.结论
In this tutorial, we’ve explored different ways to access secrets stored in a Vault instance from Kubernetes-based applications.
在本教程中,我们探讨了从基于 Kubernetes 的应用程序访问存储在 Vault 实例中的秘密的不同方法。
As always, all code is available over on GitHub.
一如既往,所有代码均可在 GitHub 上获取。