3.3. 使用服务提供的证书 secret 保护服务流量

3.3.1. 了解服务用证书

服务用证书旨在为需要加密的复杂中间件应用程序提供支持。这些证书是作为 TLS web 服务器证书发布的。

service-ca 控制器使用 x509.SHA256WithRSA 签名算法来生成服务证书。

生成的证书和密钥采用 PEM 格式,分别存储在所创建 secret 的 tls.crttls.key 中。证书和密钥在接近到期时自动替换。

用于发布服务证书的服务 CA 证书在 26 个月内有效,并在有效期少于 13 个月时进行自动轮转。轮转后,以前的服务 CA 配置仍会被信任直到其过期为止。这将为所有受影响的服务建立一个宽限期,以在过期前刷新其密钥内容。如果没有在这个宽限期内对集群进行升级(升级会重启服务并刷新其密钥),您可能需要手动重启服务以避免在上一个服务 CA 过期后出现故障。

注意

您可以使用以下命令来手动重启集群中的所有 pod。此命令会导致服务中断,因为它将删除每个命名空间中运行的所有 pod。这些 Pod 会在删除后自动重启。

$ for I in $(oc get ns -o jsonpath='{range .items[*]} {.metadata.name}{"\n"} {end}'); \
      do oc delete pods --all -n $I; \
      sleep 1; \
      done

3.3.2. 添加服务证书

要保证与服务的通信的安全,请在与服务相同的命名空间中将签名的服务证书和密钥对生成 secret。

生成的证书仅对内部服务 DNS 名称 <service.name>.<service.namespace>.svc 有效,并且只适用于内部通信。如果您的服务是一个无头服务(未设置 clusterIP 值),则生成的证书还包含通配符主题,格式为 *.<service.name>.<service.namespace>.svc

重要

因为生成的证书包含无头服务的通配符主题,因此如果您的客户端必须区分不同的 pod,则不得使用服务 CA。在这种情况下:

  • 使用其他 CA 生成各个 TLS 证书。
  • 对于定向到单个 pod 且不得被其他 pod 模拟的连接,不接受服务 CA 作为可信 CA。这些连接必须配置为信任用于生成单个 TLS 证书的 CA。

先决条件:

  • 必须定义了服务。

流程

  1. 使用 service.beta.openshift.io/serving-cert-secret-name 注解该服务:

    $ oc annotate service <service_name> \1
         service.beta.openshift.io/serving-cert-secret-name=<secret_name> 2
    1
    <service_name> 替换为要保护的服务的名称。
    2
    <secret_name> 是生成的 secret 的名称,该 secret 包含证书和密钥对。为方便起见,建议您使用与 <service_name> 相同的名称。

    例如,使用以下命令来注解服务 test1:

    $ oc annotate service test1 service.beta.openshift.io/serving-cert-secret-name=test1
  2. 检查服务以确认是否存在注解:

    $ oc describe service <service_name>

    输出示例

    ...
    Annotations:              service.beta.openshift.io/serving-cert-secret-name: <service_name>
                              service.beta.openshift.io/serving-cert-signed-by: openshift-service-serving-signer@1556850837
    ...

  3. 在集群为服务生成 secret 后,Pod spec 可以挂载它,pod 将在可用后运行。

其他资源

3.3.3. 将服务 CA 捆绑包添加到配置映射中

Pod 可通过挂载使用 service.beta.openshift.io/inject-cabundle=true 注解的 ConfigMap 对象来访问服务 CA 证书。注解后,集群会自动将服务 CA 证书注入配置映射上的 service-ca.crt 键。访问此 CA 证书可允许 TLS 客户端使用服务用证书验证服务连接。

重要

将这个注解添加到配置映射后,会删除其中的所有现有数据。建议您使用单独的配置映射来包含 service-ca.crt,而不是使用存储您的 Pod 配置的同一配置映射。

流程

  1. 使用 service.beta.openshift.io/inject-cabundle=true 注解配置映射:

    $ oc annotate configmap <config_map_name> \1
         service.beta.openshift.io/inject-cabundle=true
    1
    <config_map_name> 替换为配置映射的名称。
    注意

    在卷挂载中明确引用 service-ca.crt 键可防止 pod 启动,直到配置映射使用 CA 捆绑包注入为止。可通过为卷的 serving 证书将 optional字段设置为 true 来覆盖此行为。

    例如,使用以下命令来注解配置映射 test1:

    $ oc annotate configmap test1 service.beta.openshift.io/inject-cabundle=true
  2. 查看配置映射,以确保注入了服务 CA 捆绑包:

    $ oc get configmap <config_map_name> -o yaml

    CA 捆绑包在 YAML 输出中作为 service-ca.crt 键的值显示:

    apiVersion: v1
    data:
      service-ca.crt: |
        -----BEGIN CERTIFICATE-----
    ...

