5.2 Attest + Conforma
Overview
You copy the too-permissive Conforma seed and tighten your copy. Unsigned builder images must fail. The signed app digest from 5.1 must pass. You run that gate as Task conforma-policy in namespace lightwell-tasks. The Task is not in the seeded pipeline.
This is not SLSA L3. There is no Tekton Chains on this cluster and no cosign attest step. Leave skip-att-sig-check=true on the ConfigMap. Showroom ec is 0.7 (ec-rhel9:0.7). It has no --skip-att-sig-check, and --ignore-rekor breaks Fulcio timestamps on the pass path. The listing and Task ignore only builtin.attestation.signature_check in the report. Konflux Conforma maps to this Task. Chains and in-toto are a callout. Full table is Konflux mapping.
The seeded ConfigMap skips signature checks, uses identity .*, and sets CVE 999. Argo reverts edits to that object. Copy it to lw-poc-build and tighten the copy.
Why it matters
Policy must be able to fail. A pipeline that always passes is not a gate. You own the policy copy. Do not fetch a bundle from quay.io or github.com.
You copy and tighten the ConfigMap because Argo owns the seed. A wildcard identity would accept anything. Task order is after cosign-sign-keyless.
Lightwell Network and Clearinghouse Premier do not replace Conforma. Library VEX is Track 7. Conforma here gates image signature and identity. A Premier GAV inside an unsigned image still fails.
What does it solve
-
Policy that never fails
-
Unsigned work that still ships
-
Wildcard identity that accepts any signer
-
Editing the Argo-owned seed instead of a copy you own
Discover the seed (do not paste the example)
oc -n lightwell-tasks get task conforma-policy
oc -n lightwell-tasks get configmap conforma-policy \
-o jsonpath='{.data.skip-image-sig-check}{"\n"}{.data.certificate-identity-regexp}{"\n"}'
oc -n lightwell-tasks get configmap conforma-policy-docs \
-o jsonpath='{.data.example-pipeline-snippet\.yaml}'
Worked example (not the Check)
Named verify-enterprise-contract, runAfter: [clone] (before sign), fake example.invalid identity, skip left on, image docker.io/library/java:latest. Paste-identical copy fails.
# Worked example ONLY — wrong Task name, runs before sign, public image.
- name: verify-enterprise-contract
runAfter: [clone]
params:
- name: POLICY_CONFIGURATION
value: example.invalid/not-tightened
- name: IMAGES
value: docker.io/library/java:latest
Your change: copy, tighten, wire
-
Copy ConfigMap
conforma-policyfromlightwell-tasksintolw-poc-build. Do not edit the Argo-owned original.
BUILD_NS="$(oc -n gitea get configmap demo-userinfo-gitea -o jsonpath='{.data.student_build_namespace}')"
oc -n lightwell-tasks get configmap conforma-policy -o yaml \
| sed -e '/^ resourceVersion:/d' -e '/^ uid:/d' -e '/^ creationTimestamp:/d' \
-e "s/namespace: lightwell-tasks/namespace: ${BUILD_NS}/" \
| oc apply -f -
-
On the copy in
lw-poc-build, setskip-image-sig-checktofalse. Leaveskip-att-sig-checktrue(no Chains / nocosign atteston this claim). Setcertificate-identity-regexpto the same pipeline SA regexp you used in 5.1 (not a wildcard identity, not a Hummingbird placeholder). Set the OIDC issuer regexp tohttps://kubernetes.default.svc. Inpolicy.yaml/data.yaml, drop the catch-all exclude (the list that is a single asterisk). Do not add anexcludeforattestation_signature_check—ec0.7 builtins ignore that list. Lowerrestrict_max_cve_scorebelow 999, and pinallowed_registry_prefixesto the internal registry (image-registry.openshift-image-registry.svc). -
In Gitea
.tekton/pipeline.yaml, add Taskconforma-policy(cluster resolver,namespace: lightwell-tasks) withrunAfter: [cosign-sign-keyless]. Pointpolicy-namespace/policy-configmapat your copy inlw-poc-build, notlightwell-tasks. Passtuf-url: $(params.cosign-tuf-url)andrekor-url: $(params.cosign-rekor-url)(in-cluster*.trusted-artifact-signer.svcfrom 4.3 / 5.1 — not HTTPS Route hints). Commit, push, apply the Pipeline.
Check: fail on the builder; pass on the signed app
Fail path is the in-cluster ImageStream openjdk-21-builder you imported in 4.1 — it is not signed with the RHTAS pipeline SA. It can pull (internal registry is allowed). Pass path is the 5.1 app digest. Do not use docker.io/library/java:latest (worked example; hermetic egress also blocks it from the build namespace).
ec is on Showroom PATH (do not curl github.com). Initialize TUF and log in to the internal registry the same way as 5.1. Do not pass --ignore-rekor (Fulcio certs need Rekor timestamps) and do not pass --skip-att-sig-check (unknown on ec 0.7). --strict=false writes a report even when the attestation builtin fails; judge the files, not the exit code.
BUILD_NS="$(oc -n gitea get configmap demo-userinfo-gitea -o jsonpath='{.data.student_build_namespace}')"
TUF="$(oc -n trusted-artifact-signer get configmap demo-userinfo-rhtas -o jsonpath='{.data.tuf_url_hint}')"
REKOR="$(oc -n trusted-artifact-signer get configmap demo-userinfo-rhtas -o jsonpath='{.data.rekor_url_hint}')"
mkdir -p /tmp/ec /tmp/lab-home
export HOME=/tmp/lab-home
export SSL_CERT_FILE=/var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt
cosign initialize --mirror="${TUF}" --root="${TUF}/root.json"
cosign login -u unused -p "$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
image-registry.openshift-image-registry.svc:5000
oc -n "${BUILD_NS}" extract configmap/conforma-policy --to=/tmp/ec --confirm
FAIL_IMG="image-registry.openshift-image-registry.svc:5000/${BUILD_NS}/openjdk-21-builder:latest"
PASS_IMG="image-registry.openshift-image-registry.svc:5000/${BUILD_NS}/spring-boot-lw-poc:latest"
IDENTITY="$(tr -d '[:space:]' < /tmp/ec/certificate-identity-regexp)"
ISSUER="$(tr -d '[:space:]' < /tmp/ec/certificate-oidc-issuer-regexp)"
# Fail path: unsigned builder must report builtin.image.signature_check
ec validate image --image="${FAIL_IMG}" --policy=/tmp/ec/policy.yaml --strict=false \
--show-successes --info --output=text=/tmp/ec-fail.txt \
--certificate-identity-regexp="${IDENTITY}" \
--certificate-oidc-issuer-regexp="${ISSUER}" \
--rekor-url="${REKOR}" || true
grep '\[Violation\]' /tmp/ec-fail.txt | grep -q 'builtin.image.signature_check' \
|| { echo 'FAIL PATH UNEXPECTEDLY PASSED'; cat /tmp/ec-fail.txt; exit 1; }
# Pass path: ignore only the attestation builtin (no cosign attest on this claim)
ec validate image --image="${PASS_IMG}" --policy=/tmp/ec/policy.yaml --strict=false \
--show-successes --info --output=text=/tmp/ec-pass.txt \
--certificate-identity-regexp="${IDENTITY}" \
--certificate-oidc-issuer-regexp="${ISSUER}" \
--rekor-url="${REKOR}" || true
grep '\[Violation\]' /tmp/ec-pass.txt | grep -q 'builtin.image.signature_check' \
&& { echo 'PASS PATH: image signature still failing'; cat /tmp/ec-pass.txt; exit 1; }
leftover="$(grep '\[Violation\]' /tmp/ec-pass.txt | grep -v 'builtin.attestation.signature_check' || true)"
[[ -z "${leftover}" ]] || { echo "PASS PATH leftover: ${leftover}"; cat /tmp/ec-pass.txt; exit 1; }
oc -n "${BUILD_NS}" get pipeline spring-boot-lw-poc-build-sign -o yaml \
| grep -A30 'name: conforma-policy' | head -40
Pass when the builder report has builtin.image.signature_check as a [Violation], the signed app leftover [Violation] lines are empty after dropping builtin.attestation.signature_check, the live Pipeline includes conforma-policy after cosign-sign-keyless with in-cluster tuf-url / rekor-url, and policy-namespace is lw-poc-build.
The Job also grades ConfigMap report-13-attest-conforma key policy_owner. Set it to learner-copy. Empty or REPLACE_ME fails even if cluster state is correct. Do not copy validate-docs.
oc -n lw-poc-validate edit configmap report-13-attest-conforma
The scored Check is Job validate-13-attest-conforma 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-13-attest-conforma --ignore-not-found
TPL='job-13.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-13-attest-conforma
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.
Continue to 5.3 when you are ready. Track 6 still opens.
Official documentation
-
Trusted Artifact Signer deployment guide (Conforma /
ecagainst RHTAS signatures) -
Konflux mapping (Conforma → Task
conforma-policy)
Callout
SLSA L3 / Tekton Chains is a mapping sentence, not this Check. Full table is Konflux mapping.
Key takeaways
-
You own the Conforma policy copy. A passing default is not a gate.
-
Lightwell Network and Clearinghouse Premier do not skip this gate.
-
This lab is not SLSA L3. Leave
skip-att-sig-check=trueand ignorebuiltin.attestation.signature_checkin theecreport. Do not use--ignore-rekor.
cd ~/ocp5-rhacs-showroom
bash setup/lab-cleanup.sh --module tssc-13

