From fb499e9a43da5efc530fb94a65858af5a02f0f53 Mon Sep 17 00:00:00 2001 From: Simon Baird Date: Thu, 21 Mar 2024 17:46:08 -0400 Subject: [PATCH 1/3] Small refactor in acceptance test sigstore rego This is helpful for some experiments I'm working on, and seems like a good enough tidy/refactor anyhow. --- acceptance/examples/sigstore.rego | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/acceptance/examples/sigstore.rego b/acceptance/examples/sigstore.rego index 559bb9c02..a3c32d451 100644 --- a/acceptance/examples/sigstore.rego +++ b/acceptance/examples/sigstore.rego @@ -16,50 +16,50 @@ _errors contains error if { } _errors contains error if { - not data.config.default_sigstore_opts + not _sigstore_opts error := "default sigstore options not set" } _errors contains error if { - info := ec.sigstore.verify_image(_image_ref, data.config.default_sigstore_opts) + info := ec.sigstore.verify_image(_image_ref, _sigstore_opts) some raw_error in info.errors error := sprintf("image signature verification failed: %s", [raw_error]) } _errors contains error if { - info := ec.sigstore.verify_image(_image_ref, data.config.default_sigstore_opts) + info := ec.sigstore.verify_image(_image_ref, _sigstore_opts) count(info.signatures) == 0 error := "verification successful, but no image signatures found" } _errors contains error if { - info := ec.sigstore.verify_image(_image_ref, data.config.default_sigstore_opts) + info := ec.sigstore.verify_image(_image_ref, _sigstore_opts) some sig in info.signatures not valid_signature(sig) error := sprintf("not a valid image signature: %s", [sig]) } _errors contains error if { - info := ec.sigstore.verify_attestation(_image_ref, data.config.default_sigstore_opts) + info := ec.sigstore.verify_attestation(_image_ref, _sigstore_opts) some raw_error in info.errors error := sprintf("image attestation verification failed: %s", [raw_error]) } _errors contains error if { - info := ec.sigstore.verify_attestation(_image_ref, data.config.default_sigstore_opts) + info := ec.sigstore.verify_attestation(_image_ref, _sigstore_opts) count(info.attestations) == 0 error := "verification successful, but no attestations found" } _errors contains error if { - info := ec.sigstore.verify_attestation(_image_ref, data.config.default_sigstore_opts) + info := ec.sigstore.verify_attestation(_image_ref, _sigstore_opts) some att in info.attestations count(att.signatures) == 0 error := sprintf("attestation has no signatures: %s", [att]) } _errors contains error if { - info := ec.sigstore.verify_attestation(_image_ref, data.config.default_sigstore_opts) + info := ec.sigstore.verify_attestation(_image_ref, _sigstore_opts) some att in info.attestations some sig in att.signatures not valid_signature(sig) @@ -67,7 +67,7 @@ _errors contains error if { } _errors contains error if { - info := ec.sigstore.verify_attestation(_image_ref, data.config.default_sigstore_opts) + info := ec.sigstore.verify_attestation(_image_ref, _sigstore_opts) some att in info.attestations att.statement.predicateType != "https://slsa.dev/provenance/v0.2" @@ -75,7 +75,7 @@ _errors contains error if { } _errors contains error if { - info := ec.sigstore.verify_attestation(_image_ref, data.config.default_sigstore_opts) + info := ec.sigstore.verify_attestation(_image_ref, _sigstore_opts) some att in info.attestations builder_id := _builder_id(att) builder_id != "https://tekton.dev/chains/v2" @@ -84,6 +84,8 @@ _errors contains error if { _image_ref := input.image.ref +_sigstore_opts := data.config.default_sigstore_opts + valid_signature(sig) if { type_name(sig.keyid) == "string" type_name(sig.signature) == "string" From 56255d8ca02b1c6d0bb081086ee656927818771a Mon Sep 17 00:00:00 2001 From: Simon Baird Date: Thu, 21 Mar 2024 18:07:41 -0400 Subject: [PATCH 2/3] Experiments with ec validate input and sigstore --- .gitignore | 4 ++ acceptance/examples/sigstore.rego | 2 + hack/builtin-experiments/demo.sh | 89 +++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+) create mode 100755 hack/builtin-experiments/demo.sh diff --git a/.gitignore b/.gitignore index c3cfbd7bb..342740f91 100644 --- a/.gitignore +++ b/.gitignore @@ -177,3 +177,7 @@ node_modules # kustomize expanded Helm charts hack/**/charts + +# Some other stuff we don't want to check in +hack/builtin-experiments/data +hack/builtin-experiments/policy diff --git a/acceptance/examples/sigstore.rego b/acceptance/examples/sigstore.rego index a3c32d451..0ed946913 100644 --- a/acceptance/examples/sigstore.rego +++ b/acceptance/examples/sigstore.rego @@ -3,6 +3,8 @@ package sigstore import rego.v1 # METADATA +# title: Image validation +# description: Check image and attestation signatures # custom: # short_name: valid deny contains result if { diff --git a/hack/builtin-experiments/demo.sh b/hack/builtin-experiments/demo.sh new file mode 100755 index 000000000..6b371af22 --- /dev/null +++ b/hack/builtin-experiments/demo.sh @@ -0,0 +1,89 @@ +#!/usr/bin/env bash +# Copyright The Enterprise Contract Contributors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +GIT_ROOT=$(git rev-parse --show-toplevel) +EC=${EC:-"${GIT_ROOT}/dist/ec"} +LOCAL_DIR=${GIT_ROOT}/hack/builtin-experiments +DATA_DIR=${LOCAL_DIR}/data/data +POLICY_DIR=${LOCAL_DIR}/policy/policy + +mkdir -p ${DATA_DIR} ${POLICY_DIR} + +# This has no attestation currently... +#IMAGE=${IMAGE:-"quay.io/redhat-appstudio/ec-golden-image:latest"} + +# This is the ec build for TAS so it should be good 🐕🥣 +IMAGE=${IMAGE:-"quay.io/redhat-user-workloads/rhtap-contract-tenant/ec-v02/cli-v02:c862b0f77bb10082d1440e0d4b6a4e9645b83382"} + +# The image digest must be specified explictly so go look it up +IMAGE_DIGEST=$(skopeo inspect --no-tags docker://$IMAGE | jq -r .Digest) +FULL_IMAGE_REF="$IMAGE@$IMAGE_DIGEST" + +# Input looks like this +INPUT_JSON='{ + "image": { + "ref": "'$FULL_IMAGE_REF'" + } +}' + +# A minimal ECP using local files +# ec looks for specific subdirs under the source's root location +# so that's why we have policy/policy and data/data +POLICY_JSON='{ + "sources": [ + { + "policy": [ + "'$LOCAL_DIR'/policy" + ], + "data": [ + "'$LOCAL_DIR'/data" + ] + } + ] +}' + +# Public key for the signature of the image we're verifying +PUBLIC_KEY="-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZP/0htjhVt2y0ohjgtIIgICOtQtA +naYJRuLprwIv6FDhZ5yFjYUEtsmoNcW7rx2KM6FOXGsCX3BNc7qhHELT+g== +-----END PUBLIC KEY-----" + +# Hack hack... +echo '{ + "sigstore_opts": { + "ignore_rekor": true, + "public_key": "'${PUBLIC_KEY//$'\n'/\\n}'" + } +}' > ${DATA_DIR}/sigstore_opts.json + +# The acceptance test rego is pretty much prod-ready.. :) +# Tweak one line to make it work with the sigstore_opts data we just created above +sed \ + 's/^_sigstore_opts :=.*/_sigstore_opts := object.union(data.config.default_sigstore_opts, data.sigstore_opts)/' \ + ${GIT_ROOT}/acceptance/examples/sigstore.rego \ + > ${POLICY_DIR}/sigstore.rego + +echo -e "\n* Input:\n" +echo "$INPUT_JSON" | yq -P + +echo -e "\n* EC results:\n" +$EC validate input \ + --file <(echo $INPUT_JSON) \ + --policy "$(echo $POLICY_JSON)" \ + --show-successes \ + --info \ + | yq -P From a93ec199acf15eb20a13d587db3caca4cfb17973 Mon Sep 17 00:00:00 2001 From: Simon Baird Date: Fri, 22 Mar 2024 09:10:41 -0400 Subject: [PATCH 3/3] More hackery Will clean it up later. This demos slsa3 passing with ec validate input. --- hack/builtin-experiments/demo.sh | 46 +++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/hack/builtin-experiments/demo.sh b/hack/builtin-experiments/demo.sh index 6b371af22..e5629aab3 100755 --- a/hack/builtin-experiments/demo.sh +++ b/hack/builtin-experiments/demo.sh @@ -43,18 +43,25 @@ INPUT_JSON='{ # A minimal ECP using local files # ec looks for specific subdirs under the source's root location # so that's why we have policy/policy and data/data -POLICY_JSON='{ - "sources": [ - { - "policy": [ - "'$LOCAL_DIR'/policy" - ], - "data": [ - "'$LOCAL_DIR'/data" - ] - } - ] -}' +POLICY_YAML=' +sources: + - policy: + - '$POLICY_DIR' + - github.com/simonbaird/ec-policies//policy/lib?ref=builtin-experiments + - github.com/simonbaird/ec-policies//policy/release?ref=builtin-experiments + + data: + - '$DATA_DIR' + - oci::quay.io/redhat-appstudio-tekton-catalog/data-acceptable-bundles:latest + - github.com/release-engineering/rhtap-ec-policy//data + + config: + include: + # Fixme: I dont think it is running the sigstore check sin sigstore.rego + # now, not sure why + - "sigstore" + - "@slsa3" +' # Public key for the signature of the image we're verifying PUBLIC_KEY="-----BEGIN PUBLIC KEY----- @@ -73,7 +80,8 @@ echo '{ # The acceptance test rego is pretty much prod-ready.. :) # Tweak one line to make it work with the sigstore_opts data we just created above sed \ - 's/^_sigstore_opts :=.*/_sigstore_opts := object.union(data.config.default_sigstore_opts, data.sigstore_opts)/' \ + -e 's/^_sigstore_opts :=.*/_sigstore_opts := object.union(data.config.default_sigstore_opts, data.sigstore_opts)/' \ + -e 's/^package sigstore/package policy.release.sigstore/' \ ${GIT_ROOT}/acceptance/examples/sigstore.rego \ > ${POLICY_DIR}/sigstore.rego @@ -83,7 +91,15 @@ echo "$INPUT_JSON" | yq -P echo -e "\n* EC results:\n" $EC validate input \ --file <(echo $INPUT_JSON) \ - --policy "$(echo $POLICY_JSON)" \ + --policy "$(echo "$POLICY_YAML" | yq -ojson)" \ --show-successes \ - --info \ | yq -P + +# For debugging... +#echo "$INPUT_JSON" > i.json +#ec opa eval \ +# --input i.json \ +# 'data.lib._input_attestations' \ +# --data ${DATA_DIR} \ +# --data /home/sbaird/code/ec-policies/policy/lib \ +# --data /home/sbaird/code/ec-policies/policy/release | yq -P