7.2 Explain the remediation and inspect ACS results
You have retrieved the inventory for the production image. Now explain what the workshop advisory says about its Commons Lang version, store the supported documents in Trusted Profile Analyzer (TPA), and inspect an Advanced Cluster Security (ACS) policy check for that same image. Finish with a short evidence-based report in Showroom.
Why this control exists
An inventory tells you which component version is present. An advisory explains which versions are affected or fixed. Vulnerability Exploitability eXchange (VEX) statements connect a vulnerability assessment to a particular product. Here the product is a Maven group, artifact, and version (GAV): org.apache.commons:commons-lang3:3.14.0.rhlw-00001.
LW-DEMO-0002 is a seeded workshop advisory, not a real CVE. Its OSV record marks upstream 3.14.0 affected and names 3.14.0.rhlw-00001 as fixed. Its OpenVEX document states the same distinction for those exact package URLs. Your conclusion is limited to that sample and the version you observed in the promoted application’s inventory. It does not establish that the application has no other vulnerabilities.
ACS evaluates Central’s image policies. That result is separate from the sample advisory and from Track 6’s signature admission test. TPA ingest does not configure ACS policy or guarantee that ACS recognizes a seeded advisory.
Learning objectives
By the end of this module, you will be able to:
-
Compare the application inventory with the package and fixed version in OSV and OpenVEX.
-
Upload the library CycloneDX document and OSV advisory to their respective TPA endpoints.
-
Configure the pipeline to fail on a skipped ACS check and inspect a check of the promoted digest.
-
Write a report distinguishing sample remediation, ACS policy findings, and signature admission.
Prepare the evidence
Continue from module 7.1 with EVIDENCE, RHTPA_URL, and TOKEN set. If you opened a new terminal, set EVIDENCE="$HOME/lightwell-compliance-evidence" and repeat 7.1’s authentication commands. Refresh an expired token the same way. Keep all evidence outside the application Git clone.
The claim’s ConfigMap keys retain the prefix scored_vex_; they identify the sample documents. You use those coordinates directly without submitting a grading token. Leave the live CSAF importer disabled: Hummingbird and RHEL advisories concern the operating-system layer, while this exercise concerns a Java library.
|
In a seeded claim, |
Exercise
Download and compare the three library documents
Nexus serves a CycloneDX library inventory, an OpenVEX statement, and an OSV advisory for the selected dependency. Download all three so you can inspect their contents before uploading anything. Success means their package names and exact versions agree with the Commons Lang entry retrieved in 7.1.
CDX_URL="$(oc -n lightwell-repo get configmap lab-lightwell-repo -o jsonpath='{.data.scored_vex_maven_cdx}')"
VEX_URL="$(oc -n lightwell-repo get configmap lab-lightwell-repo -o jsonpath='{.data.scored_vex_maven_vex}')"
OSV_URL="$(oc -n lightwell-repo get configmap lab-lightwell-repo -o jsonpath='{.data.scored_vex_osv}')"
oc -n lightwell-repo get configmap lab-lightwell-repo \
-o jsonpath='advisory={.data.scored_vex_id}{"\n"}gav={.data.scored_vex_gav}{"\n"}'
curl -fsSL --max-time 60 "$CDX_URL" -o "$EVIDENCE/library.cdx.json"
curl -fsSL --max-time 60 "$VEX_URL" -o "$EVIDENCE/library.openvex.json"
curl -fsSL --max-time 60 "$OSV_URL" -o "$EVIDENCE/library.osv.json"
jq '{id, summary, affected}' "$EVIDENCE/library.osv.json"
jq '.statements[] | {vulnerability, products, status, action_statement}' "$EVIDENCE/library.openvex.json"
jq '{root:.metadata.component, components}' "$EVIDENCE/library.cdx.json"
jq '[.components[] | select(.name == "commons-lang3") |
{name, version, purl}]' "$EVIDENCE/tpa-app-sbom.json"
Read the fixed event for package org.apache.commons:commons-lang3 in the OSV record. Compare it with the fixed OpenVEX statement’s product URL and the application inventory. The upstream 3.14.0 entry should remain affected; the .rhlw-00001 version is the sample’s fix. If the application contains the upstream version, the report must say it is affected under this sample. Downloading remediation metadata does not change the image.
Store the supported documents in TPA
The library CycloneDX document belongs on /api/v3/sbom; OSV belongs on /api/v3/advisory. This workshop’s TPA does not accept the companion OpenVEX document on either endpoint. Retain it locally as evidence for your interpretation. The library inventory is an additional document, not a replacement for the promoted application’s SBOM.
curl -fkSs --max-time 60 -X POST -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/octet-stream' \
--data-binary @"$EVIDENCE/library.cdx.json" \
-o "$EVIDENCE/library-upload.json" -w 'Library SBOM HTTP %{http_code}\n' \
"${RHTPA_URL%/}/api/v3/sbom"
curl -fkSs --max-time 60 -X POST -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/octet-stream' \
--data-binary @"$EVIDENCE/library.osv.json" \
-o "$EVIDENCE/advisory-upload.json" -w 'OSV advisory HTTP %{http_code}\n' \
"${RHTPA_URL%/}/api/v3/advisory"
jq . "$EVIDENCE/library-upload.json" "$EVIDENCE/advisory-upload.json"
Expect successful HTTP responses and retain the returned identifiers. List stored advisories and find LW-DEMO-0002 in the response. Increment OFFSET by 50 and repeat if it is not on the first page; an empty items list is the end. A rejected upload, expired token, or absent record needs investigation before you claim that TPA stores the advisory.
OFFSET=0
curl -fkSs --max-time 30 -H "Authorization: Bearer $TOKEN" \
"${RHTPA_URL%/}/api/v3/advisory?limit=50&offset=$OFFSET" \
-o "$EVIDENCE/tpa-advisories.json"
jq . "$EVIDENCE/tpa-advisories.json"
Retrieve the library SBOM using its returned upload ID. If the response does not show an ID, list /api/v3/sbom as in 7.1 and locate Commons Lang at 3.14.0.rhlw-00001. Do not apply the application digest filter to this library document. Success is a downloaded library root whose GAV matches the Nexus file.
read -r -p 'Library TPA SBOM id: ' LIBRARY_SBOM_ID
LIBRARY_ID_ENCODED="$(printf '%s' "$LIBRARY_SBOM_ID" | jq -sRr @uri)"
curl -fkSs --max-time 30 -H "Authorization: Bearer $TOKEN" \
"${RHTPA_URL%/}/api/v3/sbom/$LIBRARY_ID_ENCODED/download" \
-o "$EVIDENCE/library-stored.cdx.json"
jq '{root:.metadata.component, vulnerabilities}' "$EVIDENCE/library-stored.cdx.json"
jq -e -s '.[0].metadata.component.purl == .[1].metadata.component.purl and
.[1].bomFormat == "CycloneDX"' \
"$EVIDENCE/library.cdx.json" "$EVIDENCE/library-stored.cdx.json"
You can also open TPA’s advisory and SBOM lists and inspect the identifiers there. Record the observed advisory and library SBOM IDs in your report. Ingestion and the sample’s fixed event support a scoped conclusion; they are not proof of an independent vulnerability assessment by TPA.
Make skipped ACS checks fail in future builds
Open /home/lab-user/lightwell-workspace/spring-boot-lw-poc/.tekton/pipeline.yaml. In the task named acs-image-check, set its fail-on-skipped parameter to the string "true". Preserve the task reference, image parameter, ordering, and other pipeline edits from earlier tracks. A missing token or unavailable CLI must not look like a successful check.
# Within tasks -> name: acs-image-check -> params:
- name: fail-on-skipped
value: "true"
Review, commit, push, and apply the pipeline definition. Success is a fetched remote file and a live Pipeline that both show true on this task. Applying the definition does not start a build.
cd /home/lab-user/lightwell-workspace/spring-boot-lw-poc
BUILD_NS="$(oc -n gitea get configmap lab-gitea -o jsonpath='{.data.student_build_namespace}')"
git diff --check
git diff -- .tekton/pipeline.yaml
git add .tekton/pipeline.yaml
git commit -m "Fail the ACS task when its check is skipped"
git push origin HEAD
git fetch origin "$(git branch --show-current)"
git show FETCH_HEAD:.tekton/pipeline.yaml
oc -n "$BUILD_NS" apply -f .tekton/pipeline.yaml
oc -n "$BUILD_NS" get pipeline
Read the Pipeline name from the manifest and inspect it below. Compare only the acs-image-check task’s parameters; another task’s true value is not evidence for this control.
read -r -p 'Pipeline name from .tekton/pipeline.yaml: ' PIPELINE
oc -n "$BUILD_NS" get pipeline "$PIPELINE" -o json |
jq '.spec.tasks[] | select(.name == "acs-image-check") | {name, taskRef, params}'
oc -n "$BUILD_NS" get secret rhacs-ci-secrets \
-o go-template='{{range $key, $value := .data}}{{$key}}{{"\n"}}{{end}}'
The Secret must contain keys rox-api-endpoint and rox-api-token. Do not print their values. Provisioning creates and distributes this Secret; if it is missing, ask the instructor to repair provisioning before running the check.
Check the promoted image without rebuilding it
Run the existing ACS Task directly against the immutable production reference saved in 7.1. This TaskRun evaluates the promoted image against the policies configured in ACS. A standalone TaskRun avoids replacing the image tag or SBOM with a new build. Together, the pipeline configuration and this TaskRun show how future builds enforce the check and how ACS evaluates the promoted image.
The cluster resolver runs the acs-image-check Task from the stackrox namespace, just as the pipeline does. Save the TaskRun name to find this run’s status and logs.
PROD_IMAGE="$(cat "$EVIDENCE/promoted-image.txt")"
printf '%s\n' "$PROD_IMAGE" | grep -Eq '@sha256:[0-9a-f]{64}$' || { echo 'Expected immutable image'; exit 1; }
cat > "$EVIDENCE/acs-taskrun.yaml" <<YAML
apiVersion: tekton.dev/v1
kind: TaskRun
metadata:
generateName: track7-acs-
spec:
serviceAccountName: pipeline
taskRef:
resolver: cluster
params:
- name: kind
value: task
- name: name
value: acs-image-check
- name: namespace
value: stackrox
params:
- name: image
value: "$PROD_IMAGE"
- name: fail-on-skipped
value: "true"
- name: rox-secret-name
value: rhacs-ci-secrets
YAML
ACS_RUN="$(oc -n "$BUILD_NS" create -f "$EVIDENCE/acs-taskrun.yaml" -o jsonpath='{.metadata.name}')"
printf '%s\n' "$ACS_RUN" | tee "$EVIDENCE/acs-taskrun-name.txt"
oc -n "$BUILD_NS" get taskrun "$ACS_RUN" -w
Press Ctrl-C once the TaskRun settles; this stops watching without cancelling it. Save the status and logs. If it has no pod yet, inspect its condition and events for resolution or scheduling errors before trying to read logs.
oc -n "$BUILD_NS" get taskrun "$ACS_RUN" -o json > "$EVIDENCE/acs-taskrun.json"
jq '{name:.metadata.name, params:.spec.params,
conditions:.status.conditions, results:.status.results, pod:.status.podName}' \
"$EVIDENCE/acs-taskrun.json"
ACS_POD="$(jq -er '.status.podName | select(length > 0)' "$EVIDENCE/acs-taskrun.json")"
oc -n "$BUILD_NS" logs "$ACS_POD" --all-containers=true > "$EVIDENCE/acs.log"
cat "$EVIDENCE/acs.log"
Interpret the result with its logs:
| Observation | Conclusion and next action |
|---|---|
|
ACS evaluated this image against the configured policies and accepted it. This does not establish that every possible vulnerability is absent. |
|
ACS evaluated and rejected the image. Record the policy findings; the check ran, but the image did not pass that policy. |
|
The check did not produce usable policy evidence. Resolve the error with the instructor and create a fresh TaskRun for the same digest. |
|
No completed policy assessment. Inspect conditions and logs; repair the prerequisite and repeat this task. With |
Write the blast-radius report
Blast radius means the set of artifacts affected by a finding. This exercise inspects one promoted image; it does not search every application in the organization. Write ~/lightwell-compliance-evidence/blast-radius.txt in your editor using the evidence you just inspected. Include:
-
The promoted image reference, production commit, and TPA application SBOM ID.
-
Sample advisory ID
LW-DEMO-0002, the observed Commons Lang GAV, and the matching OpenVEX product URL. -
The sample’s affected upstream version and fixed Lightwell version, with your observed status and reasoning. Say that remediation is via the exact Lightwell pin only when the inventory and advisory agree.
-
The stored OSV and library SBOM identifiers, and the fact that OpenVEX was inspected locally.
-
The ACS TaskRun name, checked image, result, and policy finding or operational error, including any unresolved issue.
-
The scope: one Java image and a workshop sample; OS-layer CSAF and Track 6’s signature admission are separate evidence.
You author a human-readable explanation rather than copying tokens into a cluster ConfigMap. A useful sentence links a concrete observation to its conclusion: “The retrieved application inventory contains version …; the sample’s fixed event and OpenVEX statement identify that same version, so …”. Fill the blanks from your output.
Review
Read the report beside the saved JSON and ACS logs. Check that every artifact identity agrees and that the report distinguishes a policy rejection from an execution error. A failed result alone does not prove a policy evaluation occurred. If the ACS attempt is unresolved, retain that limitation and complete the repair before claiming the exercise is finished.
cat "$EVIDENCE/blast-radius.txt"
jq '.metadata.component, [.components[] | select(.name == "commons-lang3")]' "$EVIDENCE/tpa-app-sbom.json"
jq '.id, .affected' "$EVIDENCE/library.osv.json"
jq '.status.results, .status.conditions' "$EVIDENCE/acs-taskrun.json"
oc -n trusted-profile-analyzer get configmap rhtpa-ingestion-info \
-o jsonpath='live_csaf_gate={.data.live_csaf_gate}{"\n"}'
unset TOKEN
Expect live_csaf_gate=false. Review the fetched and live pipeline parameters from the exercise as well. There is no validation Job or report token to submit. Completion means you can trace the report back to the stored inventory, advisory evidence, and a completed ACS policy assessment, while accurately recording any policy rejection.
|
Python uses an exact |
Key takeaways
-
Remediation claims require the exact installed version and matching advisory evidence.
-
TPA inventory, library advisory interpretation, ACS policy results, and signature admission answer different questions.
-
A useful compliance report states its evidence, scope, and unresolved findings.