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

Commit

Permalink
Merge pull request #2218 from thedadams/new-ira-bump-apps
Browse files Browse the repository at this point in the history
Re-evaluate image permissions for failing apps
  • Loading branch information
thedadams committed Oct 4, 2023
2 parents 8901f73 + 1007f03 commit 23cb51d
Show file tree
Hide file tree
Showing 12 changed files with 303 additions and 144 deletions.
36 changes: 19 additions & 17 deletions integration/client/imagerules/imageroleauthorizations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package imagerules

import (
"context"
_ "embed"
"os"
"strings"
"testing"

"github.com/acorn-io/baaah/pkg/apply"
"github.com/acorn-io/runtime/integration/helper"
adminv1 "github.com/acorn-io/runtime/pkg/apis/admin.acorn.io/v1"
apiv1 "github.com/acorn-io/runtime/pkg/apis/api.acorn.io/v1"
Expand All @@ -21,8 +23,6 @@ import (
rbacv1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
cclient "sigs.k8s.io/controller-runtime/pkg/client"

_ "embed"
)

//go:embed testdata/nested-perms/Acornfile
Expand Down Expand Up @@ -237,15 +237,17 @@ func TestImageRoleAuthorizations(t *testing.T) {
Name: "test",
Namespace: c.GetNamespace(),
},
ImageSelector: internalv1.ImageSelector{
NamePatterns: []string{"foobar"}, // does not cover the image
},
Roles: internaladminv1.RoleAuthorizations{
Scopes: []string{"project"},
RoleRefs: []internaladminv1.RoleRef{
{
Name: "foo:bar:admin", // required by rootapp
Kind: "Role", // current namespace only
Spec: internaladminv1.ImageRoleAuthorizationInstanceSpec{
ImageSelector: internalv1.ImageSelector{
NamePatterns: []string{"foobar"}, // does not cover the image
},
Roles: internaladminv1.RoleAuthorizations{
Scopes: []string{"project"},
RoleRefs: []internaladminv1.RoleRef{
{
Name: "foo:bar:admin", // required by rootapp
Kind: "Role", // current namespace only
},
},
},
},
Expand All @@ -263,12 +265,12 @@ func TestImageRoleAuthorizations(t *testing.T) {
// --------------------------------------------------------------------
// Run #3 - Expect denied permissions since we have an IRA but it does only cover one api group
// --------------------------------------------------------------------
ira.ImageSelector.NamePatterns = []string{tagName, nestedImageTagName}
err = kclient.Update(ctx, ira)
ira.Spec.ImageSelector.NamePatterns = []string{tagName, nestedImageTagName}
err = apply.Ensure(ctx, kclient, ira)
require.NoError(t, err, "should not error while updating IRA")

// Ensure that the selector matches the image now
err = imageselector.MatchImage(ctx, kclient, c.GetNamespace(), tagName, id, image.Digest, ira.ImageSelector, imageselector.MatchImageOpts{})
err = imageselector.MatchImage(ctx, kclient, c.GetNamespace(), tagName, id, image.Digest, ira.Spec.ImageSelector, imageselector.MatchImageOpts{})
require.NoError(t, err, "should not error while matching image")

details, err = c.ImageDetails(ctx, id, &client.ImageDetailsOptions{IncludeNested: true})
Expand Down Expand Up @@ -335,15 +337,15 @@ func TestImageRoleAuthorizations(t *testing.T) {
require.NoError(t, err, "should not error while creating aws role")

// Add the missing api group to the IRA
ira.Roles.RoleRefs = append(ira.Roles.RoleRefs, internaladminv1.RoleRef{
ira.Spec.Roles.RoleRefs = append(ira.Spec.Roles.RoleRefs, internaladminv1.RoleRef{
Name: awspermissions.AWSAdminRole, // required by foo.awsapp
Kind: "Role",
})
err = kclient.Update(ctx, ira)
err = apply.Ensure(ctx, kclient, ira)
require.NoError(t, err, "should not error while updating IRA")

// Ensure that the selector matches the image now
err = imageselector.MatchImage(ctx, kclient, c.GetNamespace(), nestedImageTagName, "", nestedImage.Digest, ira.ImageSelector, imageselector.MatchImageOpts{})
err = imageselector.MatchImage(ctx, kclient, c.GetNamespace(), nestedImageTagName, "", nestedImage.Digest, ira.Spec.ImageSelector, imageselector.MatchImageOpts{})
require.NoError(t, err, "should not error while matching image")

app = createWaitLoop(ctx, blueprint.DeepCopy())
Expand Down
8 changes: 4 additions & 4 deletions pkg/apis/admin.acorn.io/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,19 @@ type ImageRoleAuthorizationInstance struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

Spec ImageRoleAuthorizationInstanceSpec `json:"spec,omitempty"`
Status ImageRoleAuthorizationInstanceStatus `json:"status,omitempty"`
}

type ImageRoleAuthorizationInstanceSpec struct {
ImageSelector internalv1.ImageSelector `json:"imageSelector,omitempty"`
Roles RoleAuthorizations `json:"roles,omitempty"`
}

type ImageRoleAuthorizationInstanceStatus struct {
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

type ImageRoleAuthorizationInstanceList struct {
Expand Down
40 changes: 36 additions & 4 deletions pkg/apis/internal.admin.acorn.io/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

70 changes: 70 additions & 0 deletions pkg/controller/permissions/ira.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package permissions

import (
"errors"

"github.com/acorn-io/baaah/pkg/router"
v1 "github.com/acorn-io/runtime/pkg/apis/internal.acorn.io/v1"
adminv1 "github.com/acorn-io/runtime/pkg/apis/internal.admin.acorn.io/v1"
"github.com/acorn-io/runtime/pkg/imageselector"
kclient "github.com/acorn-io/runtime/pkg/k8sclient"
"github.com/acorn-io/runtime/pkg/labels"
)

// BumpImageRoleAuthorizations will bump the failing apps covered by an image role authorization such that the app will
// be re-evaluated for image permissions.
func BumpImageRoleAuthorizations(req router.Request, _ router.Response) error {
return bumpAppsForIRA(req, req.Object.(*adminv1.ImageRoleAuthorizationInstance))
}

// BumpClusterImageRoleAuthorizations will bump the failing apps covered by a cluster image role authorization such that
// the app will be re-evaluated for image permissions.
func BumpClusterImageRoleAuthorizations(req router.Request, _ router.Response) error {
return bumpAppsForIRA(req, (*adminv1.ImageRoleAuthorizationInstance)(req.Object.(*adminv1.ClusterImageRoleAuthorizationInstance)))
}

func bumpAppsForIRA(req router.Request, ira *adminv1.ImageRoleAuthorizationInstance) error {
// Only name patterns should be considered for re-evaluation, not signatures.
nameSelectorOnly := v1.ImageSelector{
NamePatterns: ira.Spec.ImageSelector.NamePatterns,
}

apps := new(v1.AppInstanceList)
if err := req.List(apps, &kclient.ListOptions{
Namespace: ira.Namespace,
}); err != nil {
return err
}

for _, app := range apps.Items {
// If the app's image permissions were granted, then no need to re-evaluate those permissions
if len(app.Status.Staged.ImagePermissionsDenied) == 0 {
continue
}

imageName := app.Status.AppImage.Name

// E.g. for child Acorns, the appImage.Name is the image ID, but we need the original image name (with registry/repo)
// to check for the signatures
if oi, ok := app.GetAnnotations()[labels.AcornOriginalImage]; ok {
imageName = oi
}

err := imageselector.MatchImage(req.Ctx, req.Client, app.Namespace, imageName, "", app.Status.AppImage.Digest, nameSelectorOnly, imageselector.MatchImageOpts{})
if ierr := (*imageselector.NoMatchError)(nil); errors.As(err, &ierr) {
// If this app is not covered by the image role authorization, then no need to re-evaluate permissions
continue
} else if err != nil {
return err
}

// The app is covered by the image role authorization, so reset the observed generation so permissions are re-evaluated.
app.Status.Staged.PermissionsObservedGeneration = -1
if err := req.Client.Status().Update(req.Ctx, &app); err != nil {
return err
}
}

ira.Status.ObservedGeneration = ira.Generation
return nil
}

0 comments on commit 23cb51d

Please sign in to comment.