mirror of
https://github.com/moby/buildkit.git
synced 2026-11-06 05:16:45 +00:00
Merge pull request #7304 from crazy-max/gha-cache-tlog-threshold
remotecache: honor gha cache transparency log threshold
This commit is contained in:
9 files changed
+67
-21
No files matched your search
Vendored
+6
-11
@@ -364,7 +364,12 @@ func verifySignature(ctx context.Context, dgst digest.Digest, bundle []byte, con
|
||||
return errors.New("no verifier available for signed github actions cache")
|
||||
}
|
||||
|
||||
sig, err := v.VerifyArtifact(ctx, dgst, bundle, policy.WithSLSANotRequired())
|
||||
policyRules := config.Verify.Policy
|
||||
opts := []policy.ArtifactVerifyOpt{policy.WithSLSANotRequired()}
|
||||
if policyRules.TlogThreshold != nil {
|
||||
opts = append(opts, policy.WithTlogThreshold(*policyRules.TlogThreshold))
|
||||
}
|
||||
sig, err := v.VerifyArtifact(ctx, dgst, bundle, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -372,19 +377,9 @@ func verifySignature(ctx context.Context, dgst digest.Digest, bundle []byte, con
|
||||
return errors.New("signature verification failed: no signer found")
|
||||
}
|
||||
numTimestamps := len(sig.Timestamps)
|
||||
numTlog := 0
|
||||
for _, t := range sig.Timestamps {
|
||||
if t.Type == "Tlog" {
|
||||
numTlog++
|
||||
}
|
||||
}
|
||||
policyRules := config.Verify.Policy
|
||||
if policyRules.TimestampThreshold > numTimestamps {
|
||||
return errors.Errorf("signature verification failed: not enough timestamp authorities: have %d, need %d", numTimestamps, policyRules.TimestampThreshold)
|
||||
}
|
||||
if policyRules.TlogThreshold > numTlog {
|
||||
return errors.Errorf("signature verification failed: not enough tlog authorities: have %d, need %d", numTlog, policyRules.TlogThreshold)
|
||||
}
|
||||
|
||||
certRules, err := certToStringMap(&config.Verify.Policy.Summary)
|
||||
if err != nil {
|
||||
|
||||
Vendored
+20
@@ -9,13 +9,33 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/moby/buildkit/cache/remotecache/gha/ghatypes"
|
||||
"github.com/moby/buildkit/client"
|
||||
"github.com/moby/buildkit/client/llb"
|
||||
"github.com/moby/buildkit/util/testutil/integration"
|
||||
"github.com/moby/buildkit/util/testutil/workers"
|
||||
policy "github.com/moby/policy-helpers"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestVerifySignatureNegativeTlogThreshold(t *testing.T) {
|
||||
config := &Config{
|
||||
CacheConfig: &ghatypes.CacheConfig{
|
||||
Verify: ghatypes.VerifyConfig{
|
||||
Policy: ghatypes.VerifyPolicy{
|
||||
TlogThreshold: new(-1),
|
||||
},
|
||||
},
|
||||
},
|
||||
verifier: func() (*policy.Verifier, error) {
|
||||
return &policy.Verifier{}, nil
|
||||
},
|
||||
}
|
||||
err := verifySignature(t.Context(), digest.FromString("cache index"), nil, config)
|
||||
require.EqualError(t, err, "transparency log threshold must not be negative")
|
||||
}
|
||||
|
||||
func init() {
|
||||
if workers.IsTestDockerd() {
|
||||
workers.InitDockerdWorker()
|
||||
|
||||
+2
-2
@@ -17,7 +17,7 @@ type VerifyConfig struct {
|
||||
}
|
||||
|
||||
type VerifyPolicy struct {
|
||||
TimestampThreshold int `toml:"timestampThreshold"`
|
||||
TlogThreshold int `toml:"tlogThreshold"`
|
||||
TimestampThreshold int `toml:"timestampThreshold"`
|
||||
TlogThreshold *int `toml:"tlogThreshold"`
|
||||
certificate.Summary
|
||||
}
|
||||
@@ -267,6 +267,8 @@ provenanceEnvDir = "/etc/buildkit/provenance.d"
|
||||
#
|
||||
# [cache.gha.verify.policy]
|
||||
# timestampThreshold = 1
|
||||
# # If omitted, require all distinct transparency logs present in the bundle.
|
||||
# # Zero skips log verification and requires a verified TSA timestamp instead.
|
||||
# tlogThreshold = 1
|
||||
# # certificate properties that need to match. Simple wildcards (*) are supported.
|
||||
# certificateIssuer = ""
|
||||
|
||||
@@ -53,7 +53,7 @@ require (
|
||||
github.com/moby/go-archive v0.2.0
|
||||
github.com/moby/locker v1.0.1
|
||||
github.com/moby/patternmatcher v0.6.1
|
||||
github.com/moby/policy-helpers v0.0.0-20261006174519-bd98f4747414
|
||||
github.com/moby/policy-helpers v0.0.0-20261022152518-485a1bec29f6
|
||||
github.com/moby/profiles/seccomp v0.2.4
|
||||
github.com/moby/sys/mountinfo v0.7.2
|
||||
github.com/moby/sys/reexec v0.1.0
|
||||
|
||||
@@ -374,8 +374,8 @@ github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
|
||||
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
|
||||
github.com/moby/patternmatcher v0.6.1 h1:qlhtafmr6kgMIJjKJMDmMWq7WLkKIo23hsrpR3x084U=
|
||||
github.com/moby/patternmatcher v0.6.1/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
|
||||
github.com/moby/policy-helpers v0.0.0-20261006174519-bd98f4747414 h1:gOgxy0eXQlhvC5hB7CE+tJLLzrC9+gjTWlU+Bv5T8Ck=
|
||||
github.com/moby/policy-helpers v0.0.0-20261006174519-bd98f4747414/go.mod h1:hNMdiq4WjSmuyvy8lWcflH6erzSg/MgZlFyM7vC7Z2c=
|
||||
github.com/moby/policy-helpers v0.0.0-20261022152518-485a1bec29f6 h1:EROY4N1iyUx4awd7c2JtGnca7F9PhBU8+lJR/YejbYM=
|
||||
github.com/moby/policy-helpers v0.0.0-20261022152518-485a1bec29f6/go.mod h1:hNMdiq4WjSmuyvy8lWcflH6erzSg/MgZlFyM7vC7Z2c=
|
||||
github.com/moby/profiles/seccomp v0.2.4 h1:CNKIR4jNYCGIdstSZ3plN/yF3WCqlupmNLwO1ckLwz4=
|
||||
github.com/moby/profiles/seccomp v0.2.4/go.mod h1:H3JkVP4MWq+Q87sSWRUEdiZvK52WErUbcxr+mJHKVoM=
|
||||
github.com/moby/sys/mount v0.3.5 h1:eS3fsZTjHaBihwjp4/+5Z3jxqLXYsbwxqpVSfFv3M00=
|
||||
|
||||
+3
-3
@@ -87,11 +87,11 @@ target "vendor" {
|
||||
output = ["."]
|
||||
}
|
||||
|
||||
target "mod-outdated" {
|
||||
target "gomod-updates" {
|
||||
inherits = ["_common"]
|
||||
dockerfile = "./hack/dockerfiles/vendor.Dockerfile"
|
||||
target = "outdated"
|
||||
no-cache-filter = ["outdated"]
|
||||
target = "gomod-updates"
|
||||
no-cache-filter = ["gomod-updates"]
|
||||
output = ["type=cacheonly"]
|
||||
}
|
||||
|
||||
|
||||
+30
-1
@@ -52,6 +52,9 @@ func (v *Verifier) VerifyArtifact(ctx context.Context, dgst digest.Digest, bundl
|
||||
for _, o := range opt {
|
||||
o(opts)
|
||||
}
|
||||
if opts.TlogThreshold != nil && *opts.TlogThreshold < 0 {
|
||||
return nil, errors.New("transparency log threshold must not be negative")
|
||||
}
|
||||
|
||||
anyCert, err := anyCerificateIdentity()
|
||||
if err != nil {
|
||||
@@ -78,7 +81,23 @@ func (v *Verifier) VerifyArtifact(ctx context.Context, dgst digest.Digest, bundl
|
||||
return nil, errors.Wrap(err, "getting trusted root")
|
||||
}
|
||||
|
||||
gv, err := verify.NewVerifier(trustedRoot, verify.WithSignedCertificateTimestamps(1), verify.WithTransparencyLog(1), verify.WithObserverTimestamps(1))
|
||||
verifierOpts := []verify.VerifierOption{
|
||||
verify.WithSignedCertificateTimestamps(1),
|
||||
verify.WithObserverTimestamps(1),
|
||||
}
|
||||
// Sigstore thresholds count distinct logs, not individual entries.
|
||||
logIDs := make(map[string]struct{})
|
||||
for _, entry := range b.GetVerificationMaterial().GetTlogEntries() {
|
||||
logIDs[string(entry.GetLogId().GetKeyId())] = struct{}{}
|
||||
}
|
||||
tlogThreshold := len(logIDs)
|
||||
if opts.TlogThreshold != nil {
|
||||
tlogThreshold = *opts.TlogThreshold
|
||||
}
|
||||
if tlogThreshold > 0 {
|
||||
verifierOpts = append(verifierOpts, verify.WithTransparencyLog(tlogThreshold))
|
||||
}
|
||||
gv, err := verify.NewVerifier(trustedRoot, verifierOpts...)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "creating verifier")
|
||||
}
|
||||
@@ -368,6 +387,7 @@ func anyCerificateIdentity() (verify.PolicyOption, error) {
|
||||
|
||||
type ArtifactVerifyOpts struct {
|
||||
SLSANotRequired bool
|
||||
TlogThreshold *int
|
||||
}
|
||||
|
||||
type ArtifactVerifyOpt func(*ArtifactVerifyOpts)
|
||||
@@ -378,6 +398,15 @@ func WithSLSANotRequired() ArtifactVerifyOpt {
|
||||
}
|
||||
}
|
||||
|
||||
// WithTlogThreshold sets the minimum number of verified transparency logs.
|
||||
// By default, all distinct logs in the bundle are required. Explicit zero skips
|
||||
// log verification and returns no log timestamps, so a TSA timestamp is required.
|
||||
func WithTlogThreshold(threshold int) ArtifactVerifyOpt {
|
||||
return func(o *ArtifactVerifyOpts) {
|
||||
o.TlogThreshold = &threshold
|
||||
}
|
||||
}
|
||||
|
||||
func loadBundle(dt []byte) (*bundle.Bundle, error) {
|
||||
var bundle bundle.Bundle
|
||||
bundle.Bundle = new(protobundle.Bundle)
|
||||
|
||||
Vendored
+1
-1
@@ -815,7 +815,7 @@ github.com/moby/locker
|
||||
## explicit; go 1.19
|
||||
github.com/moby/patternmatcher
|
||||
github.com/moby/patternmatcher/ignorefile
|
||||
# github.com/moby/policy-helpers v0.0.0-20261006174519-bd98f4747414
|
||||
# github.com/moby/policy-helpers v0.0.0-20261022152518-485a1bec29f6
|
||||
## explicit; go 1.25.8
|
||||
github.com/moby/policy-helpers
|
||||
github.com/moby/policy-helpers/image
|
||||
|
||||
Reference in new issue
Block a user