2.4. 容器镜像签名

红帽为 Red Hat Container Registries 中的镜像提供签名。在使用 Machine Config Operator(MCO)拉取到 OpenShift Container Platform 4 集群时,会自动验证这些签名。

Quay.io 提供了组成 OpenShift Container Platform 的大多数镜像,只有发行镜像会被签名。发行镜像指的是批准的 OpenShift Container Platform 镜像,它可以对供应链攻击提供一定程度的保护。但是,OpenShift Container Platform 的一些扩展(如日志记录、监控和服务网格)会作为 Operator Lifecycle Manager(OLM)的 Operator 提供。这些镜像来自 红帽生态系统目录容器镜像 registry。

要验证这些镜像在红帽 registry 和您的基础架构间的完整性,启用签名验证。

2.4.1. 为 Red Hat Container registry 启用签名验证

为 Red Hat Container Registries 启用容器签名验证需要编写签名验证策略文件,指定从这些 registry 中验证镜像的密钥。对于 RHEL8 节点,默认已在 /etc/containers/registries.d 中定义 registry。

流程

  1. 创建 Butane 配置文件 51-worker-rh-registry-trust.bu,其中包含 worker 节点的必要配置。

    注意

    如需有关 Butane 的信息,请参阅"使用 Butane 创建机器配置"。

    variant: openshift
    version: 4.12.0
    metadata:
      name: 51-worker-rh-registry-trust
      labels:
        machineconfiguration.openshift.io/role: worker
    storage:
      files:
      - path: /etc/containers/policy.json
        mode: 0644
        overwrite: true
        contents:
          inline: |
            {
              "default": [
                {
                  "type": "insecureAcceptAnything"
                }
              ],
              "transports": {
                "docker": {
                  "registry.access.redhat.com": [
                    {
                      "type": "signedBy",
                      "keyType": "GPGKeys",
                      "keyPath": "/etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release"
                    }
                  ],
                  "registry.redhat.io": [
                    {
                      "type": "signedBy",
                      "keyType": "GPGKeys",
                      "keyPath": "/etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release"
                    }
                  ]
                },
                "docker-daemon": {
                  "": [
                    {
                      "type": "insecureAcceptAnything"
                    }
                  ]
                }
              }
            }
  2. 使用 Butane 生成机器配置 YAML 文件 51-worker-rh-registry-trust.yaml,其中包含要写入 worker 节点上的磁盘的文件:

    $ butane 51-worker-rh-registry-trust.bu -o 51-worker-rh-registry-trust.yaml
  3. 应用创建的机器配置:

    $ oc apply -f 51-worker-rh-registry-trust.yaml
  4. 检查 worker 机器配置池已使用新机器配置推出:

    1. 检查是否创建了新机器配置:

      $ oc get mc

      输出示例

      NAME                                               GENERATEDBYCONTROLLER                      IGNITIONVERSION   AGE
      00-master                                          a2178ad522c49ee330b0033bb5cb5ea132060b0a   3.2.0             25m
      00-worker                                          a2178ad522c49ee330b0033bb5cb5ea132060b0a   3.2.0             25m
      01-master-container-runtime                        a2178ad522c49ee330b0033bb5cb5ea132060b0a   3.2.0             25m
      01-master-kubelet                                  a2178ad522c49ee330b0033bb5cb5ea132060b0a   3.2.0             25m
      01-worker-container-runtime                        a2178ad522c49ee330b0033bb5cb5ea132060b0a   3.2.0             25m
      01-worker-kubelet                                  a2178ad522c49ee330b0033bb5cb5ea132060b0a   3.2.0             25m
      51-master-rh-registry-trust                                                                   3.2.0             13s
      51-worker-rh-registry-trust                                                                   3.2.0             53s 1
      99-master-generated-crio-seccomp-use-default                                                  3.2.0             25m
      99-master-generated-registries                     a2178ad522c49ee330b0033bb5cb5ea132060b0a   3.2.0             25m
      99-master-ssh                                                                                 3.2.0             28m
      99-worker-generated-crio-seccomp-use-default                                                  3.2.0             25m
      99-worker-generated-registries                     a2178ad522c49ee330b0033bb5cb5ea132060b0a   3.2.0             25m
      99-worker-ssh                                                                                 3.2.0             28m
      rendered-master-af1e7ff78da0a9c851bab4be2777773b   a2178ad522c49ee330b0033bb5cb5ea132060b0a   3.2.0             8s
      rendered-master-cd51fd0c47e91812bfef2765c52ec7e6   a2178ad522c49ee330b0033bb5cb5ea132060b0a   3.2.0             24m
      rendered-worker-2b52f75684fbc711bd1652dd86fd0b82   a2178ad522c49ee330b0033bb5cb5ea132060b0a   3.2.0             24m
      rendered-worker-be3b3bce4f4aa52a62902304bac9da3c   a2178ad522c49ee330b0033bb5cb5ea132060b0a   3.2.0             48s 2

      1
      新机器配置
      2
      新的渲染机器配置
    2. 检查 worker 机器配置池是否使用新机器配置更新:

      $ oc get mcp

      输出示例

      NAME     CONFIG                                             UPDATED   UPDATING   DEGRADED   MACHINECOUNT   READYMACHINECOUNT   UPDATEDMACHINECOUNT   DEGRADEDMACHINECOUNT   AGE
      master   rendered-master-af1e7ff78da0a9c851bab4be2777773b   True      False      False      3              3                   3                     0                      30m
      worker   rendered-worker-be3b3bce4f4aa52a62902304bac9da3c   False     True       False      3              0                   0                     0                      30m 1

      1
      UPDATING 字段为 True 时,机器配置池会使用新机器配置进行更新。当字段变为 False 时,代表 worker 机器配置池已应用到新机器配置。
  5. 如果您的集群使用任何 RHEL7 worker 节点,当 worker 机器配置池被更新时,在 /etc/containers/registries.d 目录中在这些节点上创建 YAML 文件,用于指定给定 registry 服务器的分离签名的位置。以下示例只适用于托管在 registry.access.redhat.comregistry.redhat.io 中的镜像。

    1. 为每个 RHEL7 worker 节点启动一个 debug 会话:

      $ oc debug node/<node_name>
    2. 将您的根目录改为 /host

      sh-4.2# chroot /host
    3. 创建一个包含以下内容的 /etc/containers/registries.d/registry.redhat.io.yaml 文件:

      docker:
           registry.redhat.io:
               sigstore: https://registry.redhat.io/containers/sigstore
    4. 创建一个包含以下内容的 /etc/containers/registries.d/registry.access.redhat.com.yaml 文件:

      docker:
           registry.access.redhat.com:
               sigstore: https://access.redhat.com/webassets/docker/content/sigstore
    5. 退出 debug 会话。

2.4.2. 验证签名验证配置

将机器配置应用到集群后,Machine Config Controller 会检测到新的 MachineConfig 对象,并生成新的 rendered-worker-<hash> 版本。

先决条件

  • 您可以使用机器配置文件启用签名验证。

流程

  1. 在命令行中运行以下命令显示所需 worker 的信息:

    $ oc describe machineconfigpool/worker

    初始 worker 监控的输出示例

    Name:         worker
    Namespace:
    Labels:       machineconfiguration.openshift.io/mco-built-in=
    Annotations:  <none>
    API Version:  machineconfiguration.openshift.io/v1
    Kind:         MachineConfigPool
    Metadata:
      Creation Timestamp:  2019-12-19T02:02:12Z
      Generation:          3
      Resource Version:    16229
      Self Link:           /apis/machineconfiguration.openshift.io/v1/machineconfigpools/worker
      UID:                 92697796-2203-11ea-b48c-fa163e3940e5
    Spec:
      Configuration:
        Name:  rendered-worker-f6819366eb455a401c42f8d96ab25c02
        Source:
          API Version:  machineconfiguration.openshift.io/v1
          Kind:         MachineConfig
          Name:         00-worker
          API Version:  machineconfiguration.openshift.io/v1
          Kind:         MachineConfig
          Name:         01-worker-container-runtime
          API Version:  machineconfiguration.openshift.io/v1
          Kind:         MachineConfig
          Name:         01-worker-kubelet
          API Version:  machineconfiguration.openshift.io/v1
          Kind:         MachineConfig
          Name:         51-worker-rh-registry-trust
          API Version:  machineconfiguration.openshift.io/v1
          Kind:         MachineConfig
          Name:         99-worker-92697796-2203-11ea-b48c-fa163e3940e5-registries
          API Version:  machineconfiguration.openshift.io/v1
          Kind:         MachineConfig
          Name:         99-worker-ssh
      Machine Config Selector:
        Match Labels:
          machineconfiguration.openshift.io/role:  worker
      Node Selector:
        Match Labels:
          node-role.kubernetes.io/worker:
      Paused:                              false
    Status:
      Conditions:
        Last Transition Time:  2019-12-19T02:03:27Z
        Message:
        Reason:
        Status:                False
        Type:                  RenderDegraded
        Last Transition Time:  2019-12-19T02:03:43Z
        Message:
        Reason:
        Status:                False
        Type:                  NodeDegraded
        Last Transition Time:  2019-12-19T02:03:43Z
        Message:
        Reason:
        Status:                False
        Type:                  Degraded
        Last Transition Time:  2019-12-19T02:28:23Z
        Message:
        Reason:
        Status:                False
        Type:                  Updated
        Last Transition Time:  2019-12-19T02:28:23Z
        Message:               All nodes are updating to rendered-worker-f6819366eb455a401c42f8d96ab25c02
        Reason:
        Status:                True
        Type:                  Updating
      Configuration:
        Name:  rendered-worker-d9b3f4ffcfd65c30dcf591a0e8cf9b2e
        Source:
          API Version:            machineconfiguration.openshift.io/v1
          Kind:                   MachineConfig
          Name:                   00-worker
          API Version:            machineconfiguration.openshift.io/v1
          Kind:                   MachineConfig
          Name:                   01-worker-container-runtime
          API Version:            machineconfiguration.openshift.io/v1
          Kind:                   MachineConfig
          Name:                   01-worker-kubelet
          API Version:            machineconfiguration.openshift.io/v1
          Kind:                   MachineConfig
          Name:                   99-worker-92697796-2203-11ea-b48c-fa163e3940e5-registries
          API Version:            machineconfiguration.openshift.io/v1
          Kind:                   MachineConfig
          Name:                   99-worker-ssh
      Degraded Machine Count:     0
      Machine Count:              1
      Observed Generation:        3
      Ready Machine Count:        0
      Unavailable Machine Count:  1
      Updated Machine Count:      0
    Events:                       <none>

  2. 再次运行 oc describe 命令:

    $ oc describe machineconfigpool/worker

    worker 更新后的输出示例

    ...
        Last Transition Time:  2019-12-19T04:53:09Z
        Message:               All nodes are updated with rendered-worker-f6819366eb455a401c42f8d96ab25c02
        Reason:
        Status:                True
        Type:                  Updated
        Last Transition Time:  2019-12-19T04:53:09Z
        Message:
        Reason:
        Status:                False
        Type:                  Updating
      Configuration:
        Name:  rendered-worker-f6819366eb455a401c42f8d96ab25c02
        Source:
          API Version:            machineconfiguration.openshift.io/v1
          Kind:                   MachineConfig
          Name:                   00-worker
          API Version:            machineconfiguration.openshift.io/v1
          Kind:                   MachineConfig
          Name:                   01-worker-container-runtime
          API Version:            machineconfiguration.openshift.io/v1
          Kind:                   MachineConfig
          Name:                   01-worker-kubelet
          API Version:            machineconfiguration.openshift.io/v1
          Kind:                   MachineConfig
          Name:                   51-worker-rh-registry-trust
          API Version:            machineconfiguration.openshift.io/v1
          Kind:                   MachineConfig
          Name:                   99-worker-92697796-2203-11ea-b48c-fa163e3940e5-registries
          API Version:            machineconfiguration.openshift.io/v1
          Kind:                   MachineConfig
          Name:                   99-worker-ssh
      Degraded Machine Count:     0
      Machine Count:              3
      Observed Generation:        4
      Ready Machine Count:        3
      Unavailable Machine Count:  0
      Updated Machine Count:      3
    ...

    注意

    Observed Generation 参数显示基于控制器生成的配置的生成数量的增加数。此控制器即使没有处理规格并生成修订,也会更新这个值。Configuration Source 值指向 51-worker-rh-registry-trust 配置。

  3. 使用以下命令确认 policy.json 文件已存在:

    $ oc debug node/<node> -- chroot /host cat /etc/containers/policy.json

    输出示例

    Starting pod/<node>-debug ...
    To use host binaries, run `chroot /host`
    {
      "default": [
        {
          "type": "insecureAcceptAnything"
        }
      ],
      "transports": {
        "docker": {
          "registry.access.redhat.com": [
            {
              "type": "signedBy",
              "keyType": "GPGKeys",
              "keyPath": "/etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release"
            }
          ],
          "registry.redhat.io": [
            {
              "type": "signedBy",
              "keyType": "GPGKeys",
              "keyPath": "/etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release"
            }
          ]
        },
        "docker-daemon": {
          "": [
            {
              "type": "insecureAcceptAnything"
            }
          ]
        }
      }
    }

  4. 使用以下命令确认 registry.redhat.io.yaml 文件已存在:

    $ oc debug node/<node> -- chroot /host cat /etc/containers/registries.d/registry.redhat.io.yaml

    输出示例

    Starting pod/<node>-debug ...
    To use host binaries, run `chroot /host`
    docker:
         registry.redhat.io:
             sigstore: https://registry.redhat.io/containers/sigstore

  5. 使用以下命令确认 registry.access.redhat.com.yaml 文件已存在:

    $ oc debug node/<node> -- chroot /host cat /etc/containers/registries.d/registry.access.redhat.com.yaml

    输出示例

    Starting pod/<node>-debug ...
    To use host binaries, run `chroot /host`
    docker:
         registry.access.redhat.com:
             sigstore: https://access.redhat.com/webassets/docker/content/sigstore

