Skip to content

Commit

Permalink
change: adjustments to support ImageRoleBindings in Manager (acorn-io…
Browse files Browse the repository at this point in the history
  • Loading branch information
iwilltry42 authored and cloudnautique committed Sep 28, 2023
1 parent a0f2d21 commit 0745999
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 62 deletions.
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{"**"}

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)
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

0 comments on commit 0745999

Please sign in to comment.