Skip to content

Commit

Permalink
feat(STONEINTG-887): get base images from SBOM
Browse files Browse the repository at this point in the history
Task `deprecated-image-check` will fetch data about base images also from
SBOM.

This requires an incompatible change, because users must update PLR
definition with the new parameters.

In future, konflux will stop provide BASE_IMAGES_DIGESTS via parameter,
thus this param is optional now (we cannot remove it yet)

Signed-off-by: Martin Basti <[email protected]>
  • Loading branch information
MartinBasti committed Apr 22, 2024
1 parent c08d539 commit ed40d5d
Show file tree
Hide file tree
Showing 4 changed files with 235 additions and 1 deletion.
5 changes: 4 additions & 1 deletion pipelines/template-build/template-build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,13 @@ spec:
values: ["false"]
taskRef:
name: deprecated-image-check
version: "0.3"
version: "0.4"
params:
- name: BASE_IMAGES_DIGESTS
value: $(tasks.build-container.results.BASE_IMAGES_DIGESTS)
workspaces:
- name: workspace
workspace: workspace
runAfter:
- build-container
- name: clair-scan
Expand Down
39 changes: 39 additions & 0 deletions task/deprecated-image-check/0.4/MIGRATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Migration from 0.3 to 0.4

New mandatory wokspace is required in version 0.4: `workspace`

## Action from users

Update files in Pull-Request created by RHTAP bot:
- Search for the task named `deprecated-base-image-check`
- Add the new workspace into yaml file


Example how the section should look like:

BEFORE:
```yaml
- name: deprecated-base-image-check
params:
- name: BASE_IMAGES_DIGESTS
value: $(tasks.build-container.results.BASE_IMAGES_DIGESTS)
taskRef:
params:
- name: name
value: deprecated-image-check
```
AFTER:
```yaml
- name: deprecated-base-image-check
params:
- name: BASE_IMAGES_DIGESTS
value: $(tasks.build-container.results.BASE_IMAGES_DIGESTS)
workspaces:
- name: workspace
workspace: workspace
taskRef:
params:
- name: name
value: deprecated-image-check
```
37 changes: 37 additions & 0 deletions task/deprecated-image-check/0.4/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# deprecated-image-check task

## Description

The deprecated-image-check checks for deprecated images that are no longer maintained and prone to security issues.
Image SBOM and BASE_IMAGES_DIGESTS param is used to determine which base images were used during build of the image.
It accomplishes this by verifying the data using Pyxis to query container image data and running Conftest using the
supplied conftest policy. Conftest is an open-source tool that provides a way to enforce policies written
in a high-level declarative language called Rego.

## Params

| name | description |
|---------------------|-------------------------------------------------|
| POLICY_DIR | Path to directory containing Conftest policies. |
| POLICY_NAMESPACE | Namespace for Conftest policy. |
| BASE_IMAGES_DIGESTS | (Optional) Digests of base build images. |
| IMAGE_DIGEST | Image digest. |
| IMAGE_URL | Fully qualified image name. |

## Results

| name | description |
|-------------------|-------------------------------------------|
| PYXIS_HTTP_CODE | HTTP code returned by Pyxis API endpoint. |
| TEST_OUTPUT | Tekton task test output. |

## Source repository for image

https://github.com/redhat-appstudio/hacbs-test

## Additional links

https://catalog.redhat.com/api/containers/docs/
https://www.redhat.com/en/blog/gathering-security-data-container-images-using-pyxis-api
https://github.com/open-policy-agent/conftest
https://redhat-appstudio.github.io/docs.stonesoup.io/Documentation/main/concepts/testing_applications/sanity_tests.html#_deprecated_image_checks
155 changes: 155 additions & 0 deletions task/deprecated-image-check/0.4/deprecated-image-check.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
apiVersion: tekton.dev/v1
kind: Task
metadata:
labels:
app.kubernetes.io/version: "0.3"
annotations:
tekton.dev/pipelines.minVersion: "0.12.1"
tekton.dev/tags: "appstudio, hacbs"
name: deprecated-image-check
spec:
description: >-
Identifies the unmaintained and potentially insecure deprecated base images.
Pyxis API collects metadata from image repository, and Conftest applies supplied policy to identify the deprecated images using that metadata.
params:
- name: POLICY_DIR
description: Path to directory containing Conftest policies.
default: "/project/repository/"
- name: POLICY_NAMESPACE
description: Namespace for Conftest policy.
default: "required_checks"
- name: BASE_IMAGES_DIGESTS
description: Digests of base build images.
default: ""

results:
- name: PYXIS_HTTP_CODE
description: HTTP code returned by Pyxis API endpoint.
- description: Tekton task test output.
name: TEST_OUTPUT

steps:
- name: check-images
image: quay.io/redhat-appstudio/hacbs-test:v1.4.0@sha256:54d49b37c9a2e280d42961a57e4f7a16c171d6b065559f1329b548db85300bea
# per https://kubernetes.io/docs/concepts/containers/images/#imagepullpolicy-defaulting
# the cluster will set imagePullPolicy to IfNotPresent
# also per direction from Ralph Bean, we want to use image digest based tags to use a cue to automation like dependabot or renovatebot to periodially submit pull requests that update the digest as new images are released.
env:
- name: POLICY_DIR
value: $(params.POLICY_DIR)
- name: POLICY_NAMESPACE
value: $(params.POLICY_NAMESPACE)
- name: BASE_IMAGES_DIGESTS
value: $(params.BASE_IMAGES_DIGESTS)
script: |
#!/usr/bin/env bash
set -euo pipefail
source /utils.sh
trap 'handle_error $(results.TEST_OUTPUT.path)' EXIT
IMAGES_TO_BE_PROCESSED_PATH="/tmp/images_to_be_processed.txt"
success_counter=0
failure_counter=0
error_counter=0
warnings_counter=0
# Get base images from SBOM
SBOM_PATH="$(workspaces.workspace.path)/sbom-cyclonedx.json"
if [ ! -f "${SBOM_PATH}" ];
then
echo "[ERROR] SBOM not found at ${SBOM_PATH}"
note="Task $(context.task.name) failed: SBOM not found in the workspace."
ERROR_OUTPUT=$(make_result_json -r ERROR -n "$POLICY_NAMESPACE" -t "$note")
echo "${ERROR_OUTPUT}" | tee $(results.TEST_OUTPUT.path)
exit 0
fi
cat "${SBOM_PATH}" | jq -r '.formulation? // empty | .[] | .components? // empty | .[] | select(any((.properties // empty)[]; .name | test("^konflux:container:is_(base|builder)_image"))) | .name' > ${IMAGES_TO_BE_PROCESSED_PATH}
echo "Detected base images from SBOM:"
cat "${IMAGES_TO_BE_PROCESSED_PATH}"
echo ""
if [ -n "${BASE_IMAGES_DIGESTS}" ];
then
echo "Base images pased by param BASE_IMAGES_DIGESTS: $BASE_IMAGES_DIGESTS"
# Get images from the parameter
for IMAGE_WITH_TAG in $(echo -n "$BASE_IMAGES_DIGESTS" | sed 's/\\n/\'$'\n''/g' );
do
echo $IMAGE_WITH_TAG | cut -d ":" -f1 >> ${IMAGES_TO_BE_PROCESSED_PATH}
done
fi
# we want to remove duplicated entries
BASE_IMAGES=$(sort -u "${IMAGES_TO_BE_PROCESSED_PATH}")
echo "Images to be checked:"
echo "$BASE_IMAGES"
echo ""
for BASE_IMAGE in ${BASE_IMAGES};
do
IFS=:'/' read -r IMAGE_REGISTRY IMAGE_REPOSITORY<<< $BASE_IMAGE
# Red Hat Catalog hack: registry.redhat.io must be queried as registry.access.redhat.com in Red Hat catalog
IMAGE_REGISTRY_CATALOG=$(echo "${IMAGE_REGISTRY}" | sed 's/^registry.redhat.io$/registry.access.redhat.com/')
export IMAGE_REPO_PATH=/tmp/${IMAGE_REPOSITORY}
mkdir -p ${IMAGE_REPO_PATH}
echo "Querying Red Hat Catalog for $BASE_IMAGE."
http_code=$(curl -s -o ${IMAGE_REPO_PATH}/repository_data.json -w '%{http_code}' "https://catalog.redhat.com/api/containers/v1/repositories/registry/${IMAGE_REGISTRY_CATALOG}/repository/${IMAGE_REPOSITORY}")
if [ "$http_code" == "200" ];
then
echo "Running conftest using $POLICY_DIR policy, $POLICY_NAMESPACE namespace."
/usr/bin/conftest test --no-fail ${IMAGE_REPO_PATH}/repository_data.json \
--policy $POLICY_DIR --namespace $POLICY_NAMESPACE \
--output=json | tee ${IMAGE_REPO_PATH}/deprecated_image_check_output.json
failures_num=$(jq -r '.[].failures|length' ${IMAGE_REPO_PATH}/deprecated_image_check_output.json)
if [[ "${failures_num}" -gt 0 ]]; then
echo "[FAILURE] Image ${IMAGE_REGISTRY}/${IMAGE_REPOSITORY} has been deprecated"
fi
failure_counter=$((failure_counter+failures_num))
successes_num=$(jq -r '.[].successes' ${IMAGE_REPO_PATH}/deprecated_image_check_output.json)
if [[ "${successes_num}" -gt 0 ]]; then
echo "[SUCCESS] Image ${IMAGE_REGISTRY}/${IMAGE_REPOSITORY} is valid"
fi
success_counter=$((success_counter+successes_num))
elif [ "$http_code" == "404" ];
then
echo "[WARNING] Registry/image ${IMAGE_REGISTRY}/${IMAGE_REPOSITORY} not found in Red Hat Catalog. Task cannot provide results if image is deprecated."
warnings_counter=$((warnings_counter+1))
else
echo "[ERROR] Unexpected error (HTTP code: ${http_code}) occurred for registry/image ${IMAGE_REGISTRY}/${IMAGE_REPOSITORY}."
error_counter=$((error_counter+1))
fi
done
note="Task $(context.task.name) failed: Command conftest failed. For details, check Tekton task log."
ERROR_OUTPUT=$(make_result_json -r ERROR -n "$POLICY_NAMESPACE" -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"
elif [[ "${success_counter}" -eq 0 ]]; then
# when all counters are 0, there are no base images to check
note="Task $(context.task.name) success: No base images to check."
RES="SUCCESS"
else
RES="SUCCESS"
fi
TEST_OUTPUT=$(make_result_json \
-r "${RES}" -n "$POLICY_NAMESPACE" \
-s "${success_counter}" -f "${failure_counter}" -w "${warnings_counter}" -t "$note")
fi
echo "${TEST_OUTPUT:-${ERROR_OUTPUT}}" | tee $(results.TEST_OUTPUT.path)
workspaces:
- name: workspace
description: Workspace containing the build artifacts.

0 comments on commit ed40d5d

Please sign in to comment.