3.3.4. 将服务 CA 捆绑包添加到 API 服务

您可以使用 service.beta.openshift.io/inject-cabundle=true 注解 APIService 对象,使其 spec.caBundle 字段由服务 CA 捆绑包填充。这可让 Kubernetes API 服务器验证用于保护目标端点的安全的服务 CA 证书。

流程

  1. 使用 service.beta.openshift.io/inject-cabundle=true 注解 API 服务:

    $ oc annotate apiservice <api_service_name> \1
         service.beta.openshift.io/inject-cabundle=true
    1
    <api_service_name> 替换为要注解的 API 服务的名称。

    例如,使用以下命令来注解 API 服务 test1:

    $ oc annotate apiservice test1 service.beta.openshift.io/inject-cabundle=true
  2. 查看 API 服务,以确保注入了服务 CA 捆绑包:

    $ oc get apiservice <api_service_name> -o yaml

    CA 捆绑包在 YAML 输出中的 spec.caBundle 字段中显示:

    apiVersion: apiregistration.k8s.io/v1
    kind: APIService
    metadata:
      annotations:
        service.beta.openshift.io/inject-cabundle: "true"
    ...
    spec:
      caBundle: <CA_BUNDLE>
    ...

3.3.5. 将服务 CA 捆绑包添加到自定义资源定义中

您可以使用 service.beta.openshift.io/inject-cabundle=true 注解 CustomResourceDefinition(CRD)对象,使其 spec.conversion.webhook.clientConfig.caBundle 字段 由服务 CA 捆绑包填充。这可让 Kubernetes API 服务器验证用于保护目标端点的安全的服务 CA 证书。

注意

只有在 CRD 被配置为使用 webhook 进行转换,才会将服务 CA 捆绑包注入 CRD。只有在 CRD 的 webhook 需要使用服务 CA 证书时,注入服务 CA 捆绑包才有意义。

流程

  1. 使用 service.beta.openshift.io/inject-cabundle=true 注解 CRD:

    $ oc annotate crd <crd_name> \1
         service.beta.openshift.io/inject-cabundle=true
    1
    <crd_name> 替换为要注解的 CRD 的名称。

    例如,使用以下命令来注解 CRD test1:

    $ oc annotate crd test1 service.beta.openshift.io/inject-cabundle=true
  2. 查看 CRD,以确保注入了服务 CA 捆绑包:

    $ oc get crd <crd_name> -o yaml

    CA 捆绑包在 YAML 输出中的 spec.conversion.webhook.clientConfig.caBundle 字段中显示:

    apiVersion: apiextensions.k8s.io/v1
    kind: CustomResourceDefinition
    metadata:
      annotations:
        service.beta.openshift.io/inject-cabundle: "true"
    ...
    spec:
      conversion:
        strategy: Webhook
        webhook:
          clientConfig:
            caBundle: <CA_BUNDLE>
    ...

3.3.6. 将服务 CA 捆绑包添加到变异的 webhook 配置中

您可以使用 service.beta.openshift.io/inject-cabundle=true 注解 MutatingWebhookConfiguration 对象,使每个 webhook 的 clientConfig.caBundle 字段由服务 CA 捆绑包填充。这可让 Kubernetes API 服务器验证用于保护目标端点的安全的服务 CA 证书。

注意

不要为 admission webhook 配置设置此注解,不同的 webhook 需要指定不同的 CA 捆绑包。如果您这样做了,则会为所有 webhook 注入这个服务 CA 捆绑包。

流程

  1. 使用 service.beta.openshift.io/inject-cabundle=true 注解变异 Webhook 配置:

    $ oc annotate mutatingwebhookconfigurations <mutating_webhook_name> \1
         service.beta.openshift.io/inject-cabundle=true
    1
    <mutating_webhook_name> 替换为要注解的变异 Webhook 配置的名称。

    例如,使用以下命令来注解变异 Webhook 配置 test1:

    $ oc annotate mutatingwebhookconfigurations test1 service.beta.openshift.io/inject-cabundle=true
  2. 查看变异 Webhook 配置,以确保注入了服务 CA 捆绑包:

    $ oc get mutatingwebhookconfigurations <mutating_webhook_name> -o yaml

    CA 捆包在 YAML 输出中所有 webhook 的 clientConfig.caBundle 字段中显示:

    apiVersion: admissionregistration.k8s.io/v1
    kind: MutatingWebhookConfiguration
    metadata:
      annotations:
        service.beta.openshift.io/inject-cabundle: "true"
    ...
    webhooks:
    - myWebhook:
      - v1beta1
      clientConfig:
        caBundle: <CA_BUNDLE>
    ...

