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

8.3.1. 了解服务用证书

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

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

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

用于发布服务证书的服务 CA 证书在 26 个月内有效,并在有效期少于 6 个月时进行自动轮转。轮转后,以前的服务 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

8.3.2. 添加服务证书

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

重要

生成的证书仅对内部服务 DNS 名称 <service.name>.<service.namespace>.svc 有效,并且只适用于内部通信。

先决条件

  • 必须定义了服务。

流程

  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> 相同的名称。

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

    $ oc annotate service foo service.beta.openshift.io/serving-cert-secret-name=foo
  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 后,PodSpec 可以挂载它,Pod 也会在可用后运行。

8.3.3. 向 ConfigMap 添加服务证书

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

重要

向 ConfigMap 中添加此注解后,将删除其中的所有现有数据。建议您使用单独的 ConfigMap 来包含 service-ca.crt,而不要使用存储您的 Pod 配置的相同 ConfigMap。

流程

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

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

    在 volumeMount 中明确引用 service-ca.crt 键会使 Pod 无法启动,直到 ConfigMap 通过 CA 捆绑包注入后为止。

    例如,若要注解 ConfigMap foo,应使用以下命令:

    $ oc annotate configmap foo service.beta.openshift.io/inject-cabundle=true
  2. 查看 ConfigMap 以确保证书已经生成。这在 YAML 输出中显示为 service-ca.crt

    $ oc get configmap <configmap-name> -o yaml
    apiVersion: v1
    data:
      service-ca.crt: |
        -----BEGIN CERTIFICATE-----
    ...

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

您可以通过删除关联的 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

8.3.5. 手动轮转服务 CA 证书

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

如果需要,您可以按照以下步骤手动刷新服务 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 -d \
         | 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 会在删除后自动重启。