Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Push SBOM to TPA in gitops PR pipeline #975

Merged
merged 5 commits into from
May 22, 2024

Conversation

chmeliik
Copy link
Contributor

@chmeliik chmeliik commented Apr 30, 2024

When a PR in a gitops repo updates the stage or prod image:

  • download the attestation for that image using cosign verify-attestation
  • find the SBOM_BLOB_URL in the attestation
  • download the blob from the registry
  • if the blob is a CycloneDX JSON SBOM:
    • convert it to the CycloneDX version supported by the Trustification instance
    • upload it to TPA with id=sha256:<pre-conversion-digest>

This is split into two separate tasks

download-sbom-from-url-in-attestation

Gets an array of images, downloads their attestations, downloads the SBOM blobs found in those attestations

upload-sbom-to-trustification

Gets a directory of SBOMs, uploads them to Trustification.
Requires the trustification-secret (see the task README).


}

download_blob() {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should absolutely not be done in Bash. We should use oras blob fetch. But we would have to productize oras.

Comment on lines 247 to 264
attestation_file="$WORKDIR/$image/attestation.json"
sbom_blob_url=$(jq -r \
'.payload | @base64d | fromjson | .. | select(.name? == "SBOM_BLOB_URL").value' \
"$attestation_file"
)
mkdir -p "$SBOMS_DIR/$image"
download_blob "$sbom_blob_url" "$SBOMS_DIR/$image/sbom.json"
Copy link
Contributor Author

@chmeliik chmeliik Apr 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively, we could just get the SBOM with cosign download sbom. But that's even less secure.

Given a container image:

  • With the "find SBOM_BLOB_URL in the attestation" solution:
    • The pipeline can verify that the SBOM_BLOB_URL was returned by the Tekton pipeline that built the image. You still have to trust that the build pipeline created a real SBOM and returned the correct url.
  • With the cosign solution:
    • The pipeline takes the image digest and downloads the sha256-$digest.sbom tag from the image repository. You have to trust (everything above and) that nobody tampered with the tag between the build time and the SBOM download time.

- bombastic_api_url: URL of the BOMbastic api host (e.g. https://sbom.trustification.dev)
- oidc_issuer_url: URL of the OIDC token issuer (e.g. https://sso.trustification.dev/realms/chicken)
- oidc_client_id: OIDC client ID
- oidc_client_secret: OIDC client secret
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where do RHTAP customers get the client ID and secret? Do they all use the single "walker" client created at install time?

Comment on lines 202 to 224
echo "Getting OIDC token from $token_endpoint"
token_response="$(
curl "${curl_opts[@]}" \
-H "authorization: Basic $basic_auth" \
-d "grant_type=client_credentials" \
"$token_endpoint"
)"
# https://www.rfc-editor.org/rfc/rfc6749.html#section-5.1
access_token="$(jq -r .access_token <<< "$token_response")"
token_type="$(jq -r .token_type <<< "$token_response")"
expires_in="$(jq -r ".expires_in // empty" <<< "$token_response")"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This task is also too complex for Bash. But as far as I know, there are no plans to productize the CLI that should do this.

Comment on lines +94 to +109
if ! jq empty "$filepath" 2>/dev/null; then
echo "$file_relpath: not JSON"
continue
fi

if ! jq -e '.bomFormat == "CycloneDX"' "$filepath" >/dev/null; then
echo "$file_relpath: not a CycloneDX SBOM"
continue
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Supports only CycloneDX JSONs, I hope that's good enough.

@chmeliik
Copy link
Contributor Author

PTAL @mmorhun @jduimovich. I don't like this at all. But it does work if we must have it (some fixes and a lot of polish needed).

Tested in https://github.com/acmiel-rhtap/rhtap-idk-gitops/pull/2 (failed on EC validation because I didn't set up ACS)

@chmeliik
Copy link
Contributor Author

One more thing - there's probably nothing that would tie the SBOM uploaded to TPA with the user's container image or with their idea of a "product"

image

A solution could be to document that if user's want their SBOMs to be possible to find, they need to commit Syft configuration into their repo to give their product a name and version

source:
  name: foo
  version: "1.0"

Copy link
Collaborator

@mmorhun mmorhun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just put a few of my thought, they are not a request to rework something.

"$image" > "$WORKDIR/$image/attestation.json"
done

- name: download-sboms
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should have some functionality in ec itself to download certain artifacts associated with an image.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would certainly make this task less awful. If you feel that downloading SBOMs based on the SBOM_BLOB_URL in the attestation makes sense for the EC CLI, I wouldn't mind that.

retry_max_time="$expires_in"
fi

sbom_id="$(basename -s .json "$sbom_path")"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you want something more unique here. Maybe uuidgen?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The id is the sha256 checksum of the SBOM content (before downgrading its CycloneDX version). The idea is that this avoids duplication when the same SBOM is uploaded multiple times.

(It's not very clear from the code though, so I'll add a comment to clarify).

fi
done

- name: upload-sboms
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been playing around with uploading to TPA recently but from GitLab. I'll share what I did here in case it's useful to you: https://gitlab.com/lucarval/sign-attest-poc/-/blob/c24001db921c8c2bbb12aeb1c33ae1d910f20504/.gitlab-ci.yml#L108-140

@chmeliik chmeliik force-pushed the push-to-tpa branch 2 times, most recently from 6b5c2af to 2333a40 Compare May 6, 2024 15:40
@chmeliik chmeliik marked this pull request as ready for review May 6, 2024 15:40
@chmeliik
Copy link
Contributor Author

chmeliik commented May 6, 2024

I've cleaned this up as much as I could.

Managed to get rid of the jq task, so now the pipeline looks like this:

       gather-images -- download-sboms -- upload-sboms
      /
clone
      \
       gather-images -- verify-enterprise-contract

(the gather-images for SBOMS is called with different params to gather only the stage and prod images)

@chmeliik
Copy link
Contributor Author

chmeliik commented May 9, 2024

Apart from the temp commit with the create-trustification-secret.sh script, this is about as clean as it's going to be. PTAL @mmorhun @jduimovich

Copy link
Collaborator

@mmorhun mmorhun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job!

@chmeliik chmeliik changed the title PoC: Push SBOM to TPA in gitops PR pipeline Push SBOM to TPA in gitops PR pipeline May 13, 2024
@chmeliik chmeliik force-pushed the push-to-tpa branch 2 times, most recently from 9eae59f to 24edb32 Compare May 13, 2024 10:59
Copy link

sonarcloud bot commented May 13, 2024

Quality Gate Passed Quality Gate passed

Issues
0 New issues
0 Accepted issues

Measures
0 Security Hotspots
No data about Coverage
0.0% Duplication on New Code

See analysis details on SonarCloud

@chmeliik
Copy link
Contributor Author

chmeliik commented May 13, 2024

Script for creating tpa-secret (dropped the commit that adds it, but still useful for testing):

#!/bin/bash
set -o errexit -o nounset -o pipefail

secret_name=${secret_name:-'tpa-secret'}
private_env_path=${private_env_path:-'../rhtap-installer/private.env'}
tpa_namespace=${tpa_namespace:-'rhtap'}

source "$private_env_path"

oc create secret generic "$secret_name" \
    --from-literal bombastic_api_url="https://$(oc -n "$tpa_namespace" get route --selector app.kubernetes.io/name=bombastic-api -o jsonpath='{.items[].spec.host}')" \
    --from-literal oidc_issuer_url="https://$(oc -n "$tpa_namespace" get route --selector app.kubernetes.io/name=keycloak -o jsonpath='{.items[].spec.host}')/realms/chicken" \
    --from-literal oidc_client_id=walker \
    --from-literal oidc_client_secret="$TPA__OIDC__WALKER_CLIENT_SECRET" \
    --from-literal supported_cyclonedx_version=1.4

@chmeliik chmeliik added this pull request to the merge queue May 20, 2024
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks May 20, 2024
@chmeliik chmeliik added this pull request to the merge queue May 20, 2024
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks May 20, 2024
Add ENVIRONMENTS param, defaults to ["development", "stage", "prod"].

Signed-off-by: Adam Cmiel <acmiel@redhat.com>
STONEBLD-2335

The task accepts the output of 'gather-deploy-images' as input. It
downloads the attestation for each image, using the same technique as
the EC task to verify them. The task extracts the SBOM_BLOB_URL from the
attestation and downloads the SBOM from the url.

The vast majority of the download_blob code could be replaced with
'oras blob fetch'. But oras is not productized for use in RHTAP.

Signed-off-by: Adam Cmiel <acmiel@redhat.com>
STONEBLD-2335

Takes a workspace containing CycloneDX JSON SBOMs, uploads them to
Trustification using the BOMBastic API.

See the task description for more details.

Signed-off-by: Adam Cmiel <acmiel@redhat.com>
STONEBLD-2335

When a PR updates the image in the stage or prod deployment, download
the SBOM for that image and upload it to Trustification.

Signed-off-by: Adam Cmiel <acmiel@redhat.com>
When FAIL_IF_TRUSTIFICATION_NOT_CONFIGURED=false and the required
Trustification configuration is missing, the task will exit with
success.

Signed-off-by: Adam Cmiel <acmiel@redhat.com>
@chmeliik
Copy link
Contributor Author

/retest

@chmeliik chmeliik added this pull request to the merge queue May 22, 2024
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks May 22, 2024
@chmeliik chmeliik added this pull request to the merge queue May 22, 2024
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks May 22, 2024
@chmeliik chmeliik added this pull request to the merge queue May 22, 2024
Merged via the queue into konflux-ci:main with commit c5b4c77 May 22, 2024
2 checks passed
@chmeliik chmeliik deleted the push-to-tpa branch May 28, 2024 11:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants