-
Notifications
You must be signed in to change notification settings - Fork 140
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(STONEINTG-887): get base images from SBOM
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
1 parent
c08d539
commit ed40d5d
Showing
4 changed files
with
235 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
155
task/deprecated-image-check/0.4/deprecated-image-check.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |