Skip to content

OTA-1773: manifests*/0000_90_cluster-update-keys_configmap: New release-repository-*#90

Open
wking wants to merge 2 commits into
openshift:mainfrom
wking:release-repository
Open

OTA-1773: manifests*/0000_90_cluster-update-keys_configmap: New release-repository-*#90
wking wants to merge 2 commits into
openshift:mainfrom
wking:release-repository

Conversation

@wking
Copy link
Copy Markdown
Member

@wking wking commented Dec 10, 2025

Preparation for Sigstore, as described in the README text I'm adding:

  • release-repository-*: In addition to checking for valid OpenPGP signatures, the cluster-version operator will also require the that target release image pullspec matches one of these expected registries.
    This supports an eventual transition from OpenPGP signatures to Sigstore signatures, where:
    • ClusterImagePolicies such as the openshift policy cover authentication ("yes, the configured policy for that scope asserts that the image is actually quay.io/openshift-release-dev/ocp-release@sha256:a29b..." vs. "no, the configured policy for that scope fails on quay.io/openshift-release-dev/ocp-release@sha256:0000..., it might be malicious or corrupted").
    • The release pullspec check covers authorization ("yes, quay.io/openshift-release-dev/ocp-release is the expected repository for OCP releases" vs. "no, quay.io/okd/scos-release is not the expected repository for OCP release, you probably don't want to update your OCP cluster to an OKD release image").

Also some other modernization of README text; details in the commit messages :)

@openshift-ci openshift-ci Bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Dec 10, 2025
@openshift-ci openshift-ci Bot requested review from jupierce and sdodson December 10, 2025 00:31
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented Dec 10, 2025

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: wking
Once this PR has been reviewed and has the lgtm label, please assign mrunalp for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

wking added 2 commits December 9, 2025 16:32
…ory-*

Preparation for Sigstore, as described in the README text I'm adding.
I backed off on some of the signature assertions in the previous
README, but checking some recent releases to see who's signing what,
OCP releases are signed by release key 2 [1]:

  $ DIGEST="$(oc image info -o json quay.io/openshift-release-dev/ocp-release:4.20.6-x86_64 | jq -r .digest)"
  $ echo "${DIGEST}"
  sha256:a29bcbc9f286d68b394ffa0288c5de7e487c90077c06cbaf7a4cadeb0398ce28
  $ curl -s "https://mirror.openshift.com/pub/openshift-v4/signatures/openshift/release/${DIGEST/:/=}/signature-1" | gpg --decrypt | jq .
  gpg: Signature made Thu 27 Nov 2025 11:27:17 AM PST
  gpg:                using RSA key 199E2F91FD431D51
  gpg: Good signature from "Red Hat, Inc. (release key 2) <security@redhat.com>" [unknown]
  gpg: WARNING: This key is not certified with a trusted signature!
  gpg:          There is no indication that the signature belongs to the owner.
  Primary key fingerprint: 567E 347A D004 4ADE 55BA  8A5F 199E 2F91 FD43 1D51
  {
    "critical": {
      "image": {
        "docker-manifest-digest": "sha256:a29bcbc9f286d68b394ffa0288c5de7e487c90077c06cbaf7a4cadeb0398ce28"
      },
      "type": "atomic container signature",
      "identity": {
        "docker-reference": "quay.io/openshift-release-dev/ocp-release:4.20.6-x86_64"
      }
    },
    "optional": {
      "creator": "Red Hat OpenShift Signing Authority 0.0.1"
    }
  }
  $ gpg --list-packets <keys/verifier-public-key-redhat-release | grep 'keyid: .*FD431D51'
  	keyid: 199E2F91FD431D51