3.3.7. 将服务 CA 捆绑包添加到验证 webhook 配置中

您可以使用 service.beta.openshift.io/inject-cabundle=true 注解 ValidatingWebhookConfiguration 对象,使每个 webhook 的 clientConfig.caBundle 字段 由服务 CA 捆绑包填充。这可让 Kubernetes API 服务器验证用于保护目标端点的安全的服务 CA 证书。

注意

不要为 admission webhook 配置设置此注解,不同的 webhook 需要指定不同的 CA 捆绑包。如果您这样做了,则会为所有 webhook 注入这个服务 CA 捆绑包。

流程

  1. 使用 service.beta.openshift.io/inject-cabundle=true 注解验证 Webhook 配置:

    $ oc annotate validatingwebhookconfigurations <validating_webhook_name> \1
         service.beta.openshift.io/inject-cabundle=true
    1
    <validating_webhook_name> 替换为要注解的验证 webhook 配置的名称。

    例如,使用以下命令来注解验证 webhook 配置 test1:

    $ oc annotate validatingwebhookconfigurations test1 service.beta.openshift.io/inject-cabundle=true
  2. 查看验证 Webhook 配置,以确保注入了服务 CA 捆绑包:

    $ oc get validatingwebhookconfigurations <validating_webhook_name> -o yaml

    CA 捆包在 YAML 输出中所有 webhook 的 clientConfig.caBundle 字段中显示:

    apiVersion: admissionregistration.k8s.io/v1
    kind: ValidatingWebhookConfiguration
    metadata:
      annotations:
        service.beta.openshift.io/inject-cabundle: "true"
    ...
    webhooks:
    - myWebhook:
      - v1beta1
      clientConfig:
        caBundle: <CA_BUNDLE>
    ...

3.3.8. 手动轮转生成的服务证书

您可以通过删除关联的 secret 来轮换服务证书。删除 secret 会导致自动创建新 secret,进而生成新的证书。

先决条件

  • 必须为服务生成了包含证书和密钥对的 secret。

流程

  1. 检查该服务以确定包含证书的 secret。这可以在 service-cert-secret-name 注解中找到,如下所示。

    $ oc describe service <service_name>

    输出示例

    ...
    service.beta.openshift.io/serving-cert-secret-name: <secret>
    ...

  2. 删除为服务生成的 secret。此过程将自动重新创建 secret。

    $ oc delete secret <secret> 1
    1
    <secret> 替换为前一步中的 secret 名称。
  3. 通过获取新 secret 并检查 AGE 来确认已经重新创建了证书。

    $ oc get secret <service_name>

    输出示例

    NAME              TYPE                DATA   AGE
    <service.name>    kubernetes.io/tls   2      1s

3.3.9. 手动轮转服务 CA 证书

服务 CA 在 26 个月内有效,并在有效期少于 13 个月时进行刷新。

如果需要,您可以按照以下步骤手动刷新服务 CA。

警告

手动轮换的服务 CA 不会保留对上一个服务 CA 的信任。在集群中的 pod 重启完成前,您的服务可能会临时中断。pod 重启可以确保 Pod 使用由新服务 CA 发布的证书服务。

先决条件

  • 必须以集群管理员身份登录。

流程

  1. 使用以下命令,查看当前服务 CA 证书的到期日期。

    $ oc get secrets/signing-key -n openshift-service-ca \
         -o template='{{index .data "tls.crt"}}' \
         | base64 --decode \
         | openssl x509 -noout -enddate
  2. 手动轮转服务 CA。此过程会生成一个新的服务 CA,用来为新服务证书签名。

    $ oc delete secret/signing-key -n openshift-service-ca
  3. 要将新证书应用到所有服务,请重启集群中的所有 pod。此命令确保所有服务都使用更新的证书。

    $ for I in $(oc get ns -o jsonpath='{range .items[*]} {.metadata.name}{"\n"} {end}'); \
          do oc delete pods --all -n $I; \
          sleep 1; \
          done
    警告

    此命令会导致服务中断,因为它将遍历并删除每个命名空间中运行的 Pod。这些 Pod 会在删除后自动重启。