2.6. 为 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

1
指示 secret 的键和值的结构。
2
data 字段中允许的键格式必须符合 Kubernetes 标识符术语表DNS_SUBDOMAIN 值的规范。
3
data 映射中键关联的值必须采用 base64 编码。
4
stringData 映射中的条目将转换为 base64,然后该条目将自动移动到 data 映射中。此字段是只写的;其值仅通过 data 字段返回。
5
stringData 映射中键关联的值由纯文本字符串组成。

您必须先创建 secret,然后创建依赖于此 secret 的 Pod。

在创建 secret 时:

  • 使用 secret 数据创建 secret 对象。
  • 更新 pod 的服务帐户以允许引用该 secret。
  • 创建以环境变量或文件(使用 secret 卷)形式消耗 secret 的 pod。

2.6.1.1. secret 的类型

type 字段中的值指明 secret 的键名称和值的结构。此类型可用于强制使 secret 对象中存在用户名和密钥。如果您不想进行验证,请使用 opaque 类型,这也是默认类型。

指定以下一种类型来触发最小服务器端验证,确保 secret 数据中存在特定的键名称:

  • kubernetes.io/service-account-token。使用服务帐户令牌。
  • kubernetes.io/basic-auth。搭配基本身份验证使用。
  • 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.2. 了解如何创建 secret

作为管理员,您必须先创建 secret,然后开发人员才能创建依赖于该 secret 的 pod。

在创建 secret 时:

  1. 创建包含您要保留 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

    1
    指定 secret 的类型。
    2
    指定编码的字符串和数据。
    3
    指定解码的字符串和数据。

    使用 datastringdata 字段,不能同时使用这两个字段。

  2. 更新 pod 的服务帐户以引用 secret:

    使用 secret 的服务帐户的 YAML

    apiVersion: v1
    kind: ServiceAccount
     ...
    secrets:
    - name: test-secret

  3. 创建以环境变量或文件(使用 secret 卷)形式消耗 secret 的 pod:

    pod 的 YAML 使用 secret 数据填充卷中的文件

    apiVersion: v1
    kind: Pod
    metadata:
      name: secret-example-pod
    spec:
      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
      volumes:
        - name: secret-volume
          secret:
            secretName: test-secret 4
      restartPolicy: Never

    1
    为每个需要 secret 的容器添加 volumeMounts 字段。
    2
    指定您希望显示 secret 的未使用目录名称。secret 数据映射中的每个密钥都将成为 mountPath 下的文件名。
    3
    设置为 true。如果为 true,这指示驱动程序提供只读卷。
    4
    指定 secret 的名称。

    pod 的 YAML 使用 secret 数据填充环境变量

    apiVersion: v1
    kind: Pod
    metadata:
      name: secret-example-pod
    spec:
      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
      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 对。

流程

  1. 在控制平面节点上的 YAML 文件中创建 Secret 对象。

    例如:

    apiVersion: v1
    kind: Secret
    metadata:
      name: mysecret
    type: Opaque 1
    data:
      username: <username>
      password: <password>
    1
    指定不透明 secret。
  2. 使用以下命令来创建 Secret 对象:

    $ oc create -f <filename>.yaml
  3. 在 pod 中使用该 secret:

    1. 更新 pod 的服务帐户以引用 secret,如 "Understanding how to create secrets" 部分所示。
    2. 创建以环境变量或文件(使用 secret 卷)形式消耗 secret 的 pod,如"创建 secret"部分所示。

其他资源

2.6.2.3. 创建服务帐户令牌 secret

作为管理员,您可以创建一个服务帐户令牌 secret,该 secret 允许您将服务帐户令牌分发到必须通过 API 进行身份验证的应用程序。

注意

建议使用 TokenRequest API 获取绑定的服务帐户令牌,而不使用服务帐户令牌 secret。从 TokenRequest API 获取的令牌比存储在 secret 中的令牌更安全,因为它们具有绑定的生命周期,且不能被其他 API 客户端读取。

只有在无法使用 TokenRequest API 且在可读的 API 对象中存在非过期令牌时,才应创建服务帐户令牌 secret。

有关创建绑定服务帐户令牌的详情,请参考下面的其他参考资料部分。

流程

  1. 在控制平面节点上的 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

    1
    指定一个现有服务帐户名称。如果您要同时创建 ServiceAccountSecret 对象,请首先创建 ServiceAccount 对象。
    2
    指定服务帐户令牌 secret。
  2. 使用以下命令来创建 Secret 对象:

    $ oc create -f <filename>.yaml
  3. 在 pod 中使用该 secret:

    1. 更新 pod 的服务帐户以引用 secret,如 "Understanding how to create secrets" 部分所示。
    2. 创建以环境变量或文件(使用 secret 卷)形式消耗 secret 的 pod,如"创建 secret"部分所示。

其他资源

2.6.2.4. 创建基本身份验证 secret

