2.6. 使用 secret 为 pod 提供敏感数据
有些应用程序需要密码和用户名等敏感信息,但您不希望开发人员持有这些信息。
作为管理员,您可以使用 Secret
对象在不以明文方式公开的前提下提供此类信息。
2.6.1. 了解 secret
Secret
对象类型提供了一种机制来保存敏感信息,如密码、OpenShift Container Platform 客户端配置文件和私有源存储库凭证等。secret 将敏感内容与 Pod 分离。您可以使用卷插件将 secret 信息挂载到容器中,系统也可以使用 secret 代表 Pod 执行操作。
主要属性包括:
- Secret 数据可以独立于其定义来引用。
- Secret 数据卷由临时文件工具 (tmpfs) 支持,永远不会停留在节点上。
- secret 数据可以在命名空间内共享。
YAML Secret
对象定义
apiVersion: v1 kind: Secret metadata: name: test-secret namespace: my-namespace type: Opaque 1 data: 2 username: <username> 3 password: <password> stringData: 4 hostname: myapp.mydomain.com 5
您必须先创建 secret,然后创建依赖于此 secret 的 Pod。
在创建 secret 时:
- 使用 secret 数据创建 secret 对象。
- 更新 pod 的服务帐户以允许引用该 secret。
-
创建以环境变量或文件(使用
secret
卷)形式消耗 secret 的 pod。
2.6.1.1. secret 的类型
type
字段中的值指明 secret 的键名称和值的结构。此类型可用于强制使 secret 对象中存在用户名和密钥。如果您不想进行验证,请使用 opaque
类型,这也是默认类型。
指定以下一种类型来触发最小服务器端验证,确保 secret 数据中存在特定的键名称:
-
kubernetes.io/basic-auth
:使用基本身份验证 -
kubernetes.io/dockercfg
:用作镜像 pull secret -
kubernetes.io/dockerconfigjson
: 用作镜像 pull secret -
kubernetes.io/service-account-token
:用来获取旧的服务帐户 API 令牌 -
kubernetes.io/ssh-auth
:与 SSH 密钥身份验证一起使用 -
kubernetes.io/tls
:与 TLS 证书颁发机构一起使用
如果您不想要验证,请指定 type: Opaque
,即 secret 没有声明键名称或值需要符合任何约定。opaque secret 允许使用无结构 key:value
对,可以包含任意值。
您可以指定其他任意类型,如 example.com/my-secret-type
。这些类型不是在服务器端强制执行,而是表明 secret 的创建者意在符合该类型的键/值要求。
有关创建不同类型的 secret 的示例,请参阅 了解如何创建 secret。
2.6.1.2. Secret 数据密钥
Secret 密钥必须在 DNS 子域中。
2.6.1.3. 自动生成的镜像 pull secret
默认情况下,OpenShift Container Platform 为每个服务帐户创建一个镜像 pull secret。
在 OpenShift Container Platform 4.16 之前,还会为创建的每个服务帐户生成长期服务帐户 API 令牌 secret。从 OpenShift Container Platform 4.16 开始,不再创建此服务帐户 API 令牌 secret。
升级到 4.16 后,任何现有的长期服务帐户 API 令牌 secret 都不会被删除,并将继续正常工作。有关检测集群中使用的长期 API 令牌,以及在不需要时删除它们的信息,请参阅红帽知识库文章 OpenShift Container Platform 中的 Long-lived 服务帐户 API 令牌。
此镜像 pull secret 需要将 OpenShift 镜像 registry 集成到集群的用户身份验证和授权系统中。
但是,如果您不启用 ImageRegistry
功能,或者在 Cluster Image Registry Operator 配置中禁用集成的 OpenShift 镜像 registry,则不会为每个服务帐户生成镜像 pull secret。
当在之前启用的集群中禁用集成的 OpenShift 镜像 registry 时,之前生成的镜像 pull secret 会被自动删除。
2.6.2. 了解如何创建 secret
作为管理员,您必须先创建 secret,然后开发人员才能创建依赖于该 secret 的 pod。
在创建 secret 时:
创建包含您要保留 secret 的数据的 secret 对象。在以下部分中取消每个 secret 类型所需的特定数据。
创建不透明 secret 的 YAML 对象示例
apiVersion: v1 kind: Secret metadata: name: test-secret type: Opaque 1 data: 2 username: <username> password: <password> stringData: 3 hostname: myapp.mydomain.com secret.properties: | property1=valueA property2=valueB
使用
data
或stringdata
字段,不能同时使用这两个字段。更新 pod 的服务帐户以引用 secret:
使用 secret 的服务帐户的 YAML
apiVersion: v1 kind: ServiceAccount ... secrets: - name: test-secret
创建以环境变量或文件(使用
secret
卷)形式消耗 secret 的 pod:pod 的 YAML 使用 secret 数据填充卷中的文件
apiVersion: v1 kind: Pod metadata: name: secret-example-pod spec: securityContext: runAsNonRoot: true seccompProfile: type: RuntimeDefault containers: - name: secret-test-container image: busybox command: [ "/bin/sh", "-c", "cat /etc/secret-volume/*" ] volumeMounts: 1 - name: secret-volume mountPath: /etc/secret-volume 2 readOnly: true 3 securityContext: allowPrivilegeEscalation: false capabilities: drop: [ALL] volumes: - name: secret-volume secret: secretName: test-secret 4 restartPolicy: Never
pod 的 YAML 使用 secret 数据填充环境变量
apiVersion: v1 kind: Pod metadata: name: secret-example-pod spec: securityContext: runAsNonRoot: true seccompProfile: type: RuntimeDefault containers: - name: secret-test-container image: busybox command: [ "/bin/sh", "-c", "export" ] env: - name: TEST_SECRET_USERNAME_ENV_VAR valueFrom: secretKeyRef: 1 name: test-secret key: username securityContext: allowPrivilegeEscalation: false capabilities: drop: [ALL] restartPolicy: Never
- 1
- 指定消耗 secret 密钥的环境变量。
构建配置的 YAML 使用 secret 数据填充环境变量
apiVersion: build.openshift.io/v1 kind: BuildConfig metadata: name: secret-example-bc spec: strategy: sourceStrategy: env: - name: TEST_SECRET_USERNAME_ENV_VAR valueFrom: secretKeyRef: 1 name: test-secret key: username from: kind: ImageStreamTag namespace: openshift name: 'cli:latest'
- 1
- 指定消耗 secret 密钥的环境变量。
2.6.2.1. Secret 创建限制
若要使用 secret,pod 需要引用该 secret。可以通过三种方式将 secret 用于 Pod:
- 为容器产生环境变量。
- 作为挂载到一个或多个容器上的卷中的文件。
- 在拉取 Pod 的镜像时通过 kubelet 使用。
卷类型 secret 使用卷机制将数据作为文件写入到容器中。镜像拉取 secret 使用服务帐户,将 secret 自动注入到命名空间中的所有 pod。
当模板包含 secret 定义时,模板使用提供的 secret 的唯一方法是确保验证 secret 卷源通过验证,并且指定的对象引用实际指向 Secret
类型的对象。因此,secret 需要在依赖它的任何 Pod 之前创建。确保这一点的最有效方法是通过使用服务帐户自动注入。
Secret API 对象驻留在命名空间中。它们只能由同一命名空间中的 pod 引用。
每个 secret 的大小限制为 1MB。这是为了防止创建可能会耗尽 apiserver 和 kubelet 内存的大型 secret。不过,创建许多较小的 secret 也可能会耗尽内存。
2.6.2.2. 创建不透明 secret
作为管理员,您可以创建一个不透明 secret,它允许您存储包含任意值的无结构 key:value
对。
流程
在控制平面节点上的 YAML 文件中创建
Secret
对象。例如:
apiVersion: v1 kind: Secret metadata: name: mysecret type: Opaque 1 data: username: <username> password: <password>
- 1
- 指定不透明 secret。
使用以下命令来创建
Secret
对象:$ oc create -f <filename>.yaml
在 pod 中使用该 secret:
- 更新 pod 的服务帐户以引用 secret,如 "Understanding how to create secrets" 部分所示。
-
创建以环境变量或文件(使用 secret 卷)形式消耗
secret
的 pod,如"创建 secret"部分所示。
其他资源
2.6.2.3. 创建旧的服务帐户令牌 secret
作为管理员,您可以创建一个旧的服务帐户令牌 secret,该 secret 允许您将服务帐户令牌分发到必须通过 API 进行身份验证的应用程序。
建议您使用 TokenRequest API 获取绑定的服务帐户令牌,而不使用旧的服务帐户令牌 secret。只有在无法使用 TokenRequest API 且在可读的 API 对象中存在非过期令牌时,才应创建服务帐户令牌 secret。
绑定服务帐户令牌比服务帐户令牌 secret 更安全,原因如下:
- 绑定服务帐户令牌具有绑定的生命周期。
- 绑定服务帐户令牌包含受众。
- 绑定服务帐户令牌可以绑定到 pod 或 secret,绑定令牌在删除绑定对象时无效。
工作负载自动注入投射卷以获取绑定服务帐户令牌。如果您的工作负载需要额外的服务帐户令牌,请在工作负载清单中添加额外的投射卷。
如需更多信息,请参阅"使用卷投射配置绑定服务帐户令牌"。
流程
在控制平面节点上的 YAML 文件中创建
Secret
对象:Secret
对象示例apiVersion: v1 kind: Secret metadata: name: secret-sa-sample annotations: kubernetes.io/service-account.name: "sa-name" 1 type: kubernetes.io/service-account-token 2
使用以下命令来创建
Secret
对象:$ oc create -f <filename>.yaml
在 pod 中使用该 secret:
- 更新 pod 的服务帐户以引用 secret,如 "Understanding how to create secrets" 部分所示。
-
创建以环境变量或文件(使用 secret 卷)形式消耗
secret
的 pod,如"创建 secret"部分所示。
2.6.2.4. 创建基本身份验证 secret
作为管理员,您可以创建一个基本身份验证 secret,该 secret 允许您存储基本身份验证所需的凭证。在使用此 secret 类型时,Secret
对象的 data
参数必须包含以下密钥,采用 base64 格式编码:
-
用户名
:用于身份验证的用户名 -
密码
:用于身份验证的密码或令牌
您可以使用 stringData
参数使用明文内容。
流程
在控制平面节点上的 YAML 文件中创建
Secret
对象:secret
对象示例apiVersion: v1 kind: Secret metadata: name: secret-basic-auth type: kubernetes.io/basic-auth 1 data: stringData: 2 username: admin password: <password>
使用以下命令来创建
Secret
对象:$ oc create -f <filename>.yaml
在 pod 中使用该 secret:
- 更新 pod 的服务帐户以引用 secret,如 "Understanding how to create secrets" 部分所示。
-
创建以环境变量或文件(使用 secret 卷)形式消耗
secret
的 pod,如"创建 secret"部分所示。
其他资源
2.6.2.5. 创建 SSH 身份验证 secret
作为管理员,您可以创建一个 SSH 验证 secret,该 secret 允许您存储用于 SSH 验证的数据。在使用此 secret 类型时,Secret
对象的 data
参数必须包含要使用的 SSH 凭证。
流程
在控制平面节点上的 YAML 文件中创建
Secret
对象:secret
对象示例apiVersion: v1 kind: Secret metadata: name: secret-ssh-auth type: kubernetes.io/ssh-auth 1 data: ssh-privatekey: | 2 MIIEpQIBAAKCAQEAulqb/Y ...
使用以下命令来创建
Secret
对象:$ oc create -f <filename>.yaml
在 pod 中使用该 secret:
- 更新 pod 的服务帐户以引用 secret,如 "Understanding how to create secrets" 部分所示。
-
创建以环境变量或文件(使用 secret 卷)形式消耗
secret
的 pod,如"创建 secret"部分所示。
其他资源
2.6.2.6. 创建 Docker 配置 secret
作为管理员,您可以创建一个 Docker 配置 secret,该 secret 允许您存储用于访问容器镜像 registry 的凭证。
-
kubernetes.io/dockercfg
。使用此机密类型存储本地 Docker 配置文件。secret
对象的data
参数必须包含以 base64 格式编码的.dockercfg
文件的内容。 -
kubernetes.io/dockerconfigjson
。使用此机密类型存储本地 Docker 配置 JSON 文件。secret
对象的data
参数必须包含以 base64 格式编码的.docker/config.json
文件的内容。
流程
在控制平面节点上的 YAML 文件中创建
Secret
对象。Docker 配置
secret
对象示例apiVersion: v1 kind: Secret metadata: name: secret-docker-cfg namespace: my-project type: kubernetes.io/dockerconfig 1 data: .dockerconfig:bm5ubm5ubm5ubm5ubm5ubm5ubm5ubmdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2cgYXV0aCBrZXlzCg== 2
Docker 配置 JSON
secret
对象示例apiVersion: v1 kind: Secret metadata: name: secret-docker-json namespace: my-project type: kubernetes.io/dockerconfig 1 data: .dockerconfigjson:bm5ubm5ubm5ubm5ubm5ubm5ubm5ubmdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2cgYXV0aCBrZXlzCg== 2
使用以下命令来创建
Secret
对象$ oc create -f <filename>.yaml
在 pod 中使用该 secret:
- 更新 pod 的服务帐户以引用 secret,如 "Understanding how to create secrets" 部分所示。
-
创建以环境变量或文件(使用 secret 卷)形式消耗
secret
的 pod,如"创建 secret"部分所示。
其他资源
2.6.2.7. 使用 Web 控制台创建 secret
您可以使用 Web 控制台创建 secret。
流程
-
导航到 Workloads
Secrets。 点 Create
From YAML。 手动编辑您的规格的 YAML,或者将文件拖放到 YAML 编辑器。例如:
apiVersion: v1 kind: Secret metadata: name: example namespace: <namespace> type: Opaque 1 data: username: <base64 encoded username> password: <base64 encoded password> stringData: 2 hostname: myapp.mydomain.com
- 点 Create。
点 Add Secret to workload。
- 从下拉菜单中选择要添加的工作负载。
- 点击 Save。
2.6.3. 了解如何更新 secret
修改 secret 值时,值(由已在运行的 pod 使用)不会动态更改。若要更改 secret,您必须删除原始 pod 并创建一个新 pod(可能具有相同的 PodSpec)。
更新 secret 遵循与部署新容器镜像相同的工作流程。您可以使用 kubectl rolling-update
命令。
secret 中的 resourceVersion
值不在引用时指定。因此,如果在 pod 启动的同时更新 secret,则将不能定义用于 pod 的 secret 版本。
目前,无法检查 Pod 创建时使用的 secret 对象的资源版本。按照计划 Pod 将报告此信息,以便控制器可以重启使用旧 resourceVersion
的 Pod。在此期间,请勿更新现有 secret 的数据,而应创建具有不同名称的新数据。
2.6.4. 创建和使用 secret
作为管理员,您可以创建一个服务帐户令牌 secret。这可让您将服务帐户令牌分发到必须通过 API 进行身份验证的应用程序。
流程
运行以下命令,在命名空间中创建服务帐户:
$ oc create sa <service_account_name> -n <your_namespace>
将以下 YAML 示例保存到名为
service-account-token-secret.yaml
的文件中。这个示例包括可用于生成服务帐户令牌的Secret
对象配置:apiVersion: v1 kind: Secret metadata: name: <secret_name> 1 annotations: kubernetes.io/service-account.name: "sa-name" 2 type: kubernetes.io/service-account-token 3
通过应用文件来生成服务帐户令牌:
$ oc apply -f service-account-token-secret.yaml
运行以下命令,从 secret 获取服务帐户令牌:
$ oc get secret <sa_token_secret> -o jsonpath='{.data.token}' | base64 --decode 1
输出示例
ayJhbGciOiJSUzI1NiIsImtpZCI6IklOb2dtck1qZ3hCSWpoNnh5YnZhSE9QMkk3YnRZMVZoclFfQTZfRFp1YlUifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImJ1aWxkZXItdG9rZW4tdHZrbnIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiYnVpbGRlciIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjNmZGU2MGZmLTA1NGYtNDkyZi04YzhjLTNlZjE0NDk3MmFmNyIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmJ1aWxkZXIifQ.OmqFTDuMHC_lYvvEUrjr1x453hlEEHYcxS9VKSzmRkP1SiVZWPNPkTWlfNRp6bIUZD3U6aN3N7dMSN0eI5hu36xPgpKTdvuckKLTCnelMx6cxOdAbrcw1mCmOClNscwjS1KO1kzMtYnnq8rXHiMJELsNlhnRyyIXRTtNBsy4t64T3283s3SLsancyx0gy0ujx-Ch3uKAKdZi5iT-I8jnnQ-ds5THDs2h65RJhgglQEmSxpHrLGZFmyHAQI-_SjvmHZPXEc482x3SkaQHNLqpmrpJorNqh1M8ZHKzlujhZgVooMvJmWPXTb2vnvi3DGn2XI-hZxl1yD2yGH1RBpYUHA
- 1
- 将 <sa_token_secret> 替换为服务帐户令牌 secret 的名称。
使用您的服务帐户令牌与集群的 API 进行身份验证:
$ curl -X GET <openshift_cluster_api> --header "Authorization: Bearer <token>" 1 2
2.6.5. 关于将签名证书与 secret 搭配使用
若要与服务进行安全通信,您可以配置 OpenShift Container Platform,以生成一个签名的服务用证书/密钥对,再添加到项目中的 secret 里。
服务用证书 secret 旨在支持需要开箱即用证书的复杂中间件应用程序。它的设置与管理员工具为节点和 master 生成的服务器证书相同。
为服务用证书 secret 配置的服务 Pod
规格。
apiVersion: v1
kind: Service
metadata:
name: registry
annotations:
service.beta.openshift.io/serving-cert-secret-name: registry-cert1
# ...
- 1
- 指定证书的名称
其他 pod 可以信任集群创建的证书(仅对内部 DNS 名称进行签名),方法是使用 pod 中自动挂载的 /var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt 文件中的 CA 捆绑。
此功能的签名算法是 x509.SHA256WithRSA
。要手动轮转,请删除生成的 secret。这会创建新的证书。
2.6.5.1. 生成签名证书以便与 secret 搭配使用
要将签名的服务用证书/密钥对用于 pod,请创建或编辑服务以添加到 service.beta.openshift.io/serving-cert-secret-name
注解,然后将 secret 添加到该 pod。
流程
创建服务用证书 secret:
-
编辑服务的
Pod
spec。 使用您要用于 secret 的名称,添加
service.beta.openshift.io/serving-cert-secret-name
注解。kind: Service apiVersion: v1 metadata: name: my-service annotations: service.beta.openshift.io/serving-cert-secret-name: my-cert 1 spec: selector: app: MyApp ports: - protocol: TCP port: 80 targetPort: 9376
证书和密钥采用 PEM 格式,分别存储在
tls.crt
和tls.key
中。创建服务:
$ oc create -f <file-name>.yaml
查看 secret 以确保已成功创建:
查看所有 secret 列表:
$ oc get secrets
输出示例
NAME TYPE DATA AGE my-cert kubernetes.io/tls 2 9m
查看您的 secret 详情:
$ oc describe secret my-cert
输出示例
Name: my-cert Namespace: openshift-console Labels: <none> Annotations: service.beta.openshift.io/expiry: 2023-03-08T23:22:40Z service.beta.openshift.io/originating-service-name: my-service service.beta.openshift.io/originating-service-uid: 640f0ec3-afc2-4380-bf31-a8c784846a11 service.beta.openshift.io/expiry: 2023-03-08T23:22:40Z Type: kubernetes.io/tls Data ==== tls.key: 1679 bytes tls.crt: 2595 bytes
编辑与该 secret 搭配的
Pod
spec。apiVersion: v1 kind: Pod metadata: name: my-service-pod spec: securityContext: runAsNonRoot: true seccompProfile: type: RuntimeDefault containers: - name: mypod image: redis volumeMounts: - name: my-container mountPath: "/etc/my-path" securityContext: allowPrivilegeEscalation: false capabilities: drop: [ALL] volumes: - name: my-volume secret: secretName: my-cert items: - key: username path: my-group/my-username mode: 511
当它可用时,您的 Pod 就可运行。该证书对内部服务 DNS 名称
<service.name>.<service.namespace>.svc
有效。证书/密钥对在接近到期时自动替换。在 secret 的
service.beta.openshift.io/expiry
注解中查看过期日期,其格式为 RFC3339。注意在大多数情形中,服务 DNS 名称
<service.name>.<service.namespace>.svc
不可从外部路由。<service.name>.<service.namespace>.svc
的主要用途是集群内或服务内通信,也用于重新加密路由。
2.6.6. secret 故障排除
如果服务证书生成失败并显示以下信息( 服务的 service.beta.openshift.io/serving-cert-generation-error
注解包含):
secret/ssl-key references serviceUID 62ad25ca-d703-11e6-9d6f-0e9c0057b608, which does not match 77b6dd80-d716-11e6-9d6f-0e9c0057b60
生成证书的服务不再存在,或者具有不同的 serviceUID
。您必须删除旧 secret 并清除服务上的以下注解 service.beta.openshift.io/serving-cert-generation-error
, service.beta.openshift.io/serving-cert-generation-error-num
以强制重新生成证书:
删除 secret:
$ oc delete secret <secret_name>
清除注解:
$ oc annotate service <service_name> service.beta.openshift.io/serving-cert-generation-error-
$ oc annotate service <service_name> service.beta.openshift.io/serving-cert-generation-error-num-
在用于移除注解的命令中,要移除的注解后面有一个 -
。