Skip to content

Commit

Permalink
(wip): Add permission validation option to kapp deploy subcommand
Browse files Browse the repository at this point in the history
Signed-off-by: everettraven <[email protected]>
  • Loading branch information
everettraven committed Feb 6, 2024
1 parent 9edad25 commit 924d763
Show file tree
Hide file tree
Showing 12 changed files with 1,659 additions and 14 deletions.
7 changes: 4 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ require (
github.com/vmware-tanzu/carvel-kapp-controller v0.46.2
golang.org/x/net v0.20.0
gopkg.in/yaml.v2 v2.4.0
k8s.io/api v0.29.0
k8s.io/apimachinery v0.29.0
k8s.io/client-go v0.29.0
k8s.io/api v0.29.1
k8s.io/apimachinery v0.29.1
k8s.io/client-go v0.29.1
k8s.io/component-helpers v0.29.1
sigs.k8s.io/yaml v1.3.0
)

Expand Down
18 changes: 10 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -437,8 +437,8 @@ golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss=
golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA=
golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down Expand Up @@ -509,12 +509,14 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
k8s.io/api v0.29.0 h1:NiCdQMY1QOp1H8lfRyeEf8eOwV6+0xA6XEE44ohDX2A=
k8s.io/api v0.29.0/go.mod h1:sdVmXoz2Bo/cb77Pxi71IPTSErEW32xa4aXwKH7gfBA=
k8s.io/apimachinery v0.29.0 h1:+ACVktwyicPz0oc6MTMLwa2Pw3ouLAfAon1wPLtG48o=
k8s.io/apimachinery v0.29.0/go.mod h1:eVBxQ/cwiJxH58eK/jd/vAk4mrxmVlnpBH5J2GbMeis=
k8s.io/client-go v0.29.0 h1:KmlDtFcrdUzOYrBhXHgKw5ycWzc3ryPX5mQe0SkG3y8=
k8s.io/client-go v0.29.0/go.mod h1:yLkXH4HKMAywcrD82KMSmfYg2DlE8mepPR4JGSo5n38=
k8s.io/api v0.29.1 h1:DAjwWX/9YT7NQD4INu49ROJuZAAAP/Ijki48GUPzxqw=
k8s.io/api v0.29.1/go.mod h1:7Kl10vBRUXhnQQI8YR/R327zXC8eJ7887/+Ybta+RoQ=
k8s.io/apimachinery v0.29.1 h1:KY4/E6km/wLBguvCZv8cKTeOwwOBqFNjwJIdMkMbbRc=
k8s.io/apimachinery v0.29.1/go.mod h1:6HVkd1FwxIagpYrHSwJlQqZI3G9LfYWRPAkUvLnXTKU=
k8s.io/client-go v0.29.1 h1:19B/+2NGEwnFLzt0uB5kNJnfTsbV8w6TgQRz9l7ti7A=
k8s.io/client-go v0.29.1/go.mod h1:TDG/psL9hdet0TI9mGyHJSgRkW3H9JZk2dNEUS7bRks=
k8s.io/component-helpers v0.29.1 h1:54MMEDu6xeJmMtAKztsPwu0kJKr4+jCUzaEIn2UXRoc=
k8s.io/component-helpers v0.29.1/go.mod h1:+I7xz4kfUgxWAPJIVKrqe4ml4rb9UGpazlOmhXYo+cY=
k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0=
k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo=
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780=
Expand Down
55 changes: 55 additions & 0 deletions pkg/kapp/cmd/app/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package app