作为管理员,您可以创建一个基本身份验证 secret,该 secret 允许您存储基本身份验证所需的凭证。在使用此 secret 类型时,Secret 对象的 data 参数必须包含以下密钥,采用 base64 格式编码:

  • 用户名 :用于身份验证的用户名
  • 密码 :用于身份验证的密码或令牌
注意

您可以使用 stringData 参数使用明文内容。

流程

  1. 在控制平面节点上的 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>

    1
    指定基本身份验证 secret。
    2
    指定要使用的基本身份验证值。
  2. 使用以下命令来创建 Secret 对象:

    $ oc create -f <filename>.yaml
  3. 在 pod 中使用该 secret:

    1. 更新 pod 的服务帐户以引用 secret,如 "Understanding how to create secrets" 部分所示。
    2. 创建以环境变量或文件(使用 secret 卷)形式消耗 secret 的 pod,如"创建 secret"部分所示。

其他资源

2.6.2.5. 创建 SSH 身份验证 secret

作为管理员,您可以创建一个 SSH 验证 secret,该 secret 允许您存储用于 SSH 验证的数据。在使用此 secret 类型时,Secret 对象的 data 参数必须包含要使用的 SSH 凭证。

流程

  1. 在控制平面节点上的 YAML 文件中创建 Secret 对象:

    secret 对象示例:

    apiVersion: v1
    kind: Secret
    metadata:
      name: secret-ssh-auth
    type: kubernetes.io/ssh-auth 1
    data:
      ssh-privatekey: | 2
              MIIEpQIBAAKCAQEAulqb/Y ...

    1
    指定 SSH 身份验证 secret。
    2
    指定 SSH 密钥/值对,作为要使用的 SSH 凭据。
  2. 使用以下命令来创建 Secret 对象:

    $ oc create -f <filename>.yaml
  3. 在 pod 中使用该 secret:

    1. 更新 pod 的服务帐户以引用 secret,如 "Understanding how to create secrets" 部分所示。
    2. 创建以环境变量或文件(使用 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 文件的内容。

流程

  1. 在控制平面节点上的 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

    1
    指定该 secret 使用 Docker 配置文件。
    2
    base64 编码的 Docker 配置文件

    Docker 配置 JSON secret 对象示例

    apiVersion: v1
    kind: Secret
    metadata:
      name: secret-docker-json
      namespace: my-project
    type: kubernetes.io/dockerconfig 1
    data:
      .dockerconfigjson:bm5ubm5ubm5ubm5ubm5ubm5ubm5ubmdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2cgYXV0aCBrZXlzCg== 2

    1
    指定该 secret 使用 Docker 配置 JSONfile。
    2
    base64 编码的 Docker 配置 JSON 文件
  2. 使用以下命令来创建 Secret 对象

    $ oc create -f <filename>.yaml
  3. 在 pod 中使用该 secret:

    1. 更新 pod 的服务帐户以引用 secret,如 "Understanding how to create secrets" 部分所示。
    2. 创建以环境变量或文件(使用 secret 卷)形式消耗 secret 的 pod,如"创建 secret"部分所示。

其他资源

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 进行身份验证的应用程序。

流程

  1. 运行以下命令,在命名空间中创建服务帐户:

    $ oc create sa <service_account_name> -n <your_namespace>
  2. 将以下 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
    1
    <secret_name> 替换为服务帐户令牌 secret 的名称。
    2
    指定一个现有服务帐户名称。如果您要同时创建 ServiceAccountSecret 对象,请首先创建 ServiceAccount 对象。
    3
    指定服务帐户令牌 secret 类型。
  3. 通过应用文件来生成服务帐户令牌:

    $ oc apply -f service-account-token-secret.yaml
  4. 运行以下命令,从 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 的名称。
  5. 使用您的服务帐户令牌与集群的 API 进行身份验证:

    $ curl -X GET <openshift_cluster_api> --header "Authorization: Bearer <token>" 1 2
    1
    <openshift_cluster_api> 替换为 OpenShift 集群 API。
    2
    <token> 替换为上一命令输出的服务帐户令牌。

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

  1. 编辑服务的 Pod spec。
  2. 使用您要用于 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.crttls.key 中。

  3. 创建服务:

    $ oc create -f <file-name>.yaml
  4. 查看 secret 以确保已成功创建:

    1. 查看所有 secret 列表:

      $ oc get secrets

      输出示例

      NAME                     TYPE                                  DATA      AGE
      my-cert                  kubernetes.io/tls                     2         9m

    2. 查看您的 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

  5. 编辑与该 secret 搭配的 Pod spec。

    apiVersion: v1
    kind: Pod
    metadata:
      name: my-service-pod
    spec:
      containers:
      - name: mypod
        image: redis
        volumeMounts:
        - name: my-container
          mountPath: "/etc/my-path"
      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 以强制重新生成证书:

  1. 删除 secret:

    $ oc delete secret <secret_name>
  2. 清除注解:

    $ 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-
注意

在用于移除注解的命令中,要移除的注解后面有一个 -

Red Hat logoGithubRedditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

© 2024 Red Hat, Inc.