Skip to content

Commit

Permalink
feat: add fips-operator-check task
Browse files Browse the repository at this point in the history
Refers to CVP-4333. This task uses the check-payload tool to verify if
an operator bundle image is FIPS compliant.It utilizes Tekton stepAction
because the code will be reused for checking FBC fragments in the
fbc-validation check.

Signed-off-by: Yashvardhan Nanavati <[email protected]>
  • Loading branch information
yashvardhannanavati committed Dec 6, 2024
1 parent 12bbd68 commit c473776
Show file tree
Hide file tree
Showing 6 changed files with 300 additions and 0 deletions.
13 changes: 13 additions & 0 deletions stepactions/fips-operator-check-step-action/0.1/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
## fips-operator-check-step-action

This stepAction scans relatedImages of operator bundle image builds for FIPS compliance using the check-payload tool. The relatedImages are expected to be in a file located at `/tekton/home/unique_related_images.txt`

## Results:

| name | description |
|--------------------|--------------------------------------|
| TEST_OUTPUT | Tekton task test output. |


## Additional links:
https://github.com/openshift/check-payload
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
---
apiVersion: tekton.dev/v1beta1
kind: StepAction
metadata:
labels:
app.kubernetes.io/version: "0.1"
annotations:
tekton.dev/pipelines.minVersion: "0.12.1"
tekton.dev/tags: "konflux"
name: fips-operator-check-step-action
spec:
description: >-
This stepAction scans relatedImages of operator bundle image builds for FIPS compliance using the check-payload tool.
results:
- name: TEST_OUTPUT
description: Tekton task test output.
image: quay.io/redhat-appstudio/konflux-test:v1.4.9@sha256:eee855e60b437d9a55a30e63f2eb7f95d9fd6d3b111c32cac8730c9b7a071394
securityContext:
capabilities:
add:
- SETFCAP
script: |
#!/usr/bin/env bash
set -euo pipefail
# shellcheck source=/dev/null
. /utils.sh
success_counter=0
warnings_counter=0
error_counter=0
failure_counter=0
if [ ! -e "/tekton/home/unique_related_images.txt" ]; then
echo "No relatedImages to process"
exit 0
fi
related_images=$(cat /tekton/home/unique_related_images.txt)
echo "Related images are : ${related_images}"
for related_image in ${related_images}; do
echo "Processing related image : ${related_image}"
image_labels=$(skopeo inspect docker://"${related_image}" --config | jq -r '.config.Labels // {} | to_entries[] | "\(.key)=\(.value)"')
component_label=$(echo "${image_labels}" | grep 'com.redhat.component=' | cut -d= -f2 || true)
echo "Component label is ${component_label}"
if [ -z "${component_label}" ]; then
echo "Error: Could not get com.redhat.component label for ${related_image}"
error_counter=$((error_counter + 1))
continue
fi
# Convert image to OCI format since umoci can only handle the OCI format
if ! skopeo copy --remove-signatures "docker://${related_image}" "oci:///tekton/home/${component_label}:latest"; then
echo "Error: Could not convert image ${related_image} to OCI format"
error_counter=$((error_counter + 1))
continue
fi
# Unpack OCI image
if ! umoci raw unpack --rootless \
--image "/tekton/home/${component_label}:latest" \
"/tekton/home/unpacked-${component_label}"; then
echo "Error: Could not unpack OCI image ${related_image}"
error_counter=$((error_counter + 1))
continue
fi
echo "Now RUNNING SCAN ON THE IMAGE ${related_image}"
# Run check-payload on the unpacked image
# The check-payload command fails with exit 1 when the scan for an image is unsuccessful
# or when the image is not FIPS compliant. Hence, count those as failures and not errors
if ! check-payload scan local \
--path="/tekton/home/unpacked-${component_label}" \
--components="${component_label}" \
--output-format=csv \
--output-file="/tekton/home/report-${component_label}.csv"; then
echo "check-payload scan failed for ${related_image}"
failure_counter=$((failure_counter + 1))
continue
fi
if [ -f "/tekton/home/report-${component_label}.csv" ]; then
if grep -q -- "---- Successful run" "/tekton/home/report-${component_label}.csv"; then
echo "check-payload scan was successful for ${related_image}"
success_counter=$((success_counter + 1))
elif grep -q -- "---- Successful run with warnings" "/tekton/home/report-${component_label}.csv"; then
echo "check-payload scan was successful with warnings for ${related_image}"
warnings_counter=$((warnings_counter + 1))
fi
fi
done
note="Task $(context.task.name) failed: Some images could not be scanned. For details, check Tekton task log."
ERROR_OUTPUT=$(make_result_json -r ERROR -t "$note")
note="Task $(context.task.name) completed: Check result for task result."
if [[ "$error_counter" == 0 ]];
then
if [[ "${failure_counter}" -gt 0 ]]; then
RES="FAILURE"
elif [[ "${warnings_counter}" -gt 0 ]]; then
RES="WARNING"
else
RES="SUCCESS"
fi
TEST_OUTPUT=$(make_result_json \
-r "${RES}" \
-s "${success_counter}" -f "${failure_counter}" -w "${warnings_counter}" -t "$note")
fi
echo "${TEST_OUTPUT:-${ERROR_OUTPUT}}" | tee "$(step.results.TEST_OUTPUT.path)"
6 changes: 6 additions & 0 deletions stepactions/fips-operator-check-step-action/OWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
approvers:
- integration-team
- yashvardhannanavati
reviewers:
- integration-team
- yashvardhannanavati
25 changes: 25 additions & 0 deletions task/fips-operator-bundle-check/0.1/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# fips-operator-bundle-check task

## Description:
The fips-operator-bundle-check task uses the check-payload tool to verify if an operator bundle image is FIPS compliant.
It only scans operator bundle images which either claim to be FIPS compliant by setting the `features.operators.openshift.io/fips-compliant`
label to `"true"` on the bundle image or require one of `OpenShift Kubernetes Engine, OpenShift Platform Plus or OpenShift Container Platform`
subscriptions to run the operator on an Openshift cluster.

## Params:

| name | description | default |
|--------------------------|------------------------------------------------------------------------|---------------|
| image-digest | Image digest to scan. | None |
| image-url | Image URL. | None |

## Results:

| name | description |
|--------------------|------------------------------|
| TEST_OUTPUT | Tekton task test output. |
| IMAGES_PROCESSED | Images processed in the task.|


## Additional links:
https://github.com/openshift/check-payload
136 changes: 136 additions & 0 deletions task/fips-operator-bundle-check/0.1/fips-operator-bundle-check.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
---
apiVersion: tekton.dev/v1
kind: Task
metadata:
labels:
app.kubernetes.io/version: "0.1"
annotations:
tekton.dev/pipelines.minVersion: "0.12.1"
tekton.dev/tags: "konflux"
name: fips-operator-bundle-check
spec:
description: >-
Checks operator bundle image builds for FIPS compliance using the check-payload tool.
params:
- name: image-digest
description: Image digest to scan.
- name: image-url
description: Image URL.
results:
- name: TEST_OUTPUT
description: Tekton task test output.
value: $(steps.fips-operator-check-step-action.results.TEST_OUTPUT)
- name: IMAGES_PROCESSED
description: Images processed in the task.
steps:
- name: get-unique-related-images
image: quay.io/redhat-appstudio/konflux-test:v1.4.9@sha256:eee855e60b437d9a55a30e63f2eb7f95d9fd6d3b111c32cac8730c9b7a071394
computeResources:
limits:
memory: 512Mi
cpu: 200m
requests:
memory: 256Mi
cpu: 100m
env:
- name: IMAGE_URL
value: $(params.image-url)
- name: IMAGE_DIGEST
value: $(params.image-digest)
securityContext:
capabilities:
add:
- SETFCAP
script: |
#!/usr/bin/env bash
set -euo pipefail
# shellcheck source=/dev/null
. /utils.sh
image_without_tag=$(echo -n "${IMAGE_URL}" | sed "s/\(.*\):.*/\1/")
# strip new-line escape symbol from parameter and save it to variable
image_and_digest="${image_without_tag}@${IMAGE_DIGEST}"
image_and_digest_labels=$(skopeo inspect docker://"${image_and_digest}" --config | jq -r '.config.Labels // {} | to_entries[] | "\(.key)=\(.value)"')
if ! echo "${image_and_digest_labels}" | grep -q 'operators.operatorframework.io.bundle.mediatype.v1='; then
echo "The image $image_and_digest is not an operator bundle. Skipping FIPS static check..."
exit 0
fi
# Run the FIPS check only if the bundle is part of the Openshift Subscription or has the fips label set
image_and_digest_render_out=$(opm render "$image_and_digest")
subscription_label=$(echo "${image_and_digest_render_out}" | jq -r '.properties[] | select(.value.annotations["operators.openshift.io/valid-subscription"] != null) | (.value.annotations["operators.openshift.io/valid-subscription"] | fromjson)[]')
fips_label=$(echo "${image_and_digest_labels}" | grep 'features.operators.openshift.io/fips-compliant=' | cut -d= -f2 || true)
if ! echo "${subscription_label}" | grep -e "OpenShift Kubernetes Engine" -e "OpenShift Container Platform" -e "OpenShift Platform Plus"; then
echo "OpenShift Kubernetes Engine, OpenShift Platform Plus or OpenShift Container Platform are not present in operators.openshift.io/valid-subscription."
echo "Subscription labels are : $subscription_label"
if [ -z "${fips_label}" ] || [ "${fips_label}" != "true" ]; then
echo "The label features.operators.openshift.io/fips-compliant is also not set to true. Skipping the FIPS static check..."
exit 0
else
echo "The label features.operators.openshift.io/fips-compliant is set to true. Running the FIPS static check..."
fi
else
echo "OpenShift Kubernetes Engine, OpenShift Platform Plus or OpenShift Container Platform are present in operators.openshift.io/valid-subscription. Running the FIPS static check..."
fi
unique_related_images=()
digests_processed=()
images_processed_template='{"image": {"pullspec": "'"$IMAGE_URL"'", "digests": [%s]}}'
echo "Inspecting raw image manifest $image_and_digest."
# Get the arch and image manifests by inspecting the image. This is mainly for identifying image indexes
image_manifests=$(get_image_manifests -i "${image_and_digest}")
echo "Image manifests are $image_manifests"
declare -A seen_related_images
# Extract relatedImages from the bundle image
while read -r _ arch_sha; do
digests_processed+=("\"$arch_sha\"")
bundle_render_out=$(opm render "$image_without_tag@$arch_sha")
manifest_related_images=$(echo "${bundle_render_out}" | jq -r '.relatedImages[]?.image')
if [ -n "$manifest_related_images" ]; then
for img in $manifest_related_images; do
if [ -z "${seen_related_images["$img"]:-}" ]; then
unique_related_images+=("$img")
seen_related_images["$img"]=1
fi
done
fi
done < <(echo "$image_manifests" | jq -r 'to_entries[] | "\(.key) \(.value)"')
echo "Unique related images: ${unique_related_images[*]}"
echo "${unique_related_images[*]}" > /tekton/home/unique_related_images.txt
# If the image is an Image Index, also add the Image Index digest to the list.
if [[ "${digests_processed[*]}" != *"$IMAGE_DIGEST"* ]]; then
digests_processed+=("\"$IMAGE_DIGEST\"")
fi
digests_processed_string=$(IFS=,; echo "${digests_processed[*]}")
echo "${images_processed_template/\[%s]/[$digests_processed_string]}" > /tekton/home/images_processed.txt
- name: fips-operator-check-step-action
computeResources:
limits:
memory: 512Mi
cpu: 200m
requests:
memory: 256Mi
cpu: 100m
ref:
name: fips-operator-check-step-action

- name: parse-images-processed-result
image: quay.io/redhat-appstudio/konflux-test:v1.4.9@sha256:eee855e60b437d9a55a30e63f2eb7f95d9fd6d3b111c32cac8730c9b7a071394
script: |
#!/usr/bin/env bash
set -euo pipefail
if [ -e "/tekton/home/images_processed.txt" ]; then
tee "$(results.IMAGES_PROCESSED.path)" < /tekton/home/images_processed.txt
else
echo "Task was skipped. Exiting"
exit 0
fi
6 changes: 6 additions & 0 deletions task/fips-operator-bundle-check/OWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
approvers:
- integration-team
- yashvardhannanavati
reviewers:
- integration-team
- yashvardhannanavati

0 comments on commit c473776

Please sign in to comment.