import (
"context"
"fmt"
"io/fs"
"os"
Expand All @@ -13,6 +14,7 @@ import (
"github.com/cppforlife/go-cli-ui/ui"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/kubernetes"
Expand All @@ -27,6 +29,7 @@ import (
ctldiffui "github.com/vmware-tanzu/carvel-kapp/pkg/kapp/diffui"
"github.com/vmware-tanzu/carvel-kapp/pkg/kapp/logger"
ctllogs "github.com/vmware-tanzu/carvel-kapp/pkg/kapp/logs"
"github.com/vmware-tanzu/carvel-kapp/pkg/kapp/permissions"
ctlres "github.com/vmware-tanzu/carvel-kapp/pkg/kapp/resources"
ctlresm "github.com/vmware-tanzu/carvel-kapp/pkg/kapp/resourcesmisc"
)
Expand Down Expand Up @@ -172,6 +175,13 @@ func (o *DeployOptions) Run() error {
return err
}

if o.DeployFlags.ValidatePermissions {
err = o.validatePermissionsForChangeset(clusterChangesGraph)
if err != nil {
return err
}
}

// Validate new resources _after_ presenting changes to make it easier to see big picture
err = prep.ValidateResources(newResources)
if err != nil {
Expand Down Expand Up @@ -572,3 +582,48 @@ func (o *DeployOptions) presentDiffUI(graph *ctldgraph.ChangeGraph) error {
}
return ctldiffui.NewServer(opts, o.ui).Run()
}

func (o *DeployOptions) validatePermissionsForChangeset(changeGraph *ctldgraph.ChangeGraph) error {
client, err := o.depsFactory.CoreClient()
if err != nil {
return err
}

mapper, err := o.depsFactory.RESTMapper()
if err != nil {
return err
}

roleValidator := permissions.NewRoleValidator(client.AuthorizationV1().SelfSubjectAccessReviews(), mapper)
basicValidator := permissions.NewBasicValidator(client.AuthorizationV1().SelfSubjectAccessReviews(), mapper)

validator := permissions.NewCompositeValidator(basicValidator, map[schema.GroupVersionKind]permissions.Validator{
rbacv1.SchemeGroupVersion.WithKind("Role"): roleValidator,
rbacv1.SchemeGroupVersion.WithKind("ClusterRole"): roleValidator,
})

for _, change := range changeGraph.All() {
switch change.Change.Op() {
case ctldgraph.ActualChangeOpDelete:
err = validator.Validate(context.Background(), change.Change.Resource(), "delete")
if err != nil {
return err
}
case ctldgraph.ActualChangeOpUpsert:
// Check both create and update permissions
err = validator.Validate(context.Background(), change.Change.Resource(), "create")
if err != nil {
return err
}

err = validator.Validate(context.Background(), change.Change.Resource(), "update")
if err != nil {
return err
}

// TODO: should check patch permissions?
}
}

return nil
}
5 changes: 5 additions & 0 deletions pkg/kapp/cmd/app/deploy_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ type DeployFlags struct {
LogsAll bool
AppMetadataFile string

ValidatePermissions bool

DisableGKScoping bool
}

Expand Down Expand Up @@ -60,4 +62,7 @@ func (s *DeployFlags) Set(cmd *cobra.Command) {

cmd.Flags().BoolVar(&s.DisableGKScoping, "dangerous-disable-gk-scoping",
false, "Disable scoping of resource searching to used GroupKinds")

cmd.Flags().BoolVar(&s.ValidatePermissions, "validate-permissions",
false, "Validate permissions before attempting to apply changes to the cluster")
}
27 changes: 27 additions & 0 deletions pkg/kapp/cmd/core/deps_factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,19 @@ import (
"sync"

"github.com/cppforlife/go-cli-ui/ui"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/discovery"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/restmapper"
)

type DepsFactory interface {
DynamicClient(opts DynamicClientOpts) (dynamic.Interface, error)
CoreClient() (kubernetes.Interface, error)
RESTMapper() (meta.RESTMapper, error)
ConfigureWarnings(warnings bool)
}

Expand Down Expand Up @@ -83,6 +87,29 @@ func (f *DepsFactoryImpl) CoreClient() (kubernetes.Interface, error) {
return clientset, nil
}

func (f *DepsFactoryImpl) RESTMapper() (meta.RESTMapper, error) {
config, err := f.configFactory.RESTConfig()
if err != nil {
return nil, err
}

disc, err := discovery.NewDiscoveryClientForConfig(config)
if err != nil {
return nil, err
}

groupResources, err := restmapper.GetAPIGroupResources(disc)
if err != nil {
return nil, err
}

mapper := restmapper.NewDiscoveryRESTMapper(groupResources)

f.printTarget(config)

return mapper, nil
}

func (f *DepsFactoryImpl) ConfigureWarnings(warnings bool) {
f.Warnings = warnings
}
Expand Down
Loading

0 comments on commit 924d763

Please sign in to comment.