2.4.3. 了解缺少可验证的容器镜像的验证

每个 OpenShift Container Platform 发行镜像都是不可变的,并使用红帽产品密钥签名。在 OpenShift Container Platform 更新或安装过程中,发行镜像可能会部署没有可验证签名的容器镜像。每个签名的发行镜像摘要都是不可变的。发行镜像中的每个引用都是另一个镜像的不可变摘要,因此内容可以被信任。换句话说,发行镜像中的签名会验证所有发行内容。

例如,没有可验证的签名的镜像引用包含在签名的 OpenShift Container Platform 发行镜像中:

发行信息输出示例

$ oc adm release info  quay.io/openshift-release-dev/ ocp-release@sha256:2309578b68c5666dad62aed696f1f9d778ae1a089ee461060ba7b9514b7ca417 -o pullspec 1
quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:9aafb914d5d7d0dec4edd800d02f811d7383a7d49e500af548eab5d00c1bffdb 2

1
签名的发行镜像 SHA。
2
容器镜像缺少发行版本中包含的可验证签名。

2.4.3.1. 更新过程中自动验证

签名验证是自动的。OpenShift Cluster Version Operator (CVO) 在 OpenShift Container Platform 更新过程中会在发行镜像上验证签名。这是一个内部过程。如果自动验证失败,OpenShift Container Platform 安装会失败。

也可以使用 skopeo 命令行工具手动验证签名。

2.4.3.2. 使用 skopeo 验证红帽容器镜像的签名

您可以通过从 OCP 发行镜像站点拉取这些签名来验证 OpenShift Container Platform 发行镜像中包含的容器镜像的签名。因为镜像站点上的签名不是 Podman 或 CRI-O 理解的格式,所以您可以使用 skopeo standalone-verify 命令来验证您的发行镜像是否由红帽签名。

先决条件

  • 已安装 skopeo 命令行工具。

流程

  1. 运行以下命令,获取您的发行版本的完整 SHA:

    $ oc adm release info <release_version>  \ 1
    1
    将 <release_version> 替换为您的版本号,如 4.14.3

    输出片断示例

    ---
    Pull From: quay.io/openshift-release-dev/ocp-release@sha256:e73ab4b33a9c3ff00c9f800a38d69853ca0c4dfa5a88e3df331f66df8f18ec55
    ---

  2. 运行以下命令关闭红帽发行密钥:

    $ curl -o pub.key https://access.redhat.com/security/data/fd431d51.txt
  3. 运行以下命令,获取您要验证的特定发行版本的签名文件:

    $ curl -o signature-1 https://mirror.openshift.com/pub/openshift-v4/signatures/openshift-release-dev/ocp-release/sha256%<sha_from_version>/signature-1 \ 1
    1
    <sha_from_version> 替换为与发行版本 SHA 匹配的镜像站点的完整链接中的 SHA 值。例如,到 4.12.23 发行版本的签名链接为 https://mirror.openshift.com/pub/openshift-v4/signatures/openshift-release-dev/ocp-release/sha256%e73ab4b33a9c3ff00c9f800a38d69853ca0c4dfa5a88e3df331f66df8f18ec55/signature-1,SHA 值为 e73ab4b33a9c3ff00c9f800a38d69853ca0c4dfa5a88e3df331f66df8f18ec55
  4. 运行以下命令,获取发行镜像的清单:

    $ skopeo inspect --raw docker://<quay_link_to_release> > manifest.json \ 1
    1
    <quay_link_to_release> 替换为 oc adm release info 命令的输出。例如: quay.io/openshift-release-dev/ocp-release@sha256:e73ab4b33a9c3ff00c9f800a38d69853ca0c4dfa5a88e3df331f66df8f18ec55
  5. 使用 skopeo 验证签名:

    $ skopeo standalone-verify manifest.json quay.io/openshift-release-dev/ocp-release:<release_number>-<arch> any signature-1 --public-key-file pub.key

    其中:

    <release_number>
    指定发行号,如 4.14.3
    <arch>

    指定架构,如 x86_64

    输出示例

    Signature verified using fingerprint 567E347AD0044ADE55BA8A5F199E2F91FD431D51, digest sha256:e73ab4b33a9c3ff00c9f800a38d69853ca0c4dfa5a88e3df331f66df8f18ec55

2.4.4. 其他资源