OCP Engineering candidates are signed by beta 2 [2]:

  $ DIGEST="$(oc image info -o json quay.io/openshift-release-dev/ocp-release:4.21.0-ec.3-x86_64 | jq -r .digest)"
  $ echo "${DIGEST}"
  sha256:e3a750749770f4435360852de7c566e370bef20ad90cdc1446e8ac84e4728e49
  $ curl -s "https://mirror.openshift.com/pub/openshift-v4/signatures/openshift/release/${DIGEST/:/=}/signature-1" | gpg --decrypt | jq .
  gpg: Signature made Wed 19 Nov 2025 01:45:57 AM PST
  gpg:                using RSA key 938A80CAF21541EB
  gpg: Good signature from "Red Hat, Inc. (beta key 2) <security@redhat.com>" [unknown]
  gpg: WARNING: This key is not certified with a trusted signature!
  gpg:          There is no indication that the signature belongs to the owner.
  Primary key fingerprint: B08B 659E E86A F623 BC90  E8DB 938A 80CA F215 41EB
  {
    "critical": {
      "image": {
        "docker-manifest-digest": "sha256:e3a750749770f4435360852de7c566e370bef20ad90cdc1446e8ac84e4728e49"
      },
      "type": "atomic container signature",
      "identity": {
        "docker-reference": "quay.io/openshift-release-dev/ocp-release:4.21.0-ec.3-x86_64"
      }
    },
    "optional": {
      "creator": "Red Hat OpenShift Signing Authority 0.0.1"
    }
  }
  $ gpg --list-packets <keys/verifier-public-key-redhat-beta-2 | grep 'keyid: .*F21541EB'
  	keyid: 938A80CAF21541EB

OCP nightlies are signed by the CI key [3]:

  $ DIGEST="$(oc image info -o json registry.ci.openshift.org/ocp/release:4.21.0-0.nightly-2025-12-09-062745 | jq -r .digest)"
  $ echo "${DIGEST}"
  sha256:80fa69fc5aaa9ac897df610817f60649d4310c2ab362bef6ed85fbff2203c441
  $ curl -s "https://storage.googleapis.com/openshift-ci-release/releases/signatures/openshift/release/${DIGEST/:/=}/signature-1" | gpg --decrypt | jq .
  gpg: Signature made Mon 08 Dec 2025 10:31:15 PM PST
  gpg:                using RSA key 6A9588F07F2D3AE7973AD2A9193E53CCD2E2F7A4
  gpg: Good signature from "openshift-ci-release-key (This key is used to sign releases from the OpenShift CI system) <brawilli@redhat.com>" [unknown]
  gpg: WARNING: This key is not certified with a trusted signature!
  gpg:          There is no indication that the signature belongs to the owner.
  Primary key fingerprint: 6A95 88F0 7F2D 3AE7 973A  D2A9 193E 53CC D2E2 F7A4
  {
    "critical": {
      "type": "atomic container signature",
      "image": {
        "docker-manifest-digest": "sha256:80fa69fc5aaa9ac897df610817f60649d4310c2ab362bef6ed85fbff2203c441"
      },
      "identity": {
        "docker-reference": "registry.ci.openshift.org/ocp/release:4.21.0-0.nightly-2025-12-09-062745"
      }
    },
    "optional": {
      "creator": "openshift release-controller",
      "timestamp": 1765261875
    }
  }
  $ gpg --list-packets <keys/verifier-public-key-openshift-ci-4 | grep 'keyid: .*D2E2F7A4'
  	keyid: 193E53CCD2E2F7A4

That does not seem all that useful, because they don't trust that key:

  $ oc adm release extract --to nightly registry.ci.openshift.org/ocp/release:4.21.0-0.nightly-2025-12-09-062745
  $ diff -wU3 nightly/0000_90_cluster-update-keys_configmap.yaml manifests.rhel/0000_90_cluster-update-keys_configmap.yaml
  ...no key difference...

But whatever, nightlies are internal and not customer facing, and they
don't support updates [4]:

  Nightly (Internal)   ... Red Hat internal use for inter-op and continuous QE testing...

AND OCP CI forces the updates, so it doesn't care if they're signed or not.

CI releases are not signed by anything [5], not sure why not:

  $ DIGEST="$(oc image info -o json registry.ci.openshift.org/ocp/release:4.21.0-0.ci-2025-12-09-151854 | jq -r .digest)"
  $ echo "${DIGEST}"
  sha256:f472f3cf10e72bb2b9d7289093ee63b8d1823184f3fa996f9913afffc9fd64bc
  $ curl -s "https://storage.googleapis.com/openshift-ci-release/releases/signatures/openshift/release/${DIGEST/:/=}/signature-1" | gpg --decrypt | jq .
  gpg: no valid OpenPGP data found.
  gpg: decrypt_message failed: Unknown system error

A recent 4-scos-stable release is signed by the CI key [6]:

  $ DIGEST="$(oc image info -o json quay.io/okd/scos-release:4.20.0-okd-scos.12 | jq -r .digest)"
  $ echo "${DIGEST}"
  sha256:9c0435c9552cfa98248532d3e8b0ecd7020ca332ba2a0bba21d2c8f0185d8fb5
  $ curl -s "https://storage.googleapis.com/openshift-ci-release/releases/signatures/openshift/release/${DIGEST/:/=}/signature-1" | gpg --decrypt | jq .
  gpg: Signature made Sun 07 Dec 2025 09:43:21 PM PST
  gpg:                using RSA key 6A9588F07F2D3AE7973AD2A9193E53CCD2E2F7A4
  gpg: Good signature from "openshift-ci-release-key (This key is used to sign releases from the OpenShift CI system) <brawilli@redhat.com>" [unknown]
  gpg: WARNING: This key is not certified with a trusted signature!
  gpg:          There is no indication that the signature belongs to the owner.
  Primary key fingerprint: 6A95 88F0 7F2D 3AE7 973A  D2A9 193E 53CC D2E2 F7A4
  {
    "critical": {
      "type": "atomic container signature",
      "image": {
        "docker-manifest-digest": "sha256:9c0435c9552cfa98248532d3e8b0ecd7020ca332ba2a0bba21d2c8f0185d8fb5"
      },
      "identity": {
        "docker-reference": "quay.io/okd/scos-release:4.20.0-okd-scos.12"
      }
    },
    "optional": {
      "creator": "openshift release-controller",
      "timestamp": 1765172601
    }
  }

and they trust that key:

  $ oc adm release extract --to okd quay.io/okd/scos-release:4.20.0-okd-scos.12
  $ diff -wU3 okd/0000_90_cluster-update-keys_configmap.yaml manifests/0000_90_cluster-update-keys_configmap.yaml
  ...no key differences...

OKD Engineering Candidates are also signed by the CI key [7]:

  $ DIGEST="$(oc image info -o json quay.io/okd/scos-release:4.21.0-okd-scos.ec.13 | jq -r .digest)"
  $ echo "${DIGEST}"
  sha256:a303ecbfab19d1d98d2258efde3b43cac4c308bedff49e3c10a27314b70dfe37
  $ curl -s "https://storage.googleapis.com/openshift-ci-release/releases/signatures/openshift/release/${DIGEST/:/=}/signature-1" | gpg --decrypt | jq .
  gpg: Signature made Sun 07 Dec 2025 09:15:46 PM PST
  gpg:                using RSA key 6A9588F07F2D3AE7973AD2A9193E53CCD2E2F7A4
  gpg: Good signature from "openshift-ci-release-key (This key is used to sign releases from the OpenShift CI system) <brawilli@redhat.com>" [unknown]
  gpg: WARNING: This key is not certified with a trusted signature!
  gpg:          There is no indication that the signature belongs to the owner.
  Primary key fingerprint: 6A95 88F0 7F2D 3AE7 973A  D2A9 193E 53CC D2E2 F7A4
  {
    "critical": {
      "type": "atomic container signature",
      "image": {
        "docker-manifest-digest": "sha256:a303ecbfab19d1d98d2258efde3b43cac4c308bedff49e3c10a27314b70dfe37"
      },
      "identity": {
        "docker-reference": "quay.io/okd/scos-release:4.21.0-okd-scos.ec.13"
      }
    },
    "optional": {
      "creator": "openshift release-controller",
      "timestamp": 1765170946
    }
  }

[1]: https://amd64.ocp.releases.ci.openshift.org/#4-stable
[2]: https://amd64.ocp.releases.ci.openshift.org/#4-dev-preview
[3]: https://amd64.ocp.releases.ci.openshift.org/#4.21.0-0.nightly
[4]: https://mirror.openshift.com/pub/openshift-v4/OpenShift_Release_Types.pdf
[5]: https://amd64.ocp.releases.ci.openshift.org/#4.21.0-0.ci
[6]: https://amd64.origin.releases.ci.openshift.org/#4-scos-stable
[7]: https://amd64.origin.releases.ci.openshift.org/#4-scos-next
…'namespace'

Cleaning up after 9af1fc2 (Add IBM Cloud managed annotations to CVO
manifests, 2020-11-11, openshift#24).  We only need to set the namespace key
once.
@wking wking force-pushed the release-repository branch from 5e434bd to a1cba4a Compare December 10, 2025 00:32
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented Dec 10, 2025

@wking: all tests passed!

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Copy link
Copy Markdown

@mtrmac mtrmac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the principle of the thing: From an earlier discussion I understand

  • We can extract / authenticate the version number from the release image of the update target (or from a verified signature of the update target?), in a way the update graph can’t affect
  • CVO will refuse to downgrade to earlier (even if correctly signed) versions

LGTM assuming the above.


On form:

  • If the thing we are trying to protect against is the update graph pointing at out-of-product images, that might be worth noting here.
  • I’m not sure about the authentication/authorization phrasing of the concepts (I tend to think it applies to principals, not to objects), but it works well enough and I don’t have a good short replacement for the latter one.

@QiWang19
Copy link
Copy Markdown
Member

ACK I agree we can keep image pullspec lockdown separate from signature verification. ClusterImagePolicy can provide scoped verification at the digest level that the CVO can consume and trust.

@wking
Copy link
Copy Markdown
Member Author

wking commented Dec 16, 2025

We can extract / authenticate the version number from the release image of the update target (or from a verified signature of the update target?), in a way the update graph can’t affect

Yes, that happens here, for users who set ClusterVersion's spec.desired.version to let us know which version they're expecting to retrieve.

CVO will refuse to downgrade to earlier (even if correctly signed) versions

Yes, that happens here, with a narrow carve-out for rolling back to the previous target version, if that previous target version is in the same z-stream as the current target version.

If the thing we are trying to protect against is the update graph pointing at out-of-product images, that might be worth noting here.

The update-service might have been the one recommending the update, but it's also possible that the cluster admin used a different pipeline, including passing around pullspecs via word-of-mouth, or whatever. This new guard is trying to stiffen cluster protection for all sources of next-hop update advice, under the assumption that no tooling in that space will ever be so reliable that we can trust it without guard-rails.

@wking wking changed the title WIP: manifests*/0000_90_cluster-update-keys_configmap: New release-repository-* OTA-1773: manifests*/0000_90_cluster-update-keys_configmap: New release-repository-* Dec 16, 2025
@openshift-ci openshift-ci Bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Dec 16, 2025
@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Dec 16, 2025
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

openshift-ci-robot commented Dec 16, 2025

@wking: This pull request references OTA-1773 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.22.0" version, but no target version was set.

Details

In response to this:

Preparation for Sigstore, as described in the README text I'm adding:

  • release-repository-*: In addition to checking for valid OpenPGP signatures, the cluster-version operator will also require the that target release image pullspec matches one of these expected registries.
    This supports an eventual transition from OpenPGP signatures to Sigstore signatures, where:
    • ClusterImagePolicies such as the openshift policy cover authentication ("yes, the configured policy for that scope asserts that the image is actually quay.io/openshift-release-dev/ocp-release@sha256:a29b..." vs. "no, the configured policy for that scope fails on quay.io/openshift-release-dev/ocp-release@sha256:0000..., it might be malicious or corrupted").
    • The release pullspec check covers authorization ("yes, quay.io/openshift-release-dev/ocp-release is the expected repository for OCP releases" vs. "no, quay.io/okd/scos-release is not the expected repository for OCP release, you probably don't want to update your OCP cluster to an OKD release image").

Also some other modernization of README text; details in the commit messages :)

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@mtrmac
Copy link
Copy Markdown

mtrmac commented Jan 5, 2026

Thanks for the references, LGTM. (I’ll leave formal / tool-visible approvals to specialist maintainers of this repo.)

@openshift-bot
Copy link
Copy Markdown
Contributor

Issues go stale after 90d of inactivity.

Mark the issue as fresh by commenting /remove-lifecycle stale.
Stale issues rot after an additional 30d of inactivity and eventually close.
Exclude this issue from closing by commenting /lifecycle frozen.

If this issue is safe to close now please do so with /close.

/lifecycle stale

@openshift-ci openshift-ci Bot added the lifecycle/stale Denotes an issue or PR has remained open with no activity and has become stale. label Apr 9, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 9, 2026

Important

Review skipped

Auto reviews are limited based on label configuration.

🚫 Review skipped — only excluded labels are configured. (1)
  • do-not-merge/work-in-progress

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: feab6245-84c6-48d7-8e4c-b578b387cd52

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. lifecycle/stale Denotes an issue or PR has remained open with no activity and has become stale.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants