Skip to content
This repository has been archived by the owner on Mar 16, 2024. It is now read-only.

change: adjustments to support ImageRoleBindings in Manager #2118

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion integration/client/signatures/rules_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ func TestImageAllowRules(t *testing.T) {
assert.Error(t, err, "should error since image is not covered by images scope of IAR")

// update image allow rule to cover that image
iar.Images = []string{tagName}
iar.Images = []string{"**"}
Copy link
Contributor

Choose a reason for hiding this comment

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

Why this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I will merge that change away with #2113 👍


err = kclient.Update(ctx, iar)
if err != nil {
Expand Down
103 changes: 51 additions & 52 deletions pkg/imageallowrules/imageallowrules.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,73 +106,74 @@ func CheckImageAgainstRules(ctx context.Context, c client.Reader, namespace stri
iarLoop:
for _, imageAllowRule := range imageAllowRules {
// Check if the image is in scope of the ImageAllowRule
if !imageCovered(ref, digest, imageAllowRule) {
if !ImageCovered(ref, digest, imageAllowRule.Images) {
logrus.Infof("Image %s (%s) is not covered by ImageAllowRule %s/%s: %#v", image, digest, imageAllowRule.Namespace, imageAllowRule.Name, imageAllowRule.Images)
continue
}

// > Signatures
// Any verification error or failed verification issue will skip on to the next IAR
for _, rule := range imageAllowRule.Signatures.Rules {
if err := cosign.EnsureReferences(ctx, c, image, namespace, &verifyOpts); err != nil {
logrus.Infof("failed checking image %s against %s/%s.signatures: %v", image, imageAllowRule.Namespace, imageAllowRule.Name, err)
if err := VerifySignatureRule(ctx, c, namespace, image, rule, verifyOpts); err != nil {
logrus.Errorf("Verification failed for %s against %s/%s: %v", image, imageAllowRule.Namespace, imageAllowRule.Name, err)
iwilltry42 marked this conversation as resolved.
Show resolved Hide resolved
iwilltry42 marked this conversation as resolved.
Show resolved Hide resolved
continue iarLoop
}
verifyOpts.AnnotationRules = rule.Annotations

// allOf: all signatures must pass verification
if len(rule.SignedBy.AllOf) != 0 {
for allOfRuleIndex, signer := range rule.SignedBy.AllOf {
logrus.Debugf("Checking image %s against %s/%s.signatures.allOf.%d", image, imageAllowRule.Namespace, imageAllowRule.Name, allOfRuleIndex)
verifyOpts.Key = signer
err := cosign.VerifySignature(ctx, verifyOpts)
if err != nil {
if _, ok := err.(*ocosign.VerificationError); !ok {
logrus.Errorf("error verifying image %s against %s/%s.signatures.allOf.%d: %v", image, imageAllowRule.Namespace, imageAllowRule.Name, allOfRuleIndex, err)
}
continue iarLoop // failed or errored in allOf, try next IAR
}
}
logrus.Debugf("Image %s (%s) is allowed by ImageAllowRule %s/%s", image, digest, imageAllowRule.Namespace, imageAllowRule.Name)
return nil
}
return &ErrImageNotAllowed{Image: image}
}

func VerifySignatureRule(ctx context.Context, c client.Reader, namespace string, image string, rule v1.SignatureRules, verifyOpts cosign.VerifyOpts) error {
if err := cosign.EnsureReferences(ctx, c, image, namespace, &verifyOpts); err != nil {
return fmt.Errorf(".signatures: %w", err)
}
verifyOpts.AnnotationRules = rule.Annotations

// allOf: all signatures must pass verification
if len(rule.SignedBy.AllOf) != 0 {
for allOfRuleIndex, signer := range rule.SignedBy.AllOf {
verifyOpts.Key = signer
err := cosign.VerifySignature(ctx, verifyOpts)
if err != nil {
if _, ok := err.(*ocosign.VerificationError); !ok {
return fmt.Errorf(".signatures.allOf.%d: %w", allOfRuleIndex, err)
}
return err // failed or errored in allOf, try next IAR
}
// anyOf: only one signature must pass verification
var anyOfErrs []error
if len(rule.SignedBy.AnyOf) != 0 {
anyOfOK := false
for anyOfRuleIndex, signer := range rule.SignedBy.AnyOf {
logrus.Debugf("Checking image %s against %s/%s.signatures.anyOf.%d", image, imageAllowRule.Namespace, imageAllowRule.Name, anyOfRuleIndex)
verifyOpts.Key = signer
err := cosign.VerifySignature(ctx, verifyOpts)
if err == nil {
anyOfOK = true
break
} else {
if _, ok := err.(*ocosign.VerificationError); ok {
logrus.Debugf("image %s not allowed as per %s/%s.signatures.anyOf.%d: %v", image, imageAllowRule.Namespace, imageAllowRule.Name, anyOfRuleIndex, err)
} else {
e := fmt.Errorf("error verifying image %s against %s/%s.signatures.anyOf.%d: %w", image, imageAllowRule.Namespace, imageAllowRule.Name, anyOfRuleIndex, err)
anyOfErrs = append(anyOfErrs, e)
logrus.Errorln(e.Error())
}
}
}
if !anyOfOK {
if len(anyOfErrs) == len(rule.SignedBy.AnyOf) {
// we had errors for all anyOf rules (not failed verification, but actual errors)
e := fmt.Errorf("error verifying image %s against %s/%s.signatures.anyOf.*: %w", image, imageAllowRule.Namespace, imageAllowRule.Name, merr.NewErrors(anyOfErrs...))
logrus.Errorln(e.Error())
}
continue iarLoop // failed or errored in all anyOf, try next IAR
}
}
// anyOf: only one signature must pass verification
var anyOfErrs []error
if len(rule.SignedBy.AnyOf) != 0 {
anyOfOK := false
for anyOfRuleIndex, signer := range rule.SignedBy.AnyOf {
verifyOpts.Key = signer
err := cosign.VerifySignature(ctx, verifyOpts)
if err == nil {
anyOfOK = true
break
} else {
if _, ok := err.(*ocosign.VerificationError); !ok {
e := fmt.Errorf(".signatures.anyOf.%d: %w", anyOfRuleIndex, err)
anyOfErrs = append(anyOfErrs, e)
}
}
}

return nil
if !anyOfOK {
if len(anyOfErrs) == len(rule.SignedBy.AnyOf) {
// we had errors for all anyOf rules (not failed verification, but actual errors)
return fmt.Errorf(".signatures.anyOf.*: %w", merr.NewErrors(anyOfErrs...))
}
return fmt.Errorf(".signature.anyOf: failed") // failed or errored in all anyOf, try next IAR
}
}
return &ErrImageNotAllowed{Image: image}
return nil
}

func imageCovered(image name.Reference, digest string, iar v1.ImageAllowRuleInstance) bool {
for _, pattern := range iar.Images {
func ImageCovered(image name.Reference, digest string, patterns []string) bool {
for _, pattern := range patterns {
// empty pattern? skip (should've been caught by IAR validation already)
if strings.TrimSpace(pattern) == "" {
continue
Expand All @@ -198,13 +199,11 @@ func imageCovered(image name.Reference, digest string, iar v1.ImageAllowRuleInst
}

if err := matchContext(contextPattern, image.Context().String()); err != nil {
logrus.Debugf("image %s not in scope of ImageAllowRule %s/%s: %v", image, iar.Namespace, iar.Name, err)
continue
}

if tagPattern != "" {
if err := matchTag(tagPattern, image.Identifier()); err != nil {
logrus.Debugf("image %s not in scope of ImageAllowRule %s/%s: %v", image, iar.Namespace, iar.Name, err)
continue
}
}
Expand Down
10 changes: 1 addition & 9 deletions pkg/imageallowrules/imageallowrules_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@ package imageallowrules
import (
"testing"

v1 "github.com/acorn-io/runtime/pkg/apis/internal.acorn.io/v1"
"github.com/google/go-containerregistry/pkg/name"
"github.com/stretchr/testify/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func TestImageCovered(t *testing.T) {
Expand Down Expand Up @@ -91,13 +89,7 @@ func TestImageCovered(t *testing.T) {
t.Fatalf("failed to parse image %s: %v", tc.image, err)
}

match := imageCovered(ref, "", v1.ImageAllowRuleInstance{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: "testns",
},
Images: []string{tc.pattern},
})
match := ImageCovered(ref, "", []string{tc.pattern})

assert.Equal(t, tc.shouldMatch, match)
})
Expand Down