diff --git a/config/300-clusterimagepolicy.yaml b/config/300-clusterimagepolicy.yaml index b24b4eedd..416b94401 100644 --- a/config/300-clusterimagepolicy.yaml +++ b/config/300-clusterimagepolicy.yaml @@ -104,6 +104,9 @@ spec: description: CTLog sets the configuration to verify the authority against a Rekor instance. type: object properties: + trustRootRef: + description: Use the Public Key from the referred TrustRoot.TLog + type: string url: description: URL sets the url to the rekor instance (by default the public rekor.sigstore.dev) type: string @@ -175,6 +178,9 @@ spec: subjectRegExp: description: SubjectRegExp specifies a regular expression to match the subject for this identity. type: string + trustRootRef: + description: Use the Certificate Chain from the referred TrustRoot.CertificateAuthorities and TrustRoot.CTLog + type: string url: description: URL defines a url to the keyless instance. type: string @@ -357,6 +363,9 @@ spec: description: CTLog sets the configuration to verify the authority against a Rekor instance. type: object properties: + trustRootRef: + description: Use the Public Key from the referred TrustRoot.TLog + type: string url: description: URL sets the url to the rekor instance (by default the public rekor.sigstore.dev) type: string @@ -428,6 +437,9 @@ spec: subjectRegExp: description: SubjectRegExp specifies a regular expression to match the subject for this identity. type: string + trustRootRef: + description: Use the Certificate Chain from the referred TrustRoot.CertificateAuthorities and TrustRoot.CTLog + type: string url: description: URL defines a url to the keyless instance. type: string diff --git a/docs/api-types/index.md b/docs/api-types/index.md index 330a7e278..360afcf4b 100644 --- a/docs/api-types/index.md +++ b/docs/api-types/index.md @@ -141,6 +141,7 @@ KeylessRef contains location of the validating certificate and the identities ag | url | URL defines a url to the keyless instance. | apis.URL | false | | identities | Identities sets a list of identities. | [][Identity](#identity) | false | | ca-cert | CACert sets a reference to CA certificate | [KeyRef](#keyref) | false | +| trustRootRef | Use the Certificate Chain from the referred TrustRoot.CertificateAuthorities and TrustRoot.CTLog | string | false | [Back to TOC](#table-of-contents) @@ -199,5 +200,6 @@ TLog specifies the URL to a transparency log that holds the signature and public | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | url | URL sets the url to the rekor instance (by default the public rekor.sigstore.dev) | apis.URL | false | +| trustRootRef | Use the Public Key from the referred TrustRoot.TLog | string | false | [Back to TOC](#table-of-contents) diff --git a/examples/policies/custom-key-attestation-sbom-spdxjson.yaml b/examples/policies/custom-key-attestation-sbom-spdxjson.yaml index 2da3793a5..5771915fc 100644 --- a/examples/policies/custom-key-attestation-sbom-spdxjson.yaml +++ b/examples/policies/custom-key-attestation-sbom-spdxjson.yaml @@ -36,6 +36,8 @@ spec: MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEOc6HkISHzVdUbtUsdjYtPuyPYBeg 4FCemyVurIM4KEORQk4OAu8ZNwxvGSoY3eAabYaFIPPQ8ROAjrbdPwNdJw== -----END PUBLIC KEY----- + ctlog: + url: https://rekor.sigstore.dev attestations: - name: must-have-spdxjson predicateType: spdxjson diff --git a/examples/policies/keyless-attestation-sbom-spdxjson.yaml b/examples/policies/keyless-attestation-sbom-spdxjson.yaml index 8d2a71783..ef4115f31 100644 --- a/examples/policies/keyless-attestation-sbom-spdxjson.yaml +++ b/examples/policies/keyless-attestation-sbom-spdxjson.yaml @@ -35,6 +35,8 @@ spec: identities: - issuer: https://token.actions.githubusercontent.com subject: "https://github.com/sigstore/policy-controller/.github/workflows/policy-tester-examples.yml@refs/heads/main" + ctlog: + url: https://rekor.sigstore.dev attestations: - name: must-have-spdxjson predicateType: spdxjson diff --git a/examples/policies/release-signed-by-github-actions.yaml b/examples/policies/release-signed-by-github-actions.yaml index 6292691a8..d86eeedfc 100644 --- a/examples/policies/release-signed-by-github-actions.yaml +++ b/examples/policies/release-signed-by-github-actions.yaml @@ -38,3 +38,5 @@ spec: # Matches a specific github workflow on main branch. Here we use the # sigstore policy controller example testing workflow as an example. subject: "https://github.com/sigstore/policy-controller/.github/workflows/release.yaml@refs/tags/v0.3.0" + ctlog: + url: https://rekor.sigstore.dev diff --git a/examples/policies/signed-by-aws-kms-key.yaml b/examples/policies/signed-by-aws-kms-key.yaml index dae8f5c77..4a06b40f5 100644 --- a/examples/policies/signed-by-aws-kms-key.yaml +++ b/examples/policies/signed-by-aws-kms-key.yaml @@ -34,3 +34,5 @@ spec: # NB: the policy controller must have kms.DescribeKey, kms.GetPublicKey # and kms.Verify IAM permissions on the relevant key. kms: awskms:///arn:aws:kms:<< region >>:<< account id >>:key/<< key id >> + ctlog: + url: https://rekor.sigstore.dev diff --git a/examples/policies/signed-by-github-actions.yaml b/examples/policies/signed-by-github-actions.yaml index 22df207ea..67179ac9f 100644 --- a/examples/policies/signed-by-github-actions.yaml +++ b/examples/policies/signed-by-github-actions.yaml @@ -38,3 +38,5 @@ spec: # Matches a specific github workflow on main branch. Here we use the # sigstore policy controller example testing workflow as an example. subject: "https://github.com/sigstore/policy-controller/.github/workflows/policy-tester-examples.yml@refs/heads/main" + ctlog: + url: https://rekor.sigstore.dev diff --git a/go.mod b/go.mod index 7a7954b96..aa4fe3ab2 100644 --- a/go.mod +++ b/go.mod @@ -132,6 +132,8 @@ require ( github.com/containerd/stargz-snapshotter/estargz v0.12.1 // indirect github.com/cyberphone/json-canonicalization v0.0.0-20220623050100-57a0ce2678a7 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/digitorus/pkcs7 v0.0.0-20221019075359-21b8b40e6bb4 // indirect + github.com/digitorus/timestamp v0.0.0-20221019182153-ef3b63b79b31 // indirect github.com/dimchansky/utfbom v1.1.1 // indirect github.com/docker/cli v20.10.21+incompatible // indirect github.com/docker/distribution v2.8.1+incompatible // indirect @@ -147,12 +149,13 @@ require ( github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.5.1 // indirect github.com/go-logr/logr v1.2.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/analysis v0.21.4 // indirect github.com/go-openapi/errors v0.20.3 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/jsonreference v0.20.0 // indirect github.com/go-openapi/loads v0.21.2 // indirect - github.com/go-openapi/runtime v0.24.2 // indirect + github.com/go-openapi/runtime v0.25.0 // indirect github.com/go-openapi/spec v0.20.7 // indirect github.com/go-openapi/strfmt v0.21.3 // indirect github.com/go-openapi/swag v0.22.3 // indirect @@ -199,7 +202,7 @@ require ( github.com/mpvl/unique v0.0.0-20150818121801-cbe035fff7de // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/oklog/ulid v1.3.1 // indirect - github.com/open-policy-agent/opa v0.45.0 // indirect + github.com/open-policy-agent/opa v0.47.2 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0-rc2 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect @@ -207,7 +210,7 @@ require ( github.com/pelletier/go-toml/v2 v2.0.5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.13.0 // indirect + github.com/prometheus/client_golang v1.14.0 // indirect github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect @@ -216,13 +219,14 @@ require ( github.com/sassoftware/relic v0.0.0-20210427151427-dfb082b79b74 // indirect github.com/secure-systems-lab/go-securesystemslib v0.4.0 // indirect github.com/shibumi/go-pathspec v1.3.0 // indirect + github.com/sigstore/timestamp-authority v0.1.3-0.20221114113831-cf271cea5d83 // indirect github.com/sirupsen/logrus v1.9.0 // indirect github.com/spf13/afero v1.9.2 // indirect github.com/spf13/cast v1.5.0 // indirect github.com/spf13/cobra v1.6.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.13.0 // indirect + github.com/spf13/viper v1.14.0 // indirect github.com/subosito/gotenv v1.4.1 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/tchap/go-patricia/v2 v2.3.1 // indirect @@ -231,12 +235,14 @@ require ( github.com/tjfoc/gmsm v1.4.1 // indirect github.com/transparency-dev/merkle v0.0.1 // indirect github.com/vbatts/tar-split v0.11.2 // indirect - github.com/xanzy/go-gitlab v0.73.1 // indirect + github.com/xanzy/go-gitlab v0.76.0 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/yashtewari/glob-intersection v0.1.0 // indirect go.mongodb.org/mongo-driver v1.10.3 // indirect go.opencensus.io v0.24.0 // indirect + go.opentelemetry.io/otel v1.11.1 // indirect + go.opentelemetry.io/otel/trace v1.11.1 // indirect go.uber.org/automaxprocs v1.5.1 // indirect go.uber.org/multierr v1.8.0 // indirect golang.org/x/exp v0.0.0-20221026153819-32f3d567a233 // indirect @@ -264,3 +270,7 @@ require ( // TODO: this dependency causes issues on webhook startup due // to conflicting "log_dir" flags between this and klog (knative) replace github.com/golang/glog => github.com/jdolitsky/glog v0.0.0-20220729172235-78744e90d087 + +// Bring in the latest cosign so we can pass various keys in to verification +// functions +replace github.com/sigstore/cosign => github.com/sigstore/cosign v1.13.2-0.20221209171251-6cb723fc299c diff --git a/go.sum b/go.sum index 5196d8b14..a15c1a235 100644 --- a/go.sum +++ b/go.sum @@ -52,6 +52,7 @@ contrib.go.opencensus.io/exporter/prometheus v0.4.2/go.mod h1:dvEHbiKmgvbr5pjaF9 cuelang.org/go v0.4.3 h1:W3oBBjDTm7+IZfCKZAmC8uDG0eYfJL4Pp/xbbCMKaVo= cuelang.org/go v0.4.3/go.mod h1:7805vR9H+VoBNdWFdI7jyDR3QLUPp4+naHfbcgp55HI= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0 h1:8+4G8JaejP8Xa6W46PzJEwisNgBXMvFcz78N6zG/ARw= github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0/go.mod h1:GgeIE+1be8Ivm7Sh4RgwI42aTtC9qrcj+Y9Y6CjJhJs= github.com/Azure/azure-sdk-for-go v67.1.0+incompatible h1:oziYcaopbnIKfM69DL05wXdypiqfrUKdxUKrKpynJTw= @@ -212,7 +213,7 @@ github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHf github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= -github.com/bytecodealliance/wasmtime-go v1.0.0 h1:9u9gqaUiaJeN5IoD1L7egD8atOnTGyJcNp8BhkL9cUU= +github.com/bytecodealliance/wasmtime-go/v3 v3.0.2 h1:3uZCA/BLTIu+DqCfguByNMJa2HVHpXvjfy0Dy7g6fuA= github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -261,12 +262,16 @@ github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnG github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgraph-io/badger/v3 v3.2103.2 h1:dpyM5eCJAtQCBcMCZcT4UBZchuTJgCywerHHgmxfxM8= -github.com/dgraph-io/ristretto v0.1.0 h1:Jv3CGQHp9OjuMBSne1485aDpUkTKEcUqF+jm/LuerPI= +github.com/dgraph-io/badger/v3 v3.2103.4 h1:WE1B07YNTTJTtG9xjBcSW2wn0RJLyiV99h959RKZqM4= +github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g= github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= +github.com/digitorus/pkcs7 v0.0.0-20221019075359-21b8b40e6bb4 h1:MxNIia2F3bgFyNsOZy9UbNlpKAxbtCudkVmlJBNuvmg= +github.com/digitorus/pkcs7 v0.0.0-20221019075359-21b8b40e6bb4/go.mod h1:SKVExuS+vpu2l9IoOc0RwqE7NYnb0JlcFHFnEJkVDzc= +github.com/digitorus/timestamp v0.0.0-20221019182153-ef3b63b79b31 h1:3go0tpsBpbs9L/oysk3jDwRprlLRRkpSU7YxKlTfU+o= +github.com/digitorus/timestamp v0.0.0-20221019182153-ef3b63b79b31/go.mod h1:6V2ND8Yf8TOJ4h+9pmUlx8kXvNLBB2QplToVVZQ3rF0= github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= github.com/docker/cli v20.10.21+incompatible h1:qVkgyYUnOLQ98LtXBrwd/duVqPT2X4SHndOuGsfwyhU= @@ -277,7 +282,7 @@ github.com/docker/docker v20.10.21+incompatible h1:UTLdBmHk3bEY+w8qeO5KttOhy6OmX github.com/docker/docker v20.10.21+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= @@ -331,8 +336,11 @@ github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNV github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= github.com/go-openapi/analysis v0.21.4 h1:ZDFLvSNxpDaomuCueM0BlSXxpANBlFYiBvr+GXrvIHc= github.com/go-openapi/analysis v0.21.4/go.mod h1:4zQ35W4neeZTqh3ol0rv/O8JBbka9QyAgQRPp9y3pfo= @@ -350,15 +358,14 @@ github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXym github.com/go-openapi/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g= github.com/go-openapi/loads v0.21.2 h1:r2a/xFIYeZ4Qd2TnGpWDIQNcP80dIaZgf704za8enro= github.com/go-openapi/loads v0.21.2/go.mod h1:Jq58Os6SSGz0rzh62ptiu8Z31I+OTHqmULx5e/gJbNw= -github.com/go-openapi/runtime v0.24.2 h1:yX9HMGQbz32M87ECaAhGpJjBmErO3QLcgdZj9BzGx7c= -github.com/go-openapi/runtime v0.24.2/go.mod h1:AKurw9fNre+h3ELZfk6ILsfvPN+bvvlaU/M9q/r9hpk= +github.com/go-openapi/runtime v0.25.0 h1:7yQTCdRbWhX8vnIjdzU8S00tBYf7Sg71EBeorlPHvhc= +github.com/go-openapi/runtime v0.25.0/go.mod h1:Ux6fikcHXyyob6LNWxtE96hWwjBPYF0DXgVFuMTneOs= github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= github.com/go-openapi/spec v0.20.7 h1:1Rlu/ZrOCCob0n+JKKJAWhNWMPW8bOZRg8FJaY+0SKI= github.com/go-openapi/spec v0.20.7/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg= github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= -github.com/go-openapi/strfmt v0.21.2/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= github.com/go-openapi/strfmt v0.21.3 h1:xwhj5X6CjXEZZHMWy1zKJxvW9AfHC9pkyUjLvHtKG7o= github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= @@ -366,7 +373,6 @@ github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/ github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-openapi/validate v0.21.0/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= github.com/go-openapi/validate v0.22.0 h1:b0QecH6VslW/TxtpKgzpO1SNG7GU2FsaqKdP1E2T50Y= github.com/go-openapi/validate v0.22.0/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= @@ -378,7 +384,6 @@ github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= @@ -503,6 +508,7 @@ github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/tink/go v1.7.0 h1:6Eox8zONGebBFcCBqkVmt60LaWZa6xg1cl/DwAh/J1w= github.com/google/trillian v1.5.1-0.20220819043421-0a389c4bb8d9 h1:GFmzYtwUMi1S2mjLxfrJ/CZ9gWDG+zeLtZByg/QEBkk= github.com/google/trillian v1.5.1-0.20220819043421-0a389c4bb8d9/go.mod h1:vywkS3p2SgNmPL7oAWqU5PiiknzRMp+ol3a19jfY2PQ= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -687,7 +693,6 @@ github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUb github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= @@ -728,8 +733,8 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/onsi/gomega v1.23.0 h1:/oxKu9c2HVap+F3PfKort2Hw5DEU+HGlW8n+tguWsys= -github.com/open-policy-agent/opa v0.45.0 h1:P5nuhVRtR+e58fk3CMMbiqr6ZFyWQPNOC3otsorGsFs= -github.com/open-policy-agent/opa v0.45.0/go.mod h1:/OnsYljNEWJ6DXeFOOnoGn8CvwZGMUS4iRqzYdJvmBI= +github.com/open-policy-agent/opa v0.47.2 h1:9QmIumL6MRPYoXboBDSU/c1fG2PN5J4lo800RK36jrc= +github.com/open-policy-agent/opa v0.47.2/go.mod h1:I5DbT677OGqfk9gvu5i54oIt0rrVf4B5pedpqDquAXo= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034= @@ -764,8 +769,9 @@ github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU= github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= +github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= +github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -807,6 +813,7 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= @@ -821,12 +828,14 @@ github.com/secure-systems-lab/go-securesystemslib v0.4.0/go.mod h1:FGBZgq2tXWICs github.com/shibumi/go-pathspec v1.3.0 h1:QUyMZhFo0Md5B8zV8x2tesohbb5kfbpTi9rBnKh5dkI= github.com/shibumi/go-pathspec v1.3.0/go.mod h1:Xutfslp817l2I1cZvgcfeMQJG5QnU2lh5tVaaMCl3jE= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sigstore/cosign v1.13.1 h1:+5oF8jisEcDw2TuXxCADC1u5//HfdnJhGbpv9Isiwu4= -github.com/sigstore/cosign v1.13.1/go.mod h1:PlfJODkovUOKsLrGI7Su57Ie/Eb/Ks7hRHw3tn5hQS4= +github.com/sigstore/cosign v1.13.2-0.20221209171251-6cb723fc299c h1:R8QPkiCSIQZcicsGwsNi/FKLnqsJfjjU+ioIGnePOMg= +github.com/sigstore/cosign v1.13.2-0.20221209171251-6cb723fc299c/go.mod h1:GzpCk4EzX9FU1F7sjvafzqERNKDaHNRYWiYavjWbwXo= github.com/sigstore/rekor v1.0.1 h1:rcESXSNkAPRWFYZel9rarspdvneET60F2ngNkadi89c= github.com/sigstore/rekor v1.0.1/go.mod h1:ecTKdZWGWqE1pl3U1m1JebQJLU/hSjD9vYHOmHQ7w4g= github.com/sigstore/sigstore v1.5.0 h1:NqstQ6SwwhQsp6Ll0wgk/d9g5MlfmEppo14aquUjJ/8= github.com/sigstore/sigstore v1.5.0/go.mod h1:fRAaZ9xXh7ZQ0GJqZdpmNJ3pemuHBu2PgIAngmzIFSI= +github.com/sigstore/timestamp-authority v0.1.3-0.20221114113831-cf271cea5d83 h1:9knkInHcIsx8m+2WNW/iCMdfGOT1rab1BOLnpJXXjgM= +github.com/sigstore/timestamp-authority v0.1.3-0.20221114113831-cf271cea5d83/go.mod h1:k6n2UP+ruwsyT2RiajdhKMSAv44OoHIkNPicfh0/TGU= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= @@ -857,8 +866,8 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= -github.com/spf13/viper v1.13.0 h1:BWSJ/M+f+3nmdz9bxB+bWX28kkALN2ok11D0rSo8EJU= -github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw= +github.com/spf13/viper v1.14.0 h1:Rg7d3Lo706X9tHsJMUjdiwMpHB7W8WnSVOssIY+JElU= +github.com/spf13/viper v1.14.0/go.mod h1:WT//axPky3FdvXHzGw33dNdXXXfFQqmEalje+egj8As= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -904,12 +913,13 @@ github.com/transparency-dev/merkle v0.0.1/go.mod h1:B8FIw5LTq6DaULoHsVFRzYIUDkl8 github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc= github.com/vbatts/tar-split v0.11.2 h1:Via6XqJr0hceW4wff3QRzD5gAk/tatMw/4ZA7cTlIME= github.com/vbatts/tar-split v0.11.2/go.mod h1:vV3ZuO2yWSVsz+pfFzDG/upWH1JhjOiEaWq6kXyQ3VI= github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= -github.com/xanzy/go-gitlab v0.73.1 h1:UMagqUZLJdjss1SovIC+kJCH4k2AZWXl58gJd38Y/hI= -github.com/xanzy/go-gitlab v0.73.1/go.mod h1:d/a0vswScO7Agg1CZNz15Ic6SSvBG9vfw8egL99t4kA= +github.com/xanzy/go-gitlab v0.76.0 h1:mkmuB27RDVZY/iXR61pEUfIqJ15Iivfu1kc3KZtBICI= +github.com/xanzy/go-gitlab v0.76.0/go.mod h1:d/a0vswScO7Agg1CZNz15Ic6SSvBG9vfw8egL99t4kA= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= @@ -936,7 +946,6 @@ github.com/zalando/go-keyring v0.1.0/go.mod h1:RaxNwUITJaHVdQ0VC7pELPZ3tOWn13nr0 go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg= go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= -go.mongodb.org/mongo-driver v1.8.3/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY= go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= go.mongodb.org/mongo-driver v1.10.3 h1:XDQEvmh6z1EUsXuIkXE9TaVeqHw6SwS1uf93jFs0HBA= go.mongodb.org/mongo-driver v1.10.3/go.mod h1:z4XpeoU6w+9Vht+jAFyLgVrD+jGSQQe0+CBWFHNiHt8= @@ -949,7 +958,13 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/otel v1.11.1 h1:4WLLAmcfkmDk2ukNXJyq3/kiz/3UzCaYq6PskJsaou4= +go.opentelemetry.io/otel v1.11.1/go.mod h1:1nNhXBbWSD0nsL38H6btgnFN2k4i0sNLHNNMZMSbUGE= +go.opentelemetry.io/otel/sdk v1.11.1 h1:F7KmQgoHljhUuJyA+9BiU+EkJfyX5nVVF4wyzWZpKxs= +go.opentelemetry.io/otel/trace v1.11.1 h1:ofxdnzsNrGBYXbP7t7zpUK281+go5rF7dvdIZXF8gdQ= +go.opentelemetry.io/otel/trace v1.11.1/go.mod h1:f/Q9G7vzk5u91PhbmKbg1Qn0rzH1LJ4vbPHFGkTPtOk= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.step.sm/crypto v0.23.1 h1:Yr9vlzjGqIKVi88KcpZtEcNTcpDkt1nVR7tumW4h+CU= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= @@ -977,7 +992,6 @@ golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200930160638-afb6bcd081ae/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= @@ -1179,7 +1193,6 @@ golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI= diff --git a/pkg/apis/config/sigstore_keys.go b/pkg/apis/config/sigstore_keys.go index 125652e0f..0e4f9d00c 100644 --- a/pkg/apis/config/sigstore_keys.go +++ b/pkg/apis/config/sigstore_keys.go @@ -106,7 +106,7 @@ type SigstoreKeysMap struct { } // NewSigstoreKeysFromMap creates a map of SigstoreKeys to use for validation. -func NewSigstoreKeysFromMap(data map[string]string) (map[string]SigstoreKeys, error) { +func NewSigstoreKeysFromMap(data map[string]string) (*SigstoreKeysMap, error) { ret := make(map[string]SigstoreKeys, len(data)) // Spin through the ConfigMap. Each entry will have a serialized form of // necessary validation keys in the form of SigstoreKeys. @@ -125,11 +125,11 @@ func NewSigstoreKeysFromMap(data map[string]string) (map[string]SigstoreKeys, er } ret[k] = *sigstoreKeys } - return ret, nil + return &SigstoreKeysMap{SigstoreKeys: ret}, nil } // NewImagePoliciesConfigFromConfigMap creates a Features from the supplied ConfigMap -func NewSigstoreKeysFromConfigMap(config *corev1.ConfigMap) (map[string]SigstoreKeys, error) { +func NewSigstoreKeysFromConfigMap(config *corev1.ConfigMap) (*SigstoreKeysMap, error) { return NewSigstoreKeysFromMap(config.Data) } diff --git a/pkg/apis/config/sigstore_keys_test.go b/pkg/apis/config/sigstore_keys_test.go index 369c6f72d..d6e939b34 100644 --- a/pkg/apis/config/sigstore_keys_test.go +++ b/pkg/apis/config/sigstore_keys_test.go @@ -66,11 +66,11 @@ const ( func TestDefaultsSigstoreKeysConfigurationFromFile(t *testing.T) { _, example := ConfigMapsFromTestFile(t, SigstoreKeysConfigName) - keys, err := NewSigstoreKeysFromConfigMap(example) + keysMap, err := NewSigstoreKeysFromConfigMap(example) if err != nil { t.Error("NewSigstoreKeysFromConfigMap(example) =", err) } - sigstoreKeys := keys["my-custom-sigstore-keys"] + sigstoreKeys := keysMap.SigstoreKeys["my-custom-sigstore-keys"] got := sigstoreKeys.CertificateAuthorities[0].Subject.Organization if got != "fulcio-organization" { t.Errorf("Invalid organization, want foo got %s", got) diff --git a/pkg/apis/config/store.go b/pkg/apis/config/store.go index c019416f0..1d8cef151 100644 --- a/pkg/apis/config/store.go +++ b/pkg/apis/config/store.go @@ -46,8 +46,10 @@ func FromContextOrDefaults(ctx context.Context) *Config { return cfg } config, _ := NewImagePoliciesConfigFromMap(map[string]string{}) + sigstoreKeysMap, _ := NewSigstoreKeysFromMap(map[string]string{}) return &Config{ - ImagePolicyConfig: config, + ImagePolicyConfig: config, + SigstoreKeysConfig: sigstoreKeysMap, } } @@ -88,6 +90,7 @@ func (s *Store) ToContext(ctx context.Context) context.Context { // Load creates a Config from the current config state of the Store. func (s *Store) Load() *Config { return &Config{ - ImagePolicyConfig: s.UntypedLoad(ImagePoliciesConfigName).(*ImagePolicyConfig), + ImagePolicyConfig: s.UntypedLoad(ImagePoliciesConfigName).(*ImagePolicyConfig), + SigstoreKeysConfig: s.UntypedLoad(SigstoreKeysConfigName).(*SigstoreKeysMap), } } diff --git a/pkg/apis/config/store_test.go b/pkg/apis/config/store_test.go index cfb163f72..019e0be0d 100644 --- a/pkg/apis/config/store_test.go +++ b/pkg/apis/config/store_test.go @@ -37,8 +37,10 @@ func TestStoreLoadWithContext(t *testing.T) { store := NewStore(logtesting.TestLogger(t)) _, imagePolicies := ConfigMapsFromTestFile(t, ImagePoliciesConfigName) + _, sigstoreKeysMap := ConfigMapsFromTestFile(t, SigstoreKeysConfigName) store.OnConfigChanged(imagePolicies) + store.OnConfigChanged(sigstoreKeysMap) config := FromContextOrDefaults(store.ToContext(context.Background())) @@ -48,10 +50,17 @@ func TestStoreLoadWithContext(t *testing.T) { t.Error("Unexpected defaults config (-want, +got):", diff) } }) + t.Run("sigstore-keys", func(t *testing.T) { + expected, _ := NewSigstoreKeysFromConfigMap(sigstoreKeysMap) + if diff := cmp.Diff(expected, config.SigstoreKeysConfig, ignoreStuff...); diff != "" { + t.Error("Unexpected defaults config (-want, +got):", diff) + } + }) } func TestStoreLoadWithContextOrDefaults(t *testing.T) { imagePolicies := ConfigMapFromTestFile(t, ImagePoliciesConfigName) + sigstoreKeysMap := ConfigMapFromTestFile(t, SigstoreKeysConfigName) config := FromContextOrDefaults(context.Background()) t.Run("image-policies", func(t *testing.T) { @@ -60,4 +69,10 @@ func TestStoreLoadWithContextOrDefaults(t *testing.T) { t.Error("Unexpected defaults config (-want, +got):", diff) } }) + t.Run("sigstore-keys", func(t *testing.T) { + expected, _ := NewSigstoreKeysFromConfigMap(sigstoreKeysMap) + if diff := cmp.Diff(expected, config.SigstoreKeysConfig, ignoreStuff...); diff != "" { + t.Error("Unexpected defaults config (-want, +got):", diff) + } + }) } diff --git a/pkg/apis/policy/v1alpha1/clusterimagepolicy_conversion.go b/pkg/apis/policy/v1alpha1/clusterimagepolicy_conversion.go index 27053dc08..c93f6014d 100644 --- a/pkg/apis/policy/v1alpha1/clusterimagepolicy_conversion.go +++ b/pkg/apis/policy/v1alpha1/clusterimagepolicy_conversion.go @@ -88,7 +88,10 @@ func (matchResource *MatchResource) ConvertTo(ctx context.Context, sink *v1beta1 func (authority *Authority) ConvertTo(ctx context.Context, sink *v1beta1.Authority) error { sink.Name = authority.Name if authority.CTLog != nil && authority.CTLog.URL != nil { - sink.CTLog = &v1beta1.TLog{URL: authority.CTLog.URL.DeepCopy()} + sink.CTLog = &v1beta1.TLog{ + URL: authority.CTLog.URL.DeepCopy(), + TrustRootRef: authority.CTLog.TrustRootRef, + } } for _, source := range authority.Sources { v1beta1Source := v1beta1.Source{} @@ -114,7 +117,8 @@ func (authority *Authority) ConvertTo(ctx context.Context, sink *v1beta1.Authori } if authority.Keyless != nil { sink.Keyless = &v1beta1.KeylessRef{ - URL: authority.Keyless.URL.DeepCopy(), + URL: authority.Keyless.URL.DeepCopy(), + TrustRootRef: authority.Keyless.TrustRootRef, } for _, id := range authority.Keyless.Identities { sink.Keyless.Identities = append(sink.Keyless.Identities, v1beta1.Identity{Issuer: id.Issuer, Subject: id.Subject, IssuerRegExp: id.IssuerRegExp, SubjectRegExp: id.SubjectRegExp}) @@ -222,7 +226,10 @@ func (spec *ClusterImagePolicySpec) ConvertFrom(ctx context.Context, source *v1b func (authority *Authority) ConvertFrom(ctx context.Context, source *v1beta1.Authority) error { authority.Name = source.Name if source.CTLog != nil && source.CTLog.URL != nil { - authority.CTLog = &TLog{URL: source.CTLog.URL.DeepCopy()} + authority.CTLog = &TLog{ + URL: source.CTLog.URL.DeepCopy(), + TrustRootRef: source.CTLog.TrustRootRef, + } } for _, s := range source.Sources { src := Source{} @@ -248,7 +255,8 @@ func (authority *Authority) ConvertFrom(ctx context.Context, source *v1beta1.Aut } if source.Keyless != nil { authority.Keyless = &KeylessRef{ - URL: source.Keyless.URL.DeepCopy(), + URL: source.Keyless.URL.DeepCopy(), + TrustRootRef: source.Keyless.TrustRootRef, } for _, id := range source.Keyless.Identities { authority.Keyless.Identities = append(authority.Keyless.Identities, Identity{Issuer: id.Issuer, Subject: id.Subject, IssuerRegExp: id.IssuerRegExp, SubjectRegExp: id.SubjectRegExp}) diff --git a/pkg/apis/policy/v1alpha1/clusterimagepolicy_types.go b/pkg/apis/policy/v1alpha1/clusterimagepolicy_types.go index 1d4f1586c..f8007f49e 100644 --- a/pkg/apis/policy/v1alpha1/clusterimagepolicy_types.go +++ b/pkg/apis/policy/v1alpha1/clusterimagepolicy_types.go @@ -161,6 +161,9 @@ type TLog struct { // URL sets the url to the rekor instance (by default the public rekor.sigstore.dev) // +optional URL *apis.URL `json:"url,omitempty"` + // Use the Public Key from the referred TrustRoot.TLog + // +optional + TrustRootRef string `json:"trustRootRef,omitempty"` } // KeylessRef contains location of the validating certificate and the identities @@ -176,6 +179,9 @@ type KeylessRef struct { // CACert sets a reference to CA certificate // +optional CACert *KeyRef `json:"ca-cert,omitempty"` + // Use the Certificate Chain from the referred TrustRoot.CertificateAuthorities and TrustRoot.CTLog + // +optional + TrustRootRef string `json:"trustRootRef,omitempty"` } // Attestation defines the type of attestation to validate and optionally diff --git a/pkg/apis/policy/v1beta1/clusterimagepolicy_types.go b/pkg/apis/policy/v1beta1/clusterimagepolicy_types.go index eaa6d1fa8..34f888157 100644 --- a/pkg/apis/policy/v1beta1/clusterimagepolicy_types.go +++ b/pkg/apis/policy/v1beta1/clusterimagepolicy_types.go @@ -160,6 +160,9 @@ type TLog struct { // URL sets the url to the rekor instance (by default the public rekor.sigstore.dev) // +optional URL *apis.URL `json:"url,omitempty"` + // Use the Public Key from the referred TrustRoot.TLog + // +optional + TrustRootRef string `json:"trustRootRef,omitempty"` } // KeylessRef contains location of the validating certificate and the identities @@ -175,6 +178,9 @@ type KeylessRef struct { // CACert sets a reference to CA certificate // +optional CACert *KeyRef `json:"ca-cert,omitempty"` + // Use the Certificate Chain from the referred TrustRoot.CertificateAuthorities and TrustRoot.CTLog + // +optional + TrustRootRef string `json:"trustRootRef,omitempty"` } // Attestation defines the type of attestation to validate and optionally diff --git a/pkg/reconciler/trustroot/trustroot_test.go b/pkg/reconciler/trustroot/trustroot_test.go index 7429f3b57..f4eb941af 100644 --- a/pkg/reconciler/trustroot/trustroot_test.go +++ b/pkg/reconciler/trustroot/trustroot_test.go @@ -439,7 +439,7 @@ func TestConvertFrom(t *testing.T) { if err != nil { t.Fatalf("Failed to construct from map entry: %v", err) } - sk := skMap["test-entry"] + sk := skMap.SigstoreKeys["test-entry"] if len(sk.TLogs) != 2 { t.Errorf("Not enough TLog entries, want 2 got %d", len(sk.TLogs)) } diff --git a/pkg/webhook/clusterimagepolicy/clusterimagepolicy_types.go b/pkg/webhook/clusterimagepolicy/clusterimagepolicy_types.go index c9820ba80..e053c36bd 100644 --- a/pkg/webhook/clusterimagepolicy/clusterimagepolicy_types.go +++ b/pkg/webhook/clusterimagepolicy/clusterimagepolicy_types.go @@ -111,6 +111,9 @@ type KeylessRef struct { Identities []v1alpha1.Identity `json:"identities,omitempty"` // +optional CACert *KeyRef `json:"ca-cert,omitempty"` + // Use the Certificate Chain from the referred TrustRoot.CertificateAuthorities and TrustRoot.CTLog + // +optional + TrustRootRef string `json:"trustRootRef,omitempty"` } type StaticRef struct { @@ -360,9 +363,10 @@ func convertKeylessRefV1Alpha1ToWebhook(in *v1alpha1.KeylessRef) *KeylessRef { CACertRef := convertKeyRefV1Alpha1ToWebhook(in.CACert) return &KeylessRef{ - URL: in.URL, - Identities: in.Identities, - CACert: CACertRef, + URL: in.URL, + Identities: in.Identities, + CACert: CACertRef, + TrustRootRef: in.TrustRootRef, } } diff --git a/pkg/webhook/validation.go b/pkg/webhook/validation.go index 52fc3aa0a..8c1b74926 100644 --- a/pkg/webhook/validation.go +++ b/pkg/webhook/validation.go @@ -18,7 +18,6 @@ package webhook import ( "context" "crypto" - "crypto/x509" "encoding/pem" "github.com/google/go-containerregistry/pkg/name" @@ -26,21 +25,12 @@ import ( "github.com/sigstore/cosign/pkg/cosign" "github.com/sigstore/cosign/pkg/oci" - ociremote "github.com/sigstore/cosign/pkg/oci/remote" - v1alpha1 "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" - "github.com/sigstore/rekor/pkg/generated/client" - "github.com/sigstore/sigstore/pkg/fulcioroots" "github.com/sigstore/sigstore/pkg/signature" ) -func valid(ctx context.Context, ref name.Reference, rekorClient *client.Rekor, keys []crypto.PublicKey, hashAlgo crypto.Hash, opts ...ociremote.Option) ([]oci.Signature, error) { +func valid(ctx context.Context, ref name.Reference, keys []crypto.PublicKey, hashAlgo crypto.Hash, checkOpts *cosign.CheckOpts) ([]oci.Signature, error) { if len(keys) == 0 { - // If there are no keys, then verify against the fulcio root. - fulcioRoots, err := fulcioroots.Get() - if err != nil { - return nil, err - } - return validSignaturesWithFulcio(ctx, ref, fulcioRoots, nil /* rekor */, nil /* no identities */, opts...) + return validSignatures(ctx, ref, checkOpts) } // We return nil if ANY key matches var lastErr error @@ -51,8 +41,8 @@ func valid(ctx context.Context, ref name.Reference, rekorClient *client.Rekor, k lastErr = err continue } - - sps, err := validSignatures(ctx, ref, verifier, rekorClient, opts...) + checkOpts.SigVerifier = verifier + sps, err := validSignatures(ctx, ref, checkOpts) if err != nil { logging.FromContext(ctx).Errorf("error validating signatures: %v", err) lastErr = err @@ -68,58 +58,15 @@ func valid(ctx context.Context, ref name.Reference, rekorClient *client.Rekor, k var cosignVerifySignatures = cosign.VerifyImageSignatures var cosignVerifyAttestations = cosign.VerifyImageAttestations -func validSignatures(ctx context.Context, ref name.Reference, verifier signature.Verifier, rekorClient *client.Rekor, opts ...ociremote.Option) ([]oci.Signature, error) { - sigs, _, err := cosignVerifySignatures(ctx, ref, &cosign.CheckOpts{ - RegistryClientOpts: opts, - SigVerifier: verifier, - RekorClient: rekorClient, - ClaimVerifier: cosign.SimpleClaimVerifier, - }) - return sigs, err -} - -// validSignaturesWithFulcio expects a Fulcio Cert to verify against. An -// optional rekorClient can also be given, if nil passed, default is assumed. -func validSignaturesWithFulcio(ctx context.Context, ref name.Reference, fulcioRoots *x509.CertPool, rekorClient *client.Rekor, identities []v1alpha1.Identity, opts ...ociremote.Option) ([]oci.Signature, error) { - ids := make([]cosign.Identity, len(identities)) - for i, id := range identities { - ids[i] = cosign.Identity{Issuer: id.Issuer, Subject: id.Subject, IssuerRegExp: id.IssuerRegExp, SubjectRegExp: id.SubjectRegExp} - } - sigs, _, err := cosignVerifySignatures(ctx, ref, &cosign.CheckOpts{ - RegistryClientOpts: opts, - RootCerts: fulcioRoots, - RekorClient: rekorClient, - ClaimVerifier: cosign.SimpleClaimVerifier, - Identities: ids, - }) +func validSignatures(ctx context.Context, ref name.Reference, checkOpts *cosign.CheckOpts) ([]oci.Signature, error) { + checkOpts.ClaimVerifier = cosign.SimpleClaimVerifier + sigs, _, err := cosignVerifySignatures(ctx, ref, checkOpts) return sigs, err } -func validAttestations(ctx context.Context, ref name.Reference, verifier signature.Verifier, rekorClient *client.Rekor, opts ...ociremote.Option) ([]oci.Signature, error) { - attestations, _, err := cosignVerifyAttestations(ctx, ref, &cosign.CheckOpts{ - RegistryClientOpts: opts, - SigVerifier: verifier, - RekorClient: rekorClient, - ClaimVerifier: cosign.IntotoSubjectClaimVerifier, - }) - return attestations, err -} - -// validAttestationsWithFulcio expects a Fulcio Cert to verify against. An -// optional rekorClient can also be given, if nil passed, default is assumed. -func validAttestationsWithFulcio(ctx context.Context, ref name.Reference, fulcioRoots *x509.CertPool, rekorClient *client.Rekor, identities []v1alpha1.Identity, opts ...ociremote.Option) ([]oci.Signature, error) { - ids := make([]cosign.Identity, len(identities)) - for i, id := range identities { - ids[i] = cosign.Identity{Issuer: id.Issuer, Subject: id.Subject, IssuerRegExp: id.IssuerRegExp, SubjectRegExp: id.SubjectRegExp} - } - - attestations, _, err := cosignVerifyAttestations(ctx, ref, &cosign.CheckOpts{ - RegistryClientOpts: opts, - RootCerts: fulcioRoots, - RekorClient: rekorClient, - ClaimVerifier: cosign.IntotoSubjectClaimVerifier, - Identities: ids, - }) +func validAttestations(ctx context.Context, ref name.Reference, checkOpts *cosign.CheckOpts) ([]oci.Signature, error) { + checkOpts.ClaimVerifier = cosign.IntotoSubjectClaimVerifier + attestations, _, err := cosignVerifyAttestations(ctx, ref, checkOpts) return attestations, err } diff --git a/pkg/webhook/validator.go b/pkg/webhook/validator.go index 528c1f03c..d56404aa1 100644 --- a/pkg/webhook/validator.go +++ b/pkg/webhook/validator.go @@ -16,7 +16,10 @@ package webhook import ( + "bytes" "context" + "crypto/ecdsa" + "crypto/x509" "encoding/json" "errors" "fmt" @@ -24,11 +27,10 @@ import ( "github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/authn/k8schain" - v1 "github.com/google/go-containerregistry/pkg/v1" - "github.com/google/go-containerregistry/pkg/v1/types" - "github.com/google/go-containerregistry/pkg/name" + v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/remote" + "github.com/google/go-containerregistry/pkg/v1/types" "github.com/sigstore/cosign/pkg/cosign" "github.com/sigstore/cosign/pkg/oci" ociremote "github.com/sigstore/cosign/pkg/oci/remote" @@ -36,12 +38,15 @@ import ( csigs "github.com/sigstore/cosign/pkg/signature" "github.com/sigstore/policy-controller/pkg/apis/config" policyduckv1beta1 "github.com/sigstore/policy-controller/pkg/apis/duck/v1beta1" + "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" policycontrollerconfig "github.com/sigstore/policy-controller/pkg/config" webhookcip "github.com/sigstore/policy-controller/pkg/webhook/clusterimagepolicy" rekor "github.com/sigstore/rekor/pkg/client" "github.com/sigstore/rekor/pkg/generated/client" + "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/fulcioroots" "github.com/sigstore/sigstore/pkg/signature" + "github.com/sigstore/sigstore/pkg/tuf" admissionv1 "k8s.io/api/admission/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -726,17 +731,11 @@ func attestationToPolicyAttestations(ctx context.Context, atts []attestation) [] func ValidatePolicySignaturesForAuthority(ctx context.Context, ref name.Reference, authority webhookcip.Authority, remoteOpts ...ociremote.Option) ([]PolicySignature, error) { name := authority.Name - var rekorClient *client.Rekor - var err error - if authority.CTLog != nil && authority.CTLog.URL != nil { - logging.FromContext(ctx).Debugf("Using CTLog %s for %s", authority.CTLog.URL, ref.Name()) - rekorClient, err = rekor.GetRekorClient(authority.CTLog.URL.String()) - if err != nil { - logging.FromContext(ctx).Errorf("failed creating rekor client: +v", err) - return nil, fmt.Errorf("creating Rekor client: %w", err) - } + checkOpts, err := checkOptsFromAuthority(ctx, authority, remoteOpts...) + if err != nil { + logging.FromContext(ctx).Errorf("failed constructing checkOpts for %s: +v", name, err) + return nil, fmt.Errorf("constructing checkOpts for %s: %w", name, err) } - switch { case authority.Key != nil: if len(authority.Key.PublicKeys) == 0 { @@ -746,7 +745,7 @@ func ValidatePolicySignaturesForAuthority(ctx context.Context, ref name.Referenc // Is it even allowed? 'valid' returns success if any key // matches. // https://github.com/sigstore/policy-controller/issues/1652 - sps, err := valid(ctx, ref, rekorClient, authority.Key.PublicKeys, authority.Key.HashAlgorithmCode, remoteOpts...) + sps, err := valid(ctx, ref, authority.Key.PublicKeys, authority.Key.HashAlgorithmCode, checkOpts) if err != nil { return nil, fmt.Errorf("signature key validation failed for authority %s for %s: %w", name, ref.Name(), err) } @@ -755,13 +754,7 @@ func ValidatePolicySignaturesForAuthority(ctx context.Context, ref name.Referenc case authority.Keyless != nil: if authority.Keyless.URL != nil { - // TODO: This will probably need to change for: - // https://github.com/sigstore/policy-controller/issues/138 - fulcioRoots, err := fulcioroots.Get() - if err != nil { - return nil, fmt.Errorf("fetching FulcioRoot: %w", err) - } - sps, err := validSignaturesWithFulcio(ctx, ref, fulcioRoots, rekorClient, authority.Keyless.Identities, remoteOpts...) + sps, err := validSignatures(ctx, ref, checkOpts) if err != nil { logging.FromContext(ctx).Errorf("failed validSignatures for authority %s with fulcio for %s: %v", name, ref.Name(), err) return nil, fmt.Errorf("signature keyless validation failed for authority %s for %s: %w", name, ref.Name(), err) @@ -781,15 +774,10 @@ func ValidatePolicySignaturesForAuthority(ctx context.Context, ref name.Referenc // verify attestations against it. func ValidatePolicyAttestationsForAuthority(ctx context.Context, ref name.Reference, authority webhookcip.Authority, remoteOpts ...ociremote.Option) (map[string][]PolicyAttestation, error) { name := authority.Name - var rekorClient *client.Rekor - var err error - if authority.CTLog != nil && authority.CTLog.URL != nil { - logging.FromContext(ctx).Debugf("Using CTLog %s for %s", authority.CTLog.URL, ref.Name()) - rekorClient, err = rekor.GetRekorClient(authority.CTLog.URL.String()) - if err != nil { - logging.FromContext(ctx).Errorf("failed creating rekor client: +v", err) - return nil, fmt.Errorf("creating Rekor client: %w", err) - } + checkOpts, err := checkOptsFromAuthority(ctx, authority, remoteOpts...) + if err != nil { + logging.FromContext(ctx).Errorf("failed creating checkopts client: %v", err) + return nil, fmt.Errorf("creating CheckOpts: %w", err) } verifiedAttestations := []oci.Signature{} @@ -801,7 +789,8 @@ func ValidatePolicyAttestationsForAuthority(ctx context.Context, ref name.Refere logging.FromContext(ctx).Errorf("error creating verifier: %v", err) return nil, fmt.Errorf("creating verifier: %w", err) } - va, err := validAttestations(ctx, ref, verifier, rekorClient, remoteOpts...) + checkOpts.SigVerifier = verifier + va, err := validAttestations(ctx, ref, checkOpts) if err != nil { logging.FromContext(ctx).Errorf("error validating attestations: %v", err) return nil, fmt.Errorf("attestation key validation failed for authority %s for %s: %w", name, ref.Name(), err) @@ -811,13 +800,7 @@ func ValidatePolicyAttestationsForAuthority(ctx context.Context, ref name.Refere case authority.Keyless != nil: if authority.Keyless != nil && authority.Keyless.URL != nil { - // TODO: This will probably need to change for: - // https://github.com/sigstore/policy-controller/issues/138 - fulcioRoots, err := fulcioroots.Get() - if err != nil { - return nil, fmt.Errorf("fetching FulcioRoot: %w", err) - } - va, err := validAttestationsWithFulcio(ctx, ref, fulcioRoots, rekorClient, authority.Keyless.Identities, remoteOpts...) + va, err := validAttestations(ctx, ref, checkOpts) if err != nil { logging.FromContext(ctx).Errorf("failed validAttestationsWithFulcio for authority %s with fulcio for %s: %v", name, ref.Name(), err) return nil, fmt.Errorf("attestation keyless validation failed for authority %s for %s: %w", name, ref.Name(), err) @@ -1263,3 +1246,184 @@ func normalizeArchitecture(cf *v1.ConfigFile) string { Variant: cf.Variant, }.String() } + +// checkOptsFromAuthority creates the necessary options for calling Cosign +// verify functions (signatures and attestations). +func checkOptsFromAuthority(ctx context.Context, authority webhookcip.Authority, remoteOpts ...ociremote.Option) (*cosign.CheckOpts, error) { + ret := &cosign.CheckOpts{ + RegistryClientOpts: remoteOpts, + } + + // Add in the identities for verification purposes, as well as Fulcio URL + // and certificates + if authority.Keyless != nil { + for _, id := range authority.Keyless.Identities { + ret.Identities = append(ret.Identities, + cosign.Identity{ + Issuer: id.Issuer, + Subject: id.Subject, + IssuerRegExp: id.IssuerRegExp, + SubjectRegExp: id.SubjectRegExp}) + } + fulcioRoots, fulcioIntermediates, err := fulcioCertsFromAuthority(ctx, authority.Keyless) + if err != nil { + return nil, fmt.Errorf("getting Fulcio certs: %s: %w", authority.Name, err) + } + ret.RootCerts = fulcioRoots + ret.IntermediateCerts = fulcioIntermediates + } + rekorClient, rekorPubKeys, err := rekorClientAndKeysFromAuthority(ctx, authority.CTLog) + if err != nil { + return nil, fmt.Errorf("getting Rekor public keys: %s: %w", authority.Name, err) + } + ret.RekorClient = rekorClient + ret.RekorPubKeys = rekorPubKeys + // Skip the TLog verification if we have no client or keys to validate + // against. + if ret.RekorClient == nil { + if ret.RekorPubKeys == nil { + ret.SkipTlogVerify = true + } else { + // If there's keys however, use offline for verification. + ret.Offline = true + } + } + return ret, nil +} + +func sigstoreKeysFromContext(ctx context.Context, trustRootRef string) (*config.SigstoreKeysMap, error) { + config := config.FromContext(ctx) + if config == nil { + // No config, can't fetch certificates, bail. + return nil, fmt.Errorf("trustRootRef %s not found, config missing", trustRootRef) + } + if config.SigstoreKeysConfig == nil { + // No config, can't fetch keys, bail. + return nil, fmt.Errorf("trustRootRef %s not found, SigstoreKeys missing", trustRootRef) + } + return config.SigstoreKeysConfig, nil +} + +// fulcioCertsFromAuthority gets the necessary Fulcio certificates, this is +// rootPool and an optional intermediatePool. +// Preference is given to TrustRoot if specified, from which the certificates +// are fetched and returned. If there's no TrustRoot, the certificates are +// fetched from embedded or cached TUF root. +func fulcioCertsFromAuthority(ctx context.Context, keylessRef *webhookcip.KeylessRef) (*x509.CertPool, *x509.CertPool, error) { + // If this is not Keyless, there's no Fulcio, so just return + if keylessRef.TrustRootRef == "" { + roots, err := fulcioroots.Get() + if err != nil { + return nil, nil, fmt.Errorf("failed to fetch Fulcio roots: %w", err) + } + intermediates, err := fulcioroots.GetIntermediates() + if err != nil { + return nil, nil, fmt.Errorf("failed to fetch Fulcio intermediates: %w", err) + } + return roots, intermediates, nil + } + + // There's TrustRootRef, so fetch it + trustRootRef := keylessRef.TrustRootRef + sigstoreKeys, err := sigstoreKeysFromContext(ctx, trustRootRef) + if err != nil { + return nil, nil, fmt.Errorf("getting SigstoreKeys: %w", err) + } + rootCertsPool := x509.NewCertPool() + intermediateCertsPool := x509.NewCertPool() + + if sk, ok := sigstoreKeys.SigstoreKeys[trustRootRef]; ok { + for _, ca := range sk.CertificateAuthorities { + certs, err := cryptoutils.UnmarshalCertificatesFromPEM(ca.CertChain) + if err != nil { + return nil, nil, fmt.Errorf("error unmarshalling certificates: %w", err) + } + for _, cert := range certs { + // root certificates are self-signed + if bytes.Equal(cert.RawSubject, cert.RawIssuer) { + rootCertsPool.AddCert(cert) + } else { + intermediateCertsPool.AddCert(cert) + } + } + } + return rootCertsPool, intermediateCertsPool, nil + } + return nil, nil, fmt.Errorf("trustRootRef %s not found", trustRootRef) +} + +// rekorClientAndKeysFromAuthority creates a Rekor client that should be used +// and public keys to go with it. +// Note that if Rekor is not specified, it's not an error and nil will be +// returned for it. +// Preference is given to TrustRoot if specified, from which the URL and public +// keys are fetched and returned. If there's no TrustRoot but a URL, then +// a Rekor client is returned and the keys from the embedded or cached TUF root. +func rekorClientAndKeysFromAuthority(ctx context.Context, tlog *v1alpha1.TLog) (*client.Rekor, *cosign.TrustedRekorPubKeys, error) { + if tlog == nil { + return nil, nil, nil + } + if tlog.TrustRootRef != "" { + trustRootRef := tlog.TrustRootRef + rekorPubKeys, rekorURL, err := rekorKeysFromTrustRef(ctx, trustRootRef) + if err != nil { + return nil, nil, fmt.Errorf("fetching keys for trustRootRef: %w", err) + } + rekorClient, err := rekor.GetRekorClient(rekorURL) + if err != nil { + logging.FromContext(ctx).Errorf("failed creating rekor client: %v", err) + return nil, nil, fmt.Errorf("creating Rekor client: %w", err) + } + return rekorClient, rekorPubKeys, nil + } + + // No TrustRoot, so see if there's one specified in the authority and if + // not just return that no Rekor is to be used. + if tlog.URL == nil { + return nil, nil, nil + } + rekorClient, err := rekor.GetRekorClient(tlog.URL.String()) + if err != nil { + logging.FromContext(ctx).Errorf("failed creating rekor client: %v", err) + return nil, nil, fmt.Errorf("creating Rekor client: %w", err) + } + rekorPubKeys, err := cosign.GetRekorPubs(ctx) + if err != nil { + logging.FromContext(ctx).Errorf("failed getting rekor public keys: %v", err) + return nil, nil, fmt.Errorf("getting Rekor public keys: %w", err) + } + return rekorClient, rekorPubKeys, nil +} + +func rekorKeysFromTrustRef(ctx context.Context, trustRootRef string) (*cosign.TrustedRekorPubKeys, string, error) { + sigstoreKeys, err := sigstoreKeysFromContext(ctx, trustRootRef) + if err != nil { + return nil, "", fmt.Errorf("getting SigstoreKeys: %w", err) + } + + if sk, ok := sigstoreKeys.SigstoreKeys[trustRootRef]; ok { + retKeys := &cosign.TrustedRekorPubKeys{ + Keys: make(map[string]cosign.RekorPubKey, len(sk.TLogs)), + } + rekorURL := "" + for i, tlog := range sk.TLogs { + pk, err := cryptoutils.UnmarshalPEMToPublicKey(tlog.PublicKey) + if err != nil { + return nil, "", fmt.Errorf("unmarshaling public key %d failed: %w", i, err) + } + // This needs to be ecdsa instead of crypto.PublicKey + // https://github.com/sigstore/cosign/issues/2540 + pkecdsa, ok := pk.(*ecdsa.PublicKey) + if !ok { + return nil, "", fmt.Errorf("public key %d is not ecdsa.PublicKey", i) + } + retKeys.Keys[tlog.LogID] = cosign.RekorPubKey{ + PubKey: pkecdsa, + Status: tuf.Active, + } + rekorURL = tlog.BaseURL.String() + } + return retKeys, rekorURL, nil + } + return nil, "", fmt.Errorf("trustRootRef %s not found", trustRootRef) +} diff --git a/pkg/webhook/validator_test.go b/pkg/webhook/validator_test.go index 73e3c370b..18aa8ff8c 100644 --- a/pkg/webhook/validator_test.go +++ b/pkg/webhook/validator_test.go @@ -47,6 +47,9 @@ import ( "github.com/sigstore/policy-controller/pkg/apis/signaturealgo" policycontrollerconfig "github.com/sigstore/policy-controller/pkg/config" webhookcip "github.com/sigstore/policy-controller/pkg/webhook/clusterimagepolicy" + "github.com/sigstore/sigstore/pkg/cryptoutils" + "github.com/sigstore/sigstore/pkg/fulcioroots" + "github.com/sigstore/sigstore/pkg/tuf" admissionv1 "k8s.io/api/admission/v1" batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" @@ -71,6 +74,49 @@ const ( MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENAyijLvRu5QpCPp2uOj8C79ZW1VJ SID/4H61ZiRzN4nqONzp+ZF22qQTk3MFO3D0/ZKmWHAosIf2pf2GHH7myA== -----END PUBLIC KEY-----` + + certChain = `-----BEGIN CERTIFICATE----- +MIIBzDCCAXKgAwIBAgIUfyGKDoFa7y6s/W1p1CiTmBRs1eAwCgYIKoZIzj0EAwIw +MDEOMAwGA1UEChMFbG9jYWwxHjAcBgNVBAMTFVRlc3QgVFNBIEludGVybWVkaWF0 +ZTAeFw0yMjExMDkyMDMxMzRaFw0zMTExMDkyMDM0MzRaMDAxDjAMBgNVBAoTBWxv +Y2FsMR4wHAYDVQQDExVUZXN0IFRTQSBUaW1lc3RhbXBpbmcwWTATBgcqhkjOPQIB +BggqhkjOPQMBBwNCAAR3KcDy9jwARX0rDvyr+MGGkG3n1OA0MU5+ZiDmgusFyk6U +6bovKWVMfD8J8NTcJZE0RaYJr8/dE9kgcIIXlhMwo2owaDAOBgNVHQ8BAf8EBAMC +B4AwHQYDVR0OBBYEFHNn5R3b3MtUdSNrFO49Q6XDVSnkMB8GA1UdIwQYMBaAFNLS +6gno7Om++Qt5zIa+H9o0HiT2MBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMAoGCCqG +SM49BAMCA0gAMEUCIQCF0olohnvdUq6T7/wPk19Z5aQP/yxRTjCWYuhn/TCyHgIg +azV3air4GRZbN9bdYtcQ7JUAKq89GOhtFfl6kcoVUvU= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIB0jCCAXigAwIBAgIUXpBmYJFFaGW3cC8p6b/DHr1i8IowCgYIKoZIzj0EAwIw +KDEOMAwGA1UEChMFbG9jYWwxFjAUBgNVBAMTDVRlc3QgVFNBIFJvb3QwHhcNMjIx +MTA5MjAyOTM0WhcNMzIxMTA5MjAzNDM0WjAwMQ4wDAYDVQQKEwVsb2NhbDEeMBwG +A1UEAxMVVGVzdCBUU0EgSW50ZXJtZWRpYXRlMFkwEwYHKoZIzj0CAQYIKoZIzj0D +AQcDQgAEKDPDRIwDS1ZCymub6yanCG5ma0qDjLpNonDvooSkRHEgU0TNibeJn6M+ +5W608hCw8nwuucMbXQ41kNeuBeevyqN4MHYwDgYDVR0PAQH/BAQDAgEGMBMGA1Ud +JQQMMAoGCCsGAQUFBwMIMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNLS6gno +7Om++Qt5zIa+H9o0HiT2MB8GA1UdIwQYMBaAFB1nvXpNK7AuQlbJ+ya6nPSqWi+T +MAoGCCqGSM49BAMCA0gAMEUCIGiwqCI29w7C4V8TltCsi728s5DtklCPySDASUSu +a5y5AiEA40Ifdlwf7Uj8q8NSD6Z4g/0js0tGNdLSUJ1do/WoN0s= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIBlDCCATqgAwIBAgIUYZx9sS14En7SuHDOJJP4IPopMjUwCgYIKoZIzj0EAwIw +KDEOMAwGA1UEChMFbG9jYWwxFjAUBgNVBAMTDVRlc3QgVFNBIFJvb3QwHhcNMjIx +MTA5MjAyOTM0WhcNMzIxMTA5MjAzNDM0WjAoMQ4wDAYDVQQKEwVsb2NhbDEWMBQG +A1UEAxMNVGVzdCBUU0EgUm9vdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAbB +B0SU8G75hVIUphChA4nfOwNWP347TjScIdsEPrKVn+/Y1HmmLHJDjSfn+xhEFoEk +7jqgrqon48i4xbo7xAujQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBQdZ716TSuwLkJWyfsmupz0qlovkzAKBggqhkjOPQQDAgNI +ADBFAiBe5P56foqmFcZAVpEeAOFZrAlEiq05CCpMNYh5EjLvmAIhAKNF6xIV5uFd +pSTJsAwzjW78CKQm7qol0uPmPPu6mNaw +-----END CERTIFICATE----- +` + + rekorPublicKey = `-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7D2WvgqSzs9jpdJsOJ5Nl6xg8JXm +Nmo7M3bN7+dQddw9Ibc2R3SV8tzBZw0rST8FKcn4apJepcKM4qUpYUeNfw== +-----END PUBLIC KEY----- +` ) func TestValidatePodSpec(t *testing.T) { @@ -2735,3 +2781,423 @@ func TestPolicyControllerConfigNoMatchPolicy(t *testing.T) { } } } + +func TestFulcioCertsFromAuthority(t *testing.T) { + certs, err := cryptoutils.UnmarshalCertificatesFromPEM([]byte(certChain)) + if err != nil { + t.Fatalf("Failed to unmarshal certs for testing: %v", err) + } + + roots := x509.NewCertPool() + // last cert is the root + roots.AddCert(certs[2]) + intermediates := x509.NewCertPool() + intermediates.AddCert(certs[0]) + intermediates.AddCert(certs[1]) + + embeddedRoots, err := fulcioroots.Get() + if err != nil { + t.Fatalf("Failed to get embedded fulcioroots for testing") + } + embeddedIntermediates, err := fulcioroots.GetIntermediates() + if err != nil { + t.Fatalf("Failed to get embedded fulcioroots for testing") + } + + sk := config.SigstoreKeys{ + CertificateAuthorities: []config.CertificateAuthority{{ + Subject: config.DistinguishedName{ + Organization: "testorg", + CommonName: "testcommonname", + }, + CertChain: []byte(certChain), + }}, + } + c := &config.Config{ + SigstoreKeysConfig: &config.SigstoreKeysMap{ + SigstoreKeys: map[string]config.SigstoreKeys{ + "test-trust-root": sk, + }, + }, + } + testCtx := config.ToContext(context.Background(), c) + + tests := []struct { + name string + keylessRef *webhookcip.KeylessRef + wantErr string + wantRoots *x509.CertPool + wantIntermediates *x509.CertPool + ctx context.Context + }{{ + name: "no trustroots, uses embedded", + keylessRef: &webhookcip.KeylessRef{}, + wantRoots: embeddedRoots, + wantIntermediates: embeddedIntermediates, + }, { + name: "config does not exist", + keylessRef: &webhookcip.KeylessRef{TrustRootRef: "not-there"}, + wantErr: "getting SigstoreKeys: trustRootRef not-there not found, config missing", + ctx: config.ToContext(context.Background(), nil), + }, { + name: "SigstoreKeys does not exist", + keylessRef: &webhookcip.KeylessRef{TrustRootRef: "not-there"}, + wantErr: "getting SigstoreKeys: trustRootRef not-there not found, SigstoreKeys missing", + ctx: config.ToContext(context.Background(), &config.Config{}), + }, { + name: "trustroot does not exist", + keylessRef: &webhookcip.KeylessRef{TrustRootRef: "not-there"}, + ctx: testCtx, + wantErr: "trustRootRef not-there not found", + }, { + name: "trustroot found", + keylessRef: &webhookcip.KeylessRef{TrustRootRef: "test-trust-root"}, + ctx: testCtx, + wantRoots: roots, + wantIntermediates: intermediates, + }} + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + tCtx := tc.ctx + if tCtx == nil { + tCtx = context.Background() + } + roots, intermediates, err := fulcioCertsFromAuthority(tCtx, tc.keylessRef) + if err != nil { + if tc.wantErr == "" { + t.Errorf("unexpected error: %v wanted none", err) + } else if err.Error() != tc.wantErr { + t.Errorf("unexpected error: %v wanted %q", err, tc.wantErr) + } + } else if err == nil && tc.wantErr != "" { + t.Errorf("wanted error: %q got none", tc.wantErr) + } + if !roots.Equal(tc.wantRoots) { + t.Errorf("Roots differ") + } + if !intermediates.Equal(tc.wantIntermediates) { + t.Errorf("Intermediates differ") + } + }) + } +} + +func TestRekorClientAndKeysFromAuthority(t *testing.T) { + pk, err := cryptoutils.UnmarshalPEMToPublicKey([]byte(rekorPublicKey)) + if err != nil { + t.Fatalf("Failed to unmarshal public key for testing: %v", err) + } + ecpk, ok := pk.(*ecdsa.PublicKey) + if !ok { + t.Fatalf("pk is not a ecsda public key") + } + + embeddedPKs, err := cosign.GetRekorPubs(context.Background()) + if err != nil { + t.Fatalf("Failed to get embedded rekor pubs for testing") + } + if len(embeddedPKs.Keys) != 1 { + t.Fatalf("Did not get a single Public Key for Rekor") + } + var embeddedLogID string + var embeddedPK *ecdsa.PublicKey + for k, v := range embeddedPKs.Keys { + embeddedLogID = k + embeddedPK = v.PubKey + } + + sk := config.SigstoreKeys{ + TLogs: []config.TransparencyLogInstance{{ + PublicKey: []byte(rekorPublicKey), + LogID: "rekor-logid", + BaseURL: *apis.HTTPS("rekor.example.com"), + }}, + } + c := &config.Config{ + SigstoreKeysConfig: &config.SigstoreKeysMap{ + SigstoreKeys: map[string]config.SigstoreKeys{ + "test-trust-root": sk, + }, + }, + } + testCtx := config.ToContext(context.Background(), c) + + tests := []struct { + name string + tlog *v1alpha1.TLog + wantErr string + wantPK *ecdsa.PublicKey + wantLogID string + wantClient bool + ctx context.Context + }{{ + name: "no trustroots, uses embedded", + tlog: &v1alpha1.TLog{URL: apis.HTTPS("rekor.sigstore.dev")}, + wantPK: embeddedPK, + wantLogID: embeddedLogID, + wantClient: true, + }, { + + name: "config does not exist", + tlog: &v1alpha1.TLog{TrustRootRef: "not-there"}, + wantErr: "fetching keys for trustRootRef: getting SigstoreKeys: trustRootRef not-there not found, config missing", + ctx: config.ToContext(context.Background(), nil), + }, { + name: "SigstoreKeys does not exist", + tlog: &v1alpha1.TLog{TrustRootRef: "not-there"}, + wantErr: "fetching keys for trustRootRef: getting SigstoreKeys: trustRootRef not-there not found, SigstoreKeys missing", + ctx: config.ToContext(context.Background(), &config.Config{}), + }, { + name: "trustroot does not exist", + tlog: &v1alpha1.TLog{TrustRootRef: "not-there"}, + ctx: testCtx, + wantErr: "fetching keys for trustRootRef: trustRootRef not-there not found", + }, { + name: "trustroot found", + tlog: &v1alpha1.TLog{TrustRootRef: "test-trust-root"}, + wantPK: ecpk, + wantLogID: "rekor-logid", + ctx: testCtx, + wantClient: true, + }} + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + tCtx := tc.ctx + if tCtx == nil { + tCtx = context.Background() + } + rekorClient, gotPKs, err := rekorClientAndKeysFromAuthority(tCtx, tc.tlog) + if err != nil { + if tc.wantErr == "" { + t.Errorf("unexpected error: %v wanted none", err) + } else if err.Error() != tc.wantErr { + t.Errorf("unexpected error: %v wanted %q", err, tc.wantErr) + } + } else if err == nil && tc.wantErr != "" { + t.Errorf("wanted error: %q got none", tc.wantErr) + } + if tc.wantLogID != "" { + if gotPKs == nil || gotPKs.Keys == nil { + t.Errorf("Wanted logid %s got none", tc.wantLogID) + } else if !tc.wantPK.Equal(gotPKs.Keys[tc.wantLogID].PubKey) { + t.Errorf("did not get wanted PK, want %+v got %+v", tc.wantPK, gotPKs.Keys[tc.wantLogID]) + } + } else if gotPKs != nil { + t.Errorf("did not want PK, %+v", gotPKs) + } + if tc.wantClient && rekorClient == nil { + t.Errorf("wanted rekor client, but got none") + } else if !tc.wantClient && rekorClient != nil { + t.Errorf("did not want rekor client, but got one") + } + }) + } +} + +func TestCheckOptsFromAuthority(t *testing.T) { + pk, err := cryptoutils.UnmarshalPEMToPublicKey([]byte(rekorPublicKey)) + if err != nil { + t.Fatalf("Failed to unmarshal public key for testing: %v", err) + } + ecpk, ok := pk.(*ecdsa.PublicKey) + if !ok { + t.Fatalf("pk is not a ecsda public key") + } + + embeddedPKs, err := cosign.GetRekorPubs(context.Background()) + if err != nil { + t.Fatalf("Failed to get embedded rekor pubs for testing") + } + if len(embeddedPKs.Keys) != 1 { + t.Fatalf("Did not get a single Public Key for Rekor") + } + var embeddedLogID string + var embeddedPK *ecdsa.PublicKey + for k, v := range embeddedPKs.Keys { + embeddedLogID = k + embeddedPK = v.PubKey + } + + certs, err := cryptoutils.UnmarshalCertificatesFromPEM([]byte(certChain)) + if err != nil { + t.Fatalf("Failed to unmarshal certs for testing: %v", err) + } + + roots := x509.NewCertPool() + // last cert is the root + roots.AddCert(certs[2]) + intermediates := x509.NewCertPool() + intermediates.AddCert(certs[0]) + intermediates.AddCert(certs[1]) + + embeddedRoots, err := fulcioroots.Get() + if err != nil { + t.Fatalf("Failed to get embedded fulcioroots for testing") + } + embeddedIntermediates, err := fulcioroots.GetIntermediates() + if err != nil { + t.Fatalf("Failed to get embedded fulcioroots for testing") + } + + skRekor := config.SigstoreKeys{ + TLogs: []config.TransparencyLogInstance{{ + PublicKey: []byte(rekorPublicKey), + LogID: "rekor-logid", + BaseURL: *apis.HTTPS("rekor.example.com"), + }}, + } + skFulcio := config.SigstoreKeys{ + CertificateAuthorities: []config.CertificateAuthority{{ + Subject: config.DistinguishedName{ + Organization: "testorg", + CommonName: "testcommonname", + }, + CertChain: []byte(certChain), + }}, + } + skCombined := config.SigstoreKeys{ + TLogs: []config.TransparencyLogInstance{{ + PublicKey: []byte(rekorPublicKey), + LogID: "rekor-logid", + BaseURL: *apis.HTTPS("rekor.example.com"), + }}, + CertificateAuthorities: []config.CertificateAuthority{{ + Subject: config.DistinguishedName{ + Organization: "testorg", + CommonName: "testcommonname", + }, + CertChain: []byte(certChain), + }}, + } + c := &config.Config{ + SigstoreKeysConfig: &config.SigstoreKeysMap{ + SigstoreKeys: map[string]config.SigstoreKeys{ + "test-trust-rekor": skRekor, + "test-trust-fulcio": skFulcio, + "test-trust-combined": skCombined, + }, + }, + } + testCtx := config.ToContext(context.Background(), c) + + tests := []struct { + name string + authority webhookcip.Authority + wantErr string + wantCheckOpts *cosign.CheckOpts + ctx context.Context + wantClient bool + }{{ + name: "no trustroots, uses embedded", + authority: webhookcip.Authority{ + CTLog: &v1alpha1.TLog{URL: apis.HTTPS("rekor.sigstore.dev")}, + Keyless: &webhookcip.KeylessRef{URL: apis.HTTPS("fulcio.sigstore.dev")}, + }, + wantCheckOpts: &cosign.CheckOpts{ + RekorPubKeys: &cosign.TrustedRekorPubKeys{Keys: map[string]cosign.RekorPubKey{embeddedLogID: {PubKey: embeddedPK, Status: tuf.Active}}}, + RootCerts: embeddedRoots, + IntermediateCerts: embeddedIntermediates, + }, + wantClient: true, + }, { + name: "SigstoreKeys does not exist for Rekor", + authority: webhookcip.Authority{ + Name: "test-authority", + CTLog: &v1alpha1.TLog{ + URL: apis.HTTPS("rekor.example.com"), + TrustRootRef: "not-there"}}, + wantErr: "getting Rekor public keys: test-authority: fetching keys for trustRootRef: trustRootRef not-there not found", + ctx: testCtx, + }, { + name: "SigstoreKeys does not exist for Fulcio", + authority: webhookcip.Authority{ + Name: "test-authority", + Keyless: &webhookcip.KeylessRef{ + URL: apis.HTTPS("fulcio.example.com"), + TrustRootRef: "not-there"}}, + wantErr: "getting Fulcio certs: test-authority: trustRootRef not-there not found", + ctx: testCtx, + }, { + name: "trustroot found, Rekor", + authority: webhookcip.Authority{ + CTLog: &v1alpha1.TLog{ + URL: apis.HTTPS("rekor.example.com"), + TrustRootRef: "test-trust-rekor"}}, + ctx: testCtx, + wantClient: true, + wantCheckOpts: &cosign.CheckOpts{ + RekorPubKeys: &cosign.TrustedRekorPubKeys{Keys: map[string]cosign.RekorPubKey{"rekor-logid": {PubKey: ecpk, Status: tuf.Active}}}, + }, + }, { + name: "trustroot found, Fulcio", + authority: webhookcip.Authority{ + Keyless: &webhookcip.KeylessRef{ + URL: apis.HTTPS("fulcio.example.com"), + TrustRootRef: "test-trust-fulcio"}}, + ctx: testCtx, + wantCheckOpts: &cosign.CheckOpts{ + RootCerts: roots, + IntermediateCerts: intermediates, + SkipTlogVerify: true, + }, + }, { + name: "trustroot found, combined, with Identities", + authority: webhookcip.Authority{ + CTLog: &v1alpha1.TLog{ + URL: apis.HTTPS("rekor.example.com"), + TrustRootRef: "test-trust-rekor"}, + Keyless: &webhookcip.KeylessRef{ + Identities: []v1alpha1.Identity{{ + Issuer: "issuer", + Subject: "subject", + }}, + URL: apis.HTTPS("rekor.example.com"), + TrustRootRef: "test-trust-combined"}}, + ctx: testCtx, + wantClient: true, + wantCheckOpts: &cosign.CheckOpts{ + RootCerts: roots, + IntermediateCerts: intermediates, + RekorPubKeys: &cosign.TrustedRekorPubKeys{Keys: map[string]cosign.RekorPubKey{"rekor-logid": {PubKey: ecpk, Status: tuf.Active}}}, + Identities: []cosign.Identity{{ + Issuer: "issuer", + Subject: "subject", + }}, + }, + }} + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + tCtx := tc.ctx + if tCtx == nil { + tCtx = context.Background() + } + gotCheckOpts, err := checkOptsFromAuthority(tCtx, tc.authority) + if err != nil { + if tc.wantErr == "" { + t.Errorf("unexpected error: %v wanted none", err) + } else if err.Error() != tc.wantErr { + t.Errorf("unexpected error: %v wanted %q", err, tc.wantErr) + } + } else if err == nil && tc.wantErr != "" { + t.Errorf("wanted error: %q got none", tc.wantErr) + } + if tc.wantClient && (gotCheckOpts == nil || gotCheckOpts.RekorClient == nil) { + t.Errorf("wanted rekor client, but got none") + } else if !tc.wantClient && gotCheckOpts != nil && gotCheckOpts.RekorClient != nil { + t.Errorf("did not want rekor client, but got one") + } + // nil out the rekorclient since we can't meaningfully diff it, and + // we check above that we get one when we expect one, and don't when + // we don't. + if gotCheckOpts != nil { + gotCheckOpts.RekorClient = nil + } + if diff := cmp.Diff(gotCheckOpts, tc.wantCheckOpts); diff != "" { + t.Errorf("CheckOpts differ: %s", diff) + } + }) + } +}