Skip to content

Commit

Permalink
Add generic preflight checks, add permission validation preflight check
Browse files Browse the repository at this point in the history
Signed-off-by: everettraven <[email protected]>
  • Loading branch information
everettraven authored and 100mik committed Feb 20, 2024
1 parent 70eb2c1 commit 63faf8a
Show file tree
Hide file tree
Showing 30 changed files with 3,033 additions and 15 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ require (
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.4.0
)

Expand Down
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84=
github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
Expand Down Expand Up @@ -245,6 +247,8 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
Expand Down Expand Up @@ -514,6 +518,8 @@ 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
16 changes: 14 additions & 2 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 @@ -27,6 +28,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/preflight"
ctlres "github.com/vmware-tanzu/carvel-kapp/pkg/kapp/resources"
ctlresm "github.com/vmware-tanzu/carvel-kapp/pkg/kapp/resourcesmisc"
)
Expand All @@ -50,11 +52,13 @@ type DeployOptions struct {
ResourceTypesFlags ResourceTypesFlags
LabelFlags LabelFlags

PreflightChecks *preflight.Registry

FileSystem fs.FS
}

func NewDeployOptions(ui ui.UI, depsFactory cmdcore.DepsFactory, logger logger.Logger) *DeployOptions {
return &DeployOptions{ui: ui, depsFactory: depsFactory, logger: logger}
func NewDeployOptions(ui ui.UI, depsFactory cmdcore.DepsFactory, logger logger.Logger, preflights *preflight.Registry) *DeployOptions {
return &DeployOptions{ui: ui, depsFactory: depsFactory, logger: logger, PreflightChecks: preflights}
}

func NewDeployCmd(o *DeployOptions, flagsFactory cmdcore.FlagsFactory) *cobra.Command {
Expand Down Expand Up @@ -91,6 +95,7 @@ func NewDeployCmd(o *DeployOptions, flagsFactory cmdcore.FlagsFactory) *cobra.Co
o.ResourceTypesFlags.Set(cmd)
o.LabelFlags.Set(cmd)
o.PrevAppFlags.Set(cmd)
o.PreflightChecks.AddFlags(cmd.Flags())

return cmd
}
Expand Down Expand Up @@ -194,6 +199,13 @@ func (o *DeployOptions) Run() error {
return nil
}

if o.PreflightChecks != nil {
err = o.PreflightChecks.Run(context.Background(), clusterChangesGraph)
if err != nil {
return fmt.Errorf("preflight checks failed: %w", err)
}
}

err = o.ui.AskForConfirmation()
if err != nil {
return err
Expand Down
2 changes: 1 addition & 1 deletion pkg/kapp/cmd/app/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func (o *LogsOptions) Run() error {
supportObjs.IdentifiedResources.PodResources(labelSelector, nil),
}

contFilter := func(pod corev1.Pod) []string {
contFilter := func(_ corev1.Pod) []string {
return o.LogsFlags.ContainerNames
}

Expand Down
15 changes: 9 additions & 6 deletions pkg/kapp/cmd/appgroup/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,18 @@ import (
cmdcore "github.com/vmware-tanzu/carvel-kapp/pkg/kapp/cmd/core"
cmdtools "github.com/vmware-tanzu/carvel-kapp/pkg/kapp/cmd/tools"
"github.com/vmware-tanzu/carvel-kapp/pkg/kapp/logger"
"github.com/vmware-tanzu/carvel-kapp/pkg/kapp/preflight"
)

type DeployOptions struct {
ui ui.UI
depsFactory cmdcore.DepsFactory
logger logger.Logger

AppGroupFlags Flags
DeployFlags DeployFlags
AppFlags DeployAppFlags
AppGroupFlags Flags
DeployFlags DeployFlags
AppFlags DeployAppFlags
PreflightChecks *preflight.Registry
}

type DeployAppFlags struct {
Expand All @@ -36,8 +38,8 @@ type DeployAppFlags struct {
LabelFlags cmdapp.LabelFlags
}

func NewDeployOptions(ui ui.UI, depsFactory cmdcore.DepsFactory, logger logger.Logger) *DeployOptions {
return &DeployOptions{ui: ui, depsFactory: depsFactory, logger: logger}
func NewDeployOptions(ui ui.UI, depsFactory cmdcore.DepsFactory, logger logger.Logger, preflights *preflight.Registry) *DeployOptions {
return &DeployOptions{ui: ui, depsFactory: depsFactory, logger: logger, PreflightChecks: preflights}
}

func NewDeployCmd(o *DeployOptions, flagsFactory cmdcore.FlagsFactory) *cobra.Command {
Expand All @@ -56,6 +58,7 @@ func NewDeployCmd(o *DeployOptions, flagsFactory cmdcore.FlagsFactory) *cobra.Co
o.AppFlags.DeleteApplyFlags.SetWithDefaults("delete", cmdapp.ApplyFlagsDeleteDefaults, cmd)
o.AppFlags.DeployFlags.Set(cmd)
o.AppFlags.LabelFlags.Set(cmd)
o.PreflightChecks.AddFlags(cmd.Flags())
return cmd
}

Expand Down Expand Up @@ -146,7 +149,7 @@ func (o *DeployOptions) deployApp(app appGroupApp) error {
o.ui.PrintLinef("--- deploying app '%s' (namespace: %s) from %s",
app.Name, o.appNamespace(), app.Path)

deployOpts := cmdapp.NewDeployOptions(o.ui, o.depsFactory, o.logger)
deployOpts := cmdapp.NewDeployOptions(o.ui, o.depsFactory, o.logger, o.PreflightChecks)
deployOpts.AppFlags = cmdapp.Flags{
Name: app.Name,
NamespaceFlags: o.AppGroupFlags.NamespaceFlags,
Expand Down
24 changes: 24 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,20 @@ 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/discovery/cached/memory"
"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 +88,25 @@ 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
}

cachedDisc := memory.NewMemCacheClient(disc)
mapper := restmapper.NewDeferredDiscoveryRESTMapper(cachedDisc)

f.printTarget(config)

return mapper, nil
}

func (f *DepsFactoryImpl) ConfigureWarnings(warnings bool) {
f.Warnings = warnings
}
Expand Down
23 changes: 18 additions & 5 deletions pkg/kapp/cmd/kapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import (
cmdsa "github.com/vmware-tanzu/carvel-kapp/pkg/kapp/cmd/serviceaccount"
cmdtools "github.com/vmware-tanzu/carvel-kapp/pkg/kapp/cmd/tools"
"github.com/vmware-tanzu/carvel-kapp/pkg/kapp/logger"
"github.com/vmware-tanzu/carvel-kapp/pkg/kapp/permissions"
"github.com/vmware-tanzu/carvel-kapp/pkg/kapp/preflight"
"github.com/vmware-tanzu/carvel-kapp/pkg/kapp/version"
)

Expand All @@ -32,23 +34,34 @@ type KappOptions struct {
KubeconfigFlags cmdcore.KubeconfigFlags
WarningFlags WarningFlags
ProfilingFlags ProfilingFlags

PreflightChecks *preflight.Registry
}

func NewKappOptions(ui *ui.ConfUI, configFactory cmdcore.ConfigFactory,
depsFactory cmdcore.DepsFactory) *KappOptions {
depsFactory cmdcore.DepsFactory, preflights *preflight.Registry) *KappOptions {

return &KappOptions{ui: ui, logger: logger.NewUILogger(ui),
configFactory: configFactory, depsFactory: depsFactory}
configFactory: configFactory, depsFactory: depsFactory, PreflightChecks: preflights}
}

func NewDefaultKappCmd(ui *ui.ConfUI) *cobra.Command {
configFactory := cmdcore.NewConfigFactoryImpl()
depsFactory := cmdcore.NewDepsFactoryImpl(configFactory, ui)
options := NewKappOptions(ui, configFactory, depsFactory)
preflights := defaultKappPreflightRegistry(depsFactory)
options := NewKappOptions(ui, configFactory, depsFactory, preflights)
flagsFactory := cmdcore.NewFlagsFactory(configFactory, depsFactory)
return NewKappCmd(options, flagsFactory)
}

func defaultKappPreflightRegistry(depsFactory cmdcore.DepsFactory) *preflight.Registry {
registry := preflight.NewRegistry(map[string]preflight.Check{
"PermissionValidation": permissions.NewPreflight(depsFactory, false),
})

return registry
}

func NewKappCmd(o *KappOptions, flagsFactory cmdcore.FlagsFactory) *cobra.Command {
cmd := &cobra.Command{
Use: "kapp",
Expand Down Expand Up @@ -95,15 +108,15 @@ func NewKappCmd(o *KappOptions, flagsFactory cmdcore.FlagsFactory) *cobra.Comman

cmd.AddCommand(cmdapp.NewListCmd(cmdapp.NewListOptions(o.ui, o.depsFactory, o.logger), flagsFactory))
cmd.AddCommand(cmdapp.NewInspectCmd(cmdapp.NewInspectOptions(o.ui, o.depsFactory, o.logger), flagsFactory))
cmd.AddCommand(cmdapp.NewDeployCmd(cmdapp.NewDeployOptions(o.ui, o.depsFactory, o.logger), flagsFactory))
cmd.AddCommand(cmdapp.NewDeployCmd(cmdapp.NewDeployOptions(o.ui, o.depsFactory, o.logger, o.PreflightChecks), flagsFactory))
cmd.AddCommand(cmdapp.NewDeployConfigCmd(cmdapp.NewDeployConfigOptions(o.ui, o.depsFactory), flagsFactory))
cmd.AddCommand(cmdapp.NewDeleteCmd(cmdapp.NewDeleteOptions(o.ui, o.depsFactory, o.logger), flagsFactory))
cmd.AddCommand(cmdapp.NewRenameCmd(cmdapp.NewRenameOptions(o.ui, o.depsFactory, o.logger), flagsFactory))
cmd.AddCommand(cmdapp.NewLogsCmd(cmdapp.NewLogsOptions(o.ui, o.depsFactory, o.logger), flagsFactory))
cmd.AddCommand(cmdapp.NewLabelCmd(cmdapp.NewLabelOptions(o.ui, o.depsFactory, o.logger), flagsFactory))

agCmd := cmdag.NewCmd()
agCmd.AddCommand(cmdag.NewDeployCmd(cmdag.NewDeployOptions(o.ui, o.depsFactory, o.logger), flagsFactory))
agCmd.AddCommand(cmdag.NewDeployCmd(cmdag.NewDeployOptions(o.ui, o.depsFactory, o.logger, o.PreflightChecks), flagsFactory))
agCmd.AddCommand(cmdag.NewDeleteCmd(cmdag.NewDeleteOptions(o.ui, o.depsFactory, o.logger), flagsFactory))
cmd.AddCommand(agCmd)

Expand Down
47 changes: 47 additions & 0 deletions pkg/kapp/permissions/basic.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright 2024 VMware, Inc.
// SPDX-License-Identifier: Apache-2.0

package permissions

import (
"context"

ctlres "github.com/vmware-tanzu/carvel-kapp/pkg/kapp/resources"
authv1 "k8s.io/api/authorization/v1"
"k8s.io/apimachinery/pkg/api/meta"
authv1client "k8s.io/client-go/kubernetes/typed/authorization/v1"
)

// BasicValidator is a basic validator useful for
// validating basic CRUD permissions for resources. It has no knowledge
// of how to handle permission evaluation for specific
// GroupVersionKinds
type BasicValidator struct {
ssarClient authv1client.SelfSubjectAccessReviewInterface
mapper meta.RESTMapper
}

var _ Validator = (*BasicValidator)(nil)

func NewBasicValidator(ssarClient authv1client.SelfSubjectAccessReviewInterface, mapper meta.RESTMapper) *BasicValidator {
return &BasicValidator{
ssarClient: ssarClient,
mapper: mapper,
}
}

func (bv *BasicValidator) Validate(ctx context.Context, res ctlres.Resource, verb string) error {
mapping, err := bv.mapper.RESTMapping(res.GroupKind(), res.GroupVersion().Version)
if err != nil {
return err
}

return ValidatePermissions(ctx, bv.ssarClient, &authv1.ResourceAttributes{
Group: mapping.Resource.Group,
Version: mapping.Resource.Version,
Resource: mapping.Resource.Resource,
Namespace: res.Namespace(),
Name: res.Name(),
Verb: verb,
})
}
Loading

0 comments on commit 63faf8a

Please sign in to comment.