5.3 Disconnected verify
On this page you prove that the application digest also carries a signature you can verify with a public key, without calling Fulcio.
Track 5 is sign and attest. This is the third page. 5.1 Sign already signed that digest with Trusted Artifact Signer. You generate a cosign key pair on the Showroom terminal, run cosign sign --key, and then cosign verify --key. The cluster stays on the network. You are practicing the procedure a disconnected plant uses, which is a key you can carry. You are not building a physical air gap. Mirrored TUF for keyless verifiers, and a simulated media drop, live in Appendix: disconnected transfer.
Why this control exists
Keyless signing needs Fulcio when the signature is created, and a TUF root when it is verified. A plant that cannot reach Fulcio at verify time still needs a public key it controls. You add that second signature here, on the same digest. The keyless signature stays on the image.
Native ImagePolicy signedEmail cannot hold the 5.1 Kubernetes service-account URI. 6.1 GitOps + admission therefore renders CRI-O policy as policyType: PublicKey from the PEM you publish. That PEM is ConfigMap lab-cosign-pubkey in namespace tssc-admission. 5.1 Sign draws the keyless column. This page is the other signature: ~/lab-trust/cosign.key signs, and cosign.pub is what admission will trust.
The right column is this page. cosign generate-key-pair stays on the Showroom terminal, cosign sign --key signs the digest with --tlog-upload=false, and 6.1 reads cosign.pub as policyType: PublicKey.
Lightwell Network and Lightwell Clearinghouse Premier artifacts may already have their own signatures. This Check is the application image. Premier does not replace the key pair.
|
The private key stays on this terminal. It does not go in Git, and it does not go in a screenshot. |
In a customer engagement, a disconnected plant verifies with keys, and it keeps a mirrored TUF root for any artifact that was signed keylessly. You generate the pair on this terminal and sign the digest you already built. Red Hat does not operate a data diode on this cluster. An empty COSIGN_PASSWORD is for this non-interactive lab terminal. A customer plant uses a real passphrase.
Learning objectives
By the end of this module, you will be able to:
-
Generate a cosign key pair under
/home/lab-user/lab-trustand sign the application digest with--keyand--tlog-upload=false -
Verify that digest with
cosign verify --key -
Publish
cosign.pubto ConfigMaplab-cosign-pubkeyso 6.1 can render ImagePolicy -
Explain that a Lightwell library signature is a different layer from this application key
The digest you already signed
cosign is already on the Showroom PATH. Success is a dockerImageReference for spring-boot-lw-poc:latest in the build namespace, and an empty ~/lab-trust before you generate the key.
BUILD_NS="$(oc -n gitea get configmap demo-userinfo-gitea -o jsonpath='{.data.student_build_namespace}')"
IMAGE="image-registry.openshift-image-registry.svc:5000/${BUILD_NS}/spring-boot-lw-poc:latest"
oc -n "${BUILD_NS}" get istag spring-boot-lw-poc:latest \
-o jsonpath='{.image.dockerImageReference}{"\n"}'
ls ~/lab-trust 2>/dev/null || echo 'lab-trust empty (expected before your change)'
The block below verifies a different image with a key in a different directory. Using ~/example-not-lab-trust/demo.pub as the scored key fails the Check.
# Worked example ONLY — different directory and key name. Do not use as the Check.
mkdir -p ~/example-not-lab-trust
# COSIGN_PASSWORD="" cosign generate-key-pair (would write demo.pub here)
cosign verify --key ~/example-not-lab-trust/demo.pub \
--insecure-ignore-tlog \
image-registry.openshift-image-registry.svc:5000/example/not-your-app:latest
Your change
Generate the key pair in ~/lab-trust if cosign.key is not already there. export HOME=/tmp/lab-home exists so cosign login does not write a Docker config into the real home directory. The --key path and the ConfigMap --from-file path stay on /home/lab-user/lab-trust, because a tilde would follow the temporary HOME. --tlog-upload=false keeps this signature off the public Rekor log. That is the disconnected procedure: the signature travels with the digest, and verify uses --insecure-ignore-tlog on the next step.
ImagePolicy signedEmail cannot store a service-account URI. The public key is what 6.1 will render. Success is cosign.pub on disk, cosign sign exiting 0, and ConfigMap lab-cosign-pubkey in namespace tssc-admission holding that PEM. Put HOME back to /home/lab-user before the Check.
BUILD_NS="$(oc -n gitea get configmap demo-userinfo-gitea -o jsonpath='{.data.student_build_namespace}')"
IMAGE="image-registry.openshift-image-registry.svc:5000/${BUILD_NS}/spring-boot-lw-poc:latest"
mkdir -p ~/lab-trust
cd ~/lab-trust
if [[ ! -f cosign.key ]]; then
COSIGN_PASSWORD="" cosign generate-key-pair
fi
export HOME=/tmp/lab-home
mkdir -p "${HOME}"
cosign login -u unused -p "$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
image-registry.openshift-image-registry.svc:5000
COSIGN_PASSWORD="" cosign sign --key /home/lab-user/lab-trust/cosign.key \
--tlog-upload=false \
--allow-http-registry --allow-insecure-registry \
"${IMAGE}"
# ImagePolicy signedEmail cannot be a SA URI. Publish the public key for 6.1.
oc -n tssc-admission create configmap lab-cosign-pubkey \
--from-file=cosign.pub=/home/lab-user/lab-trust/cosign.pub \
--dry-run=client -o yaml | oc apply -f -
# Tilde follows HOME. Put the real home back before the Check (or use /home/lab-user/lab-trust).
export HOME=/home/lab-user
Check
Verify the same application tag with /home/lab-user/lab-trust/cosign.pub. --insecure-ignore-tlog matches the sign, which did not upload a transparency-log entry. Success is exit code 0 on your application digest. The 5.1 keyless signature has to remain verifiable. Stripping the Fulcio signature fails that later use.
BUILD_NS="$(oc -n gitea get configmap demo-userinfo-gitea -o jsonpath='{.data.student_build_namespace}')"
IMAGE="image-registry.openshift-image-registry.svc:5000/${BUILD_NS}/spring-boot-lw-poc:latest"
export HOME=/home/lab-user
LAB_TRUST=/home/lab-user/lab-trust
test -f "${LAB_TRUST}/cosign.pub"
test ! -f /home/lab-user/example-not-lab-trust/demo.pub || echo 'example path present (ok if unused)'
cosign login -u unused -p "$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
image-registry.openshift-image-registry.svc:5000
cosign verify --key "${LAB_TRUST}/cosign.pub" \
--insecure-ignore-tlog \
--allow-http-registry --allow-insecure-registry \
"${IMAGE}"
The Job also grades ConfigMap report-14-disconnected-verify key diode_honest. Set it to not-air-gap. Empty or REPLACE_ME fails even if cluster state is correct. Do not copy validate-docs.
oc -n lw-poc-validate edit configmap report-14-disconnected-verify
The scored Check is Job validate-14-disconnected-verify in lw-poc-validate. Direct nav URLs still work (honor system). Unlimited retries. There is no Solve.
oc -n lw-poc-validate delete job validate-14-disconnected-verify --ignore-not-found
TPL='job-14.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-14-disconnected-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.
The Validate Job reads ConfigMap tssc-admission/lab-cosign-pubkey and runs cosign verify --key on ImageStream tag spring-boot-lw-poc:latest in the build namespace. The PEM in that ConfigMap has to be the public key that signed the digest. REPLACE_ME fails the Check. Publishing ~/example-not-lab-trust/demo.pub fails it too. Task cosign-sign-keyless is the 5.1 Sign Check. Track 6 still opens if you skip this page. TUF root.json and the Fulcio and Rekor PEMs are a different exercise. Pack them in the simulated media drop when you want to say "mirrored TUF" about a keyless artifact. This page’s artifact verifies with cosign.pub.
Official documentation
-
Trusted Artifact Signer deployment guide (key-based
cosignalongside keyless) -
Disconnected transfer (mirrored TUF; a different exercise from this Check)
Key takeaways
-
Track 5 is the keyless signature and a key-based signature you created on the same digest.
-
cosign.pubis published totssc-admission/lab-cosign-pubkey. 6.1 admission uses it. -
The private key stays on the Showroom terminal.
-
The cluster stayed on the network. The procedure is what a disconnected verify looks like.
