1.5. 为 pod 提供敏感数据

有些应用程序需要密码和用户名等敏感信息,但您不希望开发人员持有这些信息。

作为管理员,您可以使用 Secret 对象在不以明文方式公开的前提下提供此类信息。

1.5.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: dmFsdWUtMQ0K 3
  password: dmFsdWUtMg0KDQo=
stringData: 4
  hostname: myapp.mydomain.com 5

1 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。

1.5.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 中的代码示例。

1.5.1.2. secret 配置示例

以下是几个 secret 配置文件示例。

创建四个文件的 Secret YAML

apiVersion: v1
kind: Secret
metadata:
  name: test-secret
data:
  username: dmFsdWUtMQ0K     1
  password: dmFsdWUtMQ0KDQo= 2
stringData:
  hostname: myapp.mydomain.com 3
  secret.properties: |-     4
    property1=valueA
    property2=valueB

1
文件包含已解码的值。
2
文件包含已解码的值。
3
文件包含提供的字符串。
4
文件包含提供的数据。

一个 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:
          # name must match the volume name below
          - name: secret-volume
            mountPath: /etc/secret-volume
            readOnly: true
  volumes:
    - name: secret-volume
      secret:
        secretName: test-secret
  restartPolicy: Never

一个 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:
              name: test-secret
              key: username
  restartPolicy: Never

一个 Build Config 的 YAML 定义,在环境变量中使用 secret 数据。

apiVersion: v1
kind: BuildConfig
metadata:
  name: secret-example-bc
spec:
  strategy:
    sourceStrategy:
      env:
      - name: TEST_SECRET_USERNAME_ENV_VAR
        valueFrom:
          secretKeyRef:
            name: test-secret
            key: username

1.5.1.3. Secret 数据密钥

Secret 密钥必须在 DNS 子域中。

1.5.2. 了解如何创建 secret

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

在创建 secret 时:

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

1.5.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 也可能会耗尽内存。

1.5.2.2. 创建不透明 secret

作为管理员,您可以创建不透明 secret,从而能使用包含任意值的无结构 key:value 对。

流程

  1. 在主控机上的 YAML 文件中创建 secret 对象。

    例如:

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

    $ oc create -f <filename>

然后:

  1. 为您要使用 secret 来允许引用该 secret 的 pod 更新服务帐户。
  2. 创建以环境变量或文件(使用 secret 卷)形式消耗 secret 的 pod。

1.5.3. 了解如何更新 secret

修改 secret 值时,值(由已在运行的 pod 使用)不会动态更改。若要更改 secret,您必须删除原始 pod 并创建一个新 pod(可能具有相同的 PodSpec)。

更新 secret 遵循与部署新容器镜像相同的工作流程。您可以使用 kubectl rolling-update 命令。

secret 中的 resourceVersion 值不在引用时指定。因此,如果在 pod 启动的同时更新 secret,则将不能定义用于 pod 的 secret 版本。

注意

目前,无法检查 pod 创建时使用的 secret 对象的资源版本。按照计划 pod 将报告此信息,以便控制器可以重启使用旧 resourceVersion 的 pod。在此期间,请勿更新现有 secret 的数据,而应创建具有不同名称的新数据。

1.5.4. 关于将签名证书与 secret 搭配使用

若要与服务进行安全通信,您可以配置 OpenShift Container Platform,以生成一个签名的服务用证书/密钥对,再添加到项目中的 secret 里。

服务用证书 secret 旨在支持需要开箱即用证书的复杂中间件应用程序。它的设置与管理员工具为节点和主控机生成的服务器证书相同。

为服务用证书 secret 配置的服务 pod 规格。

apiVersion: v1
  kind: Service
  metadata:
    name: registry
    annotations:
      service.alpha.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。这会创建新的证书。

1.5.4.1. 生成签名证书以便与 secret 搭配使用

要将签名的服务用证书/密钥对用于 pod,请创建或编辑服务以添加到 service.alpha.openshift.io/serving-cert-secret-name 注解,然后将 secret 添加到该 pod。

流程

创建服务用证书 secret

  1. 编辑服务的 pod 规格。
  2. 使用您要用于 secret 的名称,添加 service.alpha.openshift.io/serving-cert-secret-name 注解。

    kind: Service
    apiVersion: v1
    metadata:
      name: my-service
      annotations:
          service.alpha.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 以确保已成功创建:

    $ oc get secrets
    
    NAME                         TYPE                                  DATA      AGE
    my-cert                  kubernetes.io/tls                     2         9m
    
    $ oc describe secret my-service-pod
    Name:         my-service-pod
    Namespace:    openshift-console
    Labels:       <none>
    Annotations:  kubernetes.io/service-account.name: builder
                  kubernetes.io/service-account.uid: ab-11e9-988a-0eb4e1b4a396
    
    Type:  kubernetes.io/service-account-token
    
    Data
    
    ca.crt:     5802 bytes
    namespace:  17 bytes
    token:      eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Ii
    wia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJvcGVuc2hpZnQtY29uc29sZSIsImt1YmVyb
    cnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiJhYmE4Y2UyZC00MzVlLTExZTktOTg4YS0wZWI0ZTFiNGEz
    OTYiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6b3BlbnNoaWZ
  5. 编辑与该 secret 搭配的 pod 规格。

    apiVersion: v1
    kind: Pod
    metadata:
      name: my-service-pod
    spec:
      containers:
      - name: mypod
        image: redis
        volumeMounts:
        - name: foo
          mountPath: "/etc/foo"
      volumes:
      - name: foo
        secret:
          secretName: my-cert
          items:
          - key: username
            path: my-group/my-username
            mode: 511

    当它可用时,您的 pod 将会运行。该证书对内部服务 DNS 名称 <service.name>.<service.namespace>.svc 有效。

    证书/密钥对在接近到期时自动替换。在 secret 的 service.alpha.openshift.io/expiry 注解中查看到期日期,其采用 RFC3339 格式。

    注意

    在大多数情形中,服务 DNS 名称 <service.name>.<service.namespace>.svc 不可从外部路由。<service.name>.<service.namespace>.svc 的主要用途是集群内或服务内通信,也用于重新加密路由。

1.5.5. secret 故障排除

如果服务证书生成失败并显示以下信息(服务的 service.alpha.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.alpha.openshift.io/serving-cert-generation-errorservice.alpha.openshift.io/serving-cert-generation-error-num,以强制重新生成证书:

$ oc delete secret <secret_name>
$ oc annotate service <service_name> service.alpha.openshift.io/serving-cert-generation-error-
$ oc annotate service <service_name> service.alpha.openshift.io/serving-cert-generation-error-num-
注意

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