1.1 Verify Hummingbird

Overview

You verify a published Project Hummingbird / Red Hat Hardened Images runtime with cosign before anything is mirrored. You discover the workshop pin from cluster userinfo, complete the incomplete ConfigMap, and run cosign verify against that published digest.

Why it matters

Unsigned or unverified bases undermine every later signature, SBOM, and admission decision. Lightwell Network and Lightwell Clearinghouse Premier remediate application libraries. They are not this FROM. Hummingbird is the OS and runtime layer. A Premier GAV still needs a verified base.

What does it solve

  • Runtime bases that were never signature-checked

  • Mutable tags such as :latest instead of a digest pin

  • Mixing the Hummingbird Red Hat key with in-cluster RHTAS

  • Treating Lightwell as a runtime substitute

Why verify before you mirror

UBI is a general-purpose base image. Red Hat Hardened Images (registry.access.redhat.com/hi/…) are a minimal, signed runtime with a smaller attack surface and no package manager in the image. They are built for production constraints.

1.1 proves the published coordinate. 1.2 copies that trust into the cluster dest. Track 3 is when application FROM switches.

Published Hummingbird digest versus internal dest digest after learner oc-mirror

A Hummingbird Python runtime uses the same verify story (hi/python or the pin your catalog names). This Check is the Java hi/openjdk pin from userinfo.

Prerequisites

  • Bastion or Showroom terminal after Environment setup on the Welcome page (setup/lab-environment.sh). That script installs cosign, oc-mirror, and ec into ~/.local/bin from Red Hat images. Do not curl github.com for CLIs.

  • ConfigMap demo-userinfo-lightwell-repo in namespace lightwell-repo.

  • If command -v cosign prints nothing, run source ~/.bashrc or re-run the Welcome setup block.

Confirm the lab CLIs (expect a path and a version, not an empty prompt)
command -v cosign
command -v oc-mirror
cosign version
oc-mirror version

Discover the published pin

Do not paste a digest from chat, a slide, or this page’s narrative. The live pin is userinfo.

Read the source pull spec (what you verify in 1.1 and pin in 1.2)
oc -n lightwell-repo get configmap demo-userinfo-lightwell-repo \
  -o jsonpath='{.data.hummingbird_source_pullspec}{"\n"}{.data.dest_registry_host}{"\n"}'

Keep the pull spec. The @sha256:… on that line is the index (it may list more than amd64). This cluster and this Check are amd64. Dual-arch hands-on is out of this lab.

Here’s an example for you

The following verifies a different image with a non-Red Hat key URL. If your Check uses this block unchanged, it fails.

# Worked example ONLY — ubi-minimal + a key that is not Red Hat Hardened Images.
cosign verify \
  --key https://example.invalid/not-redhat-hardened-images.pub \
  --insecure-ignore-tlog \
  registry.access.redhat.com/ubi9/ubi-minimal:latest

Your change: complete the verify ConfigMap

The Check grades ConfigMap stub-01-hummingbird-verify in namespace lightwell-repo, key published-verify.sh. That key is a short shell script. It ships with two placeholders. You copy it to your home directory, fill those two strings, then write the file back onto the same ConfigMap. A file that exists only on the bastion does not pass. Leave REPLACE_ME in the cluster object and the Check fails.

There are exactly two substitutions.

Placeholder in the seed What you put there

REPLACE_ME_HUMMINGBIRD_PULLSPEC

The hummingbird_source_pullspec line you printed under Discover the published pin (the hi/openjdk digest, not ubi-minimal)

REPLACE_ME_COSIGN_KEY

https://security.access.redhat.com/data/63405576.txt (Red Hat Hardened Images public key, from the docs link below)

Do not paste the ubi-minimal worked example. Do not use an in-cluster Fulcio or Rekor URL. This Check is Red Hat’s published key, not Track 5 RHTAS.

1. Copy the seed out of the ConfigMap
oc -n lightwell-repo get configmap stub-01-hummingbird-verify \
  -o jsonpath='{.data.published-verify\.sh}' > ~/track-1-1-published-verify.sh
cat ~/track-1-1-published-verify.sh

You should see both REPLACE_ME_* strings. The seed looks like this:

#!/usr/bin/env bash
set -euo pipefail
export HUMMINGBIRD_PUBLISHED='REPLACE_ME_HUMMINGBIRD_PULLSPEC'
cosign verify \
  --key REPLACE_ME_COSIGN_KEY \
  --insecure-ignore-tlog \
  "${HUMMINGBIRD_PUBLISHED}"
2. Fill both placeholders from live userinfo (do not type a digest from this page)
PIN="$(oc -n lightwell-repo get configmap demo-userinfo-lightwell-repo \
  -o jsonpath='{.data.hummingbird_source_pullspec}')"
echo "PIN=${PIN}"
test -n "${PIN}"

cat > ~/track-1-1-published-verify.sh <<ENDSCRIPT
#!/usr/bin/env bash
set -euo pipefail
export HUMMINGBIRD_PUBLISHED='${PIN}'
cosign verify --key https://security.access.redhat.com/data/63405576.txt --insecure-ignore-tlog "\${HUMMINGBIRD_PUBLISHED}"
ENDSCRIPT

chmod +x ~/track-1-1-published-verify.sh
cat ~/track-1-1-published-verify.sh

The PIN= line must be a registry.access.redhat.com/hi/openjdk pull spec with @sha256:. The script body must show that pull spec and the 63405576.txt key URL, with no REPLACE_ME.

See Verify the integrity of Red Hat Hardened Images for why that key URL is the documented non-RHEL verify pattern. That host is Red Hat key distribution, not github.com. If the fetch is blocked, stop and tell an instructor.

3. Write the filled script back onto the ConfigMap
oc -n lightwell-repo create configmap stub-01-hummingbird-verify \
  --from-file=published-verify.sh=$HOME/track-1-1-published-verify.sh \
  --dry-run=client -o yaml | oc apply -f -
4. Confirm the cluster object is filled (this is what the Check reads)
oc -n lightwell-repo get configmap stub-01-hummingbird-verify \
  -o jsonpath='{.data.published-verify\.sh}'
echo
oc -n lightwell-repo get configmap stub-01-hummingbird-verify \
  -o jsonpath='{.data.published-verify\.sh}' | grep -E 'REPLACE_ME' \
  && echo 'STILL HAS PLACEHOLDERS' || echo 'placeholders gone'

Check: published cosign verify

Run your snippet — expect a successful verify for the published hi/openjdk pin
~/track-1-1-published-verify.sh
Fill the report

The Job also grades ConfigMap report-01-hummingbird-verify key consume_published. Set it to consume-published. Empty or REPLACE_ME fails even if cluster state is correct. Do not copy validate-docs.

oc -n lw-poc-validate edit configmap report-01-hummingbird-verify

The scored Check is Job validate-01-hummingbird-verify in lw-poc-validate. Direct nav URLs still work (honor system). Unlimited retries. There is no Solve.

Run the Validate Job
oc -n lw-poc-validate delete job validate-01-hummingbird-verify --ignore-not-found
TPL='job-01.yaml'
oc -n lw-poc-validate get configmap validate-job-templates \
  -o go-template="{{ index .data \"${TPL}\" }}" | oc create -f -
oc -n lw-poc-validate logs -f job/validate-01-hummingbird-verify

Expect CHECK PASSED: before you continue. CHECK FAILED: names the object to fix. Delete the Job and create it again as often as you need.

Honor system: later modules still open if you skip this. The Validate Job grades the ConfigMap (no REPLACE_ME, digest matches userinfo) — not a screenshot of this terminal.

Do not:

  • Pre-mirror or start Job oc-mirror-learner (that is 1.2)

  • Change the application Dockerfile FROM (Track 3)

  • Treat in-cluster RHTAS issuer/subject as this Check (those sign your app in Track 5)

Callout: multi-arch

The catalog index for this pin may list arm64 alongside amd64. This cluster and this Check are amd64. The pull spec you recorded is the index digest. You do not run a second architecture in the lab.

Official documentation

Key takeaways

  • TSSC starts with a signed published runtime. You consume Hummingbird. You do not rebuild the factory.

  • Verify the published digest before you mirror. 1.2 is a separate Check on the internal digest.

  • Lightwell Network / Clearinghouse Premier remediate libraries. They are not this FROM.

  • cosign and oc-mirror came from Welcome Environment setup (~/.local/bin). You did not download them from GitHub.

cd ~/ocp5-rhacs-showroom
bash setup/lab-cleanup.sh --module tssc-01