policy: add default policy for buildkit-syft-scanner images
Extends the builtin default policy to verify docker-github-builder signatures on docker/buildkit-syft-scanner images. Tags `latest` and 1.10+ require a signature from the docker/buildkit-syft-scanner source repository; older tags pass through unchanged. Factors the shared ref matching logic into sig_ref_matches for dockerfile and introduces a syft-scanner variant that uses the plain refs/tags/ prefix. Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
+46
-3
@@ -5,6 +5,7 @@ package docker
|
||||
#
|
||||
# - docker/dockerfile
|
||||
# - docker/dockerfile-upstream
|
||||
# - docker/buildkit-syft-scanner
|
||||
#
|
||||
# Any image outside this managed set is allowed and passes through to user
|
||||
# policies unchanged. Access by digest is always allowed. For tag-based
|
||||
@@ -22,6 +23,11 @@ is_dockerfile if {
|
||||
input.image.fullRepo == "docker.io/docker/dockerfile-upstream"
|
||||
}
|
||||
|
||||
is_syft_scanner if {
|
||||
input.image
|
||||
input.image.fullRepo == "docker.io/docker/buildkit-syft-scanner"
|
||||
}
|
||||
|
||||
dockerfile_floating_tag(tag) if tag == "latest"
|
||||
dockerfile_floating_tag(tag) if tag == "labs"
|
||||
dockerfile_floating_tag(tag) if tag == "master"
|
||||
@@ -29,6 +35,11 @@ dockerfile_floating_tag(tag) if tag == "master"
|
||||
dockerfile_tag_requires_sig(tag) if dockerfile_floating_tag(tag)
|
||||
dockerfile_tag_requires_sig(tag) if version_tag_ge(tag, 1, 21)
|
||||
|
||||
syft_scanner_floating_tag(tag) if tag == "latest"
|
||||
|
||||
syft_scanner_tag_requires_sig(tag) if syft_scanner_floating_tag(tag)
|
||||
syft_scanner_tag_requires_sig(tag) if version_tag_ge(tag, 1, 10)
|
||||
|
||||
|
||||
default_policy_deny_msgs contains msg if {
|
||||
is_dockerfile
|
||||
@@ -39,6 +50,15 @@ default_policy_deny_msgs contains msg if {
|
||||
msg := sprintf("image %s is not allowed by default policy: a verified docker-github-builder signature is required for %s tag", [input.image.ref, input.image.tag])
|
||||
}
|
||||
|
||||
default_policy_deny_msgs contains msg if {
|
||||
is_syft_scanner
|
||||
tag := input.image.tag
|
||||
tag != ""
|
||||
syft_scanner_tag_requires_sig(tag)
|
||||
not syft_scanner_sig_ok(tag)
|
||||
msg := sprintf("image %s is not allowed by default policy: a verified docker-github-builder signature is required for %s tag", [input.image.ref, input.image.tag])
|
||||
}
|
||||
|
||||
dockerfile_sig_ok(tag) if {
|
||||
dockerfile_floating_tag(tag)
|
||||
some sig in input.image.signatures
|
||||
@@ -52,6 +72,19 @@ dockerfile_sig_ok(tag) if {
|
||||
dockerfile_sig_ref_matches(sig, tag)
|
||||
}
|
||||
|
||||
syft_scanner_sig_ok(tag) if {
|
||||
syft_scanner_floating_tag(tag)
|
||||
some sig in input.image.signatures
|
||||
docker_github_builder_signature(sig, "docker/buildkit-syft-scanner")
|
||||
}
|
||||
|
||||
syft_scanner_sig_ok(tag) if {
|
||||
not syft_scanner_floating_tag(tag)
|
||||
some sig in input.image.signatures
|
||||
docker_github_builder_signature(sig, "docker/buildkit-syft-scanner")
|
||||
syft_scanner_sig_ref_matches(sig, tag)
|
||||
}
|
||||
|
||||
|
||||
decision := {
|
||||
"allow": count(default_policy_deny_msgs) == 0,
|
||||
@@ -89,14 +122,24 @@ version_tag_ge(tag, target_major, target_minor) if {
|
||||
}
|
||||
|
||||
dockerfile_sig_ref_matches(sig, tag) if {
|
||||
ref := trim_prefix(sig.signer.sourceRepositoryRef, "refs/tags/dockerfile/")
|
||||
sig_ref_matches(sig.signer.sourceRepositoryRef, tag, "refs/tags/dockerfile/")
|
||||
}
|
||||
|
||||
syft_scanner_sig_ref_matches(sig, tag) if {
|
||||
ref := trim_prefix(sig.signer.sourceRepositoryRef, "refs/tags/")
|
||||
ref != sig.signer.sourceRepositoryRef
|
||||
version_tag_selector_matches(tag, ref)
|
||||
}
|
||||
|
||||
sig_ref_matches(ref, tag, prefix) if {
|
||||
stripped_ref := trim_prefix(ref, prefix)
|
||||
stripped_ref != ref
|
||||
tag_labs := endswith(tag, "-labs")
|
||||
ref_labs := endswith(ref, "-labs")
|
||||
ref_labs := endswith(stripped_ref, "-labs")
|
||||
tag_labs == ref_labs
|
||||
version_tag_selector_matches(
|
||||
trim_suffix(tag, "-labs"),
|
||||
trim_suffix(ref, "-labs"),
|
||||
trim_suffix(stripped_ref, "-labs"),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -306,3 +306,97 @@ func TestDefaultPolicyImages(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultPolicySyftScannerImages(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
sig *policytypes.SignatureInfo
|
||||
ref string
|
||||
allow bool
|
||||
denyMsg string
|
||||
}{
|
||||
{
|
||||
name: "syft_scanner_old_version_allowed_unsigned",
|
||||
ref: "docker/buildkit-syft-scanner:1.9.0",
|
||||
allow: true,
|
||||
},
|
||||
{
|
||||
name: "syft_scanner_new_version_requires_signature",
|
||||
ref: "docker/buildkit-syft-scanner:1.10.0",
|
||||
denyMsg: "signature is required for 1.10.0 tag",
|
||||
},
|
||||
{
|
||||
name: "syft_scanner_new_minor_version_requires_signature",
|
||||
ref: "docker/buildkit-syft-scanner:1.10",
|
||||
denyMsg: "signature is required for 1.10 tag",
|
||||
},
|
||||
{
|
||||
name: "syft_scanner_new_major_version_requires_signature",
|
||||
ref: "docker/buildkit-syft-scanner:1",
|
||||
denyMsg: "signature is required for 1 tag",
|
||||
},
|
||||
{
|
||||
name: "syft_scanner_new_version_allowed_with_matching_signature",
|
||||
sig: dockerGithubBuilderSig("docker/buildkit-syft-scanner", "refs/tags/1.10.0"),
|
||||
ref: "docker/buildkit-syft-scanner:1.10.0",
|
||||
allow: true,
|
||||
},
|
||||
{
|
||||
name: "syft_scanner_new_minor_version_allowed_with_matching_patch_signature",
|
||||
sig: dockerGithubBuilderSig("docker/buildkit-syft-scanner", "refs/tags/1.10.0"),
|
||||
ref: "docker/buildkit-syft-scanner:1.10",
|
||||
allow: true,
|
||||
},
|
||||
{
|
||||
name: "syft_scanner_new_major_version_allowed_with_matching_minor_signature",
|
||||
sig: dockerGithubBuilderSig("docker/buildkit-syft-scanner", "refs/tags/1.10.0"),
|
||||
ref: "docker/buildkit-syft-scanner:1",
|
||||
allow: true,
|
||||
},
|
||||
{
|
||||
name: "syft_scanner_new_version_denied_with_wrong_signature_repo",
|
||||
sig: dockerGithubBuilderSig("moby/buildkit", "refs/tags/1.10.0"),
|
||||
ref: "docker/buildkit-syft-scanner:1.10.0",
|
||||
denyMsg: "signature is required for 1.10.0 tag",
|
||||
},
|
||||
{
|
||||
name: "syft_scanner_new_version_denied_with_mismatched_ref",
|
||||
sig: dockerGithubBuilderSig("docker/buildkit-syft-scanner", "refs/tags/1.11.0"),
|
||||
ref: "docker/buildkit-syft-scanner:1.10.0",
|
||||
denyMsg: "signature is required for 1.10.0 tag",
|
||||
},
|
||||
{
|
||||
name: "syft_scanner_new_minor_version_denied_with_newer_patch_ref",
|
||||
sig: dockerGithubBuilderSig("docker/buildkit-syft-scanner", "refs/tags/1.11.0"),
|
||||
ref: "docker/buildkit-syft-scanner:1.10",
|
||||
denyMsg: "signature is required for 1.10 tag",
|
||||
},
|
||||
{
|
||||
name: "syft_scanner_latest_allowed_with_signature_any_ref",
|
||||
sig: dockerGithubBuilderSig("docker/buildkit-syft-scanner", "refs/tags/1.10.0"),
|
||||
ref: "docker/buildkit-syft-scanner:latest",
|
||||
allow: true,
|
||||
},
|
||||
{
|
||||
name: "syft_scanner_latest_denied_without_signature",
|
||||
ref: "docker/buildkit-syft-scanner:latest",
|
||||
denyMsg: "signature is required for latest tag",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
p := makeDefaultPolicy(t, tc.sig)
|
||||
resp := runDefaultPolicyImage(t, p, tc.ref)
|
||||
if tc.allow {
|
||||
require.Equal(t, moby_buildkit_v1_sourcepolicy.PolicyAction_ALLOW, resp.Action)
|
||||
require.Empty(t, resp.DenyMessages)
|
||||
return
|
||||
}
|
||||
|
||||
require.Equal(t, moby_buildkit_v1_sourcepolicy.PolicyAction_DENY, resp.Action)
|
||||
require.Len(t, resp.DenyMessages, 1)
|
||||
require.Contains(t, resp.DenyMessages[0].Message, tc.denyMsg)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user