Skip to content

Commit

Permalink
adding generateVAP field and generate-vapbinding
Browse files Browse the repository at this point in the history
Signed-off-by: Jaydip Gabani <[email protected]>
  • Loading branch information
JaydipGabani committed Jul 1, 2024
1 parent fbb014b commit 019c8a7
Show file tree
Hide file tree
Showing 20 changed files with 229 additions and 354 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ require (
github.com/google/uuid v1.6.0
github.com/onsi/gomega v1.33.1
github.com/open-policy-agent/cert-controller v0.10.1
github.com/open-policy-agent/frameworks/constraint v0.0.0-20240524210416-5368a3b697f2
github.com/open-policy-agent/frameworks/constraint v0.0.0-20240701165827-e11e1b0a90b1
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.19.1
github.com/spf13/cobra v1.8.0
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -287,8 +287,8 @@ github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
github.com/open-policy-agent/cert-controller v0.10.1 h1:RXSYoyn8FdCenWecRP//UV5nbVfmstNpj4kHQFkvPK4=
github.com/open-policy-agent/cert-controller v0.10.1/go.mod h1:4uRbBLY5DsPOog+a9pqk3JLxuuhrWsbUedQW65HcLTI=
github.com/open-policy-agent/frameworks/constraint v0.0.0-20240524210416-5368a3b697f2 h1:zalTQAmgeS+PYcEFeDG0/iWaZyNseXdeBYxpOSR0+zE=
github.com/open-policy-agent/frameworks/constraint v0.0.0-20240524210416-5368a3b697f2/go.mod h1:oXEqMRD8wI59XYd1xpkg47RTdLACMPMX7XbKXXhIJZg=
github.com/open-policy-agent/frameworks/constraint v0.0.0-20240701165827-e11e1b0a90b1 h1:en02ouTtvTP2LHQ0OZcq6+HeKPCxutBwn148hQ9FppM=
github.com/open-policy-agent/frameworks/constraint v0.0.0-20240701165827-e11e1b0a90b1/go.mod h1:5QVgZkIf934jEqGwfBUNn0GQ9sBmOfUTF2yrKdKiZuY=
github.com/open-policy-agent/opa v0.64.1 h1:n8IJTYlFWzqiOYx+JiawbErVxiqAyXohovcZxYbskxQ=
github.com/open-policy-agent/opa v0.64.1/go.mod h1:j4VeLorVpKipnkQ2TDjWshEuV3cvP/rHzQhYaraUXZY=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
Expand Down Expand Up @@ -429,8 +429,8 @@ golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvx
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
Expand Down
15 changes: 1 addition & 14 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ import (
"github.com/open-policy-agent/gatekeeper/v3/pkg/cachemanager"
"github.com/open-policy-agent/gatekeeper/v3/pkg/controller"
"github.com/open-policy-agent/gatekeeper/v3/pkg/controller/config/process"
"github.com/open-policy-agent/gatekeeper/v3/pkg/controller/constraint"
"github.com/open-policy-agent/gatekeeper/v3/pkg/expansion"
"github.com/open-policy-agent/gatekeeper/v3/pkg/externaldata"
"github.com/open-policy-agent/gatekeeper/v3/pkg/metrics"
Expand Down Expand Up @@ -117,7 +116,6 @@ var (
disabledBuiltins = util.NewFlagSet()
enableK8sCel = flag.Bool("experimental-enable-k8s-native-validation", false, "Alpha: enable the validating admission policy driver")
externaldataProviderResponseCacheTTL = flag.Duration("external-data-provider-response-cache-ttl", 3*time.Minute, "TTL for the external data provider response cache. Specify the duration in 'h', 'm', or 's' for hours, minutes, or seconds respectively. Defaults to 3 minutes if unspecified. Setting the TTL to 0 disables the cache.")
deferAdmissionToVAP = flag.Bool("defer-admission-to-vap", false, "When set to false, Gatekeeper webhook can act as a fallback in case K8s' Validating Admission Policy fails. When set to true, Gatekeeper validating webhook will not evaluate a policy for an admission request it expects vap to enforce. May improve resource usage at the cost of race conditions detecting whether VAP enforcement is in effect. This does not impact audit results. Defaults to false.")
)

func init() {
Expand All @@ -134,7 +132,6 @@ func init() {

// +kubebuilder:scaffold:scheme
flag.Var(disabledBuiltins, "disable-opa-builtin", "disable opa built-in function, this flag can be declared more than once.")
flag.Var(&constraint.VapEnforcement, "vap-enforcement", "control VAP resource generation. Allowed values are NONE: do not generate, GATEKEEPER_DEFAULT: do not generate unless label gatekeeper.sh/use-vap: yes is added to policy explicitly, VAP_DEFAULT: generate unless label gatekeeper.sh/use-vap: no is added to policy explicitly.")
}

func main() {
Expand Down Expand Up @@ -414,17 +411,7 @@ func setupControllers(ctx context.Context, mgr ctrl.Manager, sw *watch.Controlle
cfArgs := []constraintclient.Opt{constraintclient.Targets(&target.K8sValidationTarget{})}

if *enableK8sCel {
// initialize K8sValidation
var k8scelArgs []k8scel.Arg
if *deferAdmissionToVAP && constraint.VapEnforcement != constraint.VapFlagNone {
switch constraint.VapEnforcement {
case constraint.VapFlagGatekeeperDefault:
k8scelArgs = append(k8scelArgs, k8scel.VAPGenerationDefault(k8scel.VAPDefaultNo))
case constraint.VapFlagVapDefault:
k8scelArgs = append(k8scelArgs, k8scel.VAPGenerationDefault(k8scel.VAPDefaultYes))
}
}
k8sDriver, err := k8scel.New(k8scelArgs...)
k8sDriver, err := k8scel.New()
if err != nil {
setupLog.Error(err, "unable to set up K8s native driver")
return err
Expand Down
16 changes: 0 additions & 16 deletions pkg/controller/constraint/constants.go

This file was deleted.

91 changes: 6 additions & 85 deletions pkg/controller/constraint/constraint_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ package constraint
import (
"context"
"errors"
"flag"
"fmt"
"reflect"
"strings"
"sync"

"github.com/go-logr/logr"
v1beta1 "github.com/open-policy-agent/frameworks/constraint/pkg/apis/templates/v1beta1"
constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
"github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/k8scel/transform"
constraintstatusv1beta1 "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
Expand Down Expand Up @@ -59,47 +59,15 @@ import (
)

var (
log = logf.Log.V(logging.DebugLevel).WithName("controller").WithValues(logging.Process, "constraint_controller")
discoveryErr *apiutil.ErrResourceDiscoveryFailed
log = logf.Log.V(logging.DebugLevel).WithName("controller").WithValues(logging.Process, "constraint_controller")
discoveryErr *apiutil.ErrResourceDiscoveryFailed
defaultGenerateVAPB = flag.Bool("generate-vapbinding", false, "control VAPBinding resource generation. Allowed values are false: do not generate VAPBinding for constraint by default, true: generate VAPBinding for constraint by default.")
)

var vapMux sync.RWMutex

var VapAPIEnabled *bool

var VapEnforcement VapFlagType

// VapFlagType is the custom type for the vap-enforcement flag.
type VapFlagType string

// Allowed values for VapFlagType.
var allowedVapFlagVals = []string{VapFlagNone, VapFlagGatekeeperDefault, VapFlagVapDefault}

// String returns the string representation of the flag value.
func (v *VapFlagType) String() string {
return string(*v)
}

// Set validates and sets the value for the VapFlagType.
func (v *VapFlagType) Set(value string) error {
for _, val := range allowedVapFlagVals {
if val == value {
*v = VapFlagType(value)
return nil
}
}
return fmt.Errorf("invalid value %s. Allowed values are %s, %s, %s", value, VapFlagNone, VapFlagGatekeeperDefault, VapFlagVapDefault)
}

// setting defaults when not set; required for unit test.
func (v *VapFlagType) SetDefaultIfEmpty() {
if *v == "" {
*v = VapFlagType(VapFlagGatekeeperDefault)
VapAPIEnabled = new(bool)
*VapAPIEnabled = true
}
}

type Adder struct {
CFClient *constraintclient.Client
ConstraintsCache *ConstraintsCache
Expand Down Expand Up @@ -276,7 +244,6 @@ func (r *ReconcileConstraint) Reconcile(ctx context.Context, request reconcile.R
return reconcile.Result{}, nil
}

generateVapBinding := false
deleted := false
instance := &unstructured.Unstructured{}
instance.SetGroupVersionKind(gvk)
Expand All @@ -300,26 +267,6 @@ func (r *ReconcileConstraint) Reconcile(ctx context.Context, request reconcile.R

deleted = deleted || !instance.GetDeletionTimestamp().IsZero()

labels := instance.GetLabels()
log.Info("constraint resource", "labels", labels)
useVap, ok := labels[VapGenerationLabel]
if ok {
log.Info("constraint resource", "useVap", useVap)
}
// unless constraint vap label is false, default to parent
if useVap == No {
generateVapBinding = false
} else {
log.Info("constraint resource use-vap label is not no; will default to parent constraint template label")
parentCTUseVap, err := r.getCTVapLabel(ctx, instance.GetKind())
if err != nil {
log.Error(err, "could not get parent constraint template object")
return reconcile.Result{}, err
}
log.Info("constraint resource", "parentCTUseVap", parentCTUseVap)
generateVapBinding = ShouldGenerateVap(parentCTUseVap)
log.Info("constraint resource", "generateVapBinding", generateVapBinding)
}
constraintKey := strings.Join([]string{instance.GetKind(), instance.GetName()}, "/")
enforcementAction, err := util.GetEnforcementAction(instance.Object)
if err != nil {
Expand All @@ -346,7 +293,7 @@ func (r *ReconcileConstraint) Reconcile(ctx context.Context, request reconcile.R

if c, err := r.cfClient.GetConstraint(instance); err != nil || !reflect.DeepEqual(instance, c) {
// generate vapbinding resources
if generateVapBinding && IsVapAPIEnabled() {
if *defaultGenerateVAPB && IsVapAPIEnabled() {
currentVapBinding := &admissionregistrationv1beta1.ValidatingAdmissionPolicyBinding{}
vapBindingName := fmt.Sprintf("gatekeeper-%s", instance.GetName())
log.Info("check if vapbinding exists", "vapBindingName", vapBindingName)
Expand Down Expand Up @@ -398,7 +345,7 @@ func (r *ReconcileConstraint) Reconcile(ctx context.Context, request reconcile.R
}
// do not generate vapbinding resources
// remove if exists
if !generateVapBinding && IsVapAPIEnabled() {
if !*defaultGenerateVAPB && IsVapAPIEnabled() {
currentVapBinding := &admissionregistrationv1beta1.ValidatingAdmissionPolicyBinding{}
vapBindingName := fmt.Sprintf("gatekeeper-%s", instance.GetName())
log.Info("check if vapbinding exists", "vapBindingName", vapBindingName)
Expand Down Expand Up @@ -555,22 +502,6 @@ func (r *ReconcileConstraint) cacheConstraint(ctx context.Context, instance *uns
return nil
}

func (r *ReconcileConstraint) getCTVapLabel(ctx context.Context, gvk string) (string, error) {
ct := &v1beta1.ConstraintTemplate{}
ctName := strings.ToLower(gvk)
log.Info("get parent constraint template and its labels", "ctName", ctName)
if err := r.reader.Get(ctx, types.NamespacedName{Name: ctName}, ct); err != nil {
return "", err
}
labels := ct.GetLabels()
log.Info("parent constraint template", "labels", labels)
useVap, ok := labels[VapGenerationLabel]
if !ok {
return "", nil
}
return useVap, nil
}

func NewConstraintsCache() *ConstraintsCache {
return &ConstraintsCache{
cache: make(map[string]tags),
Expand Down Expand Up @@ -617,16 +548,6 @@ func (c *ConstraintsCache) reportTotalConstraints(ctx context.Context, reporter
}
}

func ShouldGenerateVap(useVapLabel string) bool {
if VapEnforcement == VapFlagGatekeeperDefault {
return useVapLabel == Yes
}
if VapEnforcement == VapFlagVapDefault {
return useVapLabel != No
}
return false
}

func IsVapAPIEnabled() bool {
vapMux.Lock()
defer vapMux.Unlock()
Expand Down
43 changes: 20 additions & 23 deletions pkg/controller/constrainttemplate/constrainttemplate_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ package constrainttemplate
import (
"context"
"errors"
"flag"
"fmt"
"reflect"
"time"

"github.com/open-policy-agent/frameworks/constraint/pkg/apis/templates/v1beta1"
constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
pSchema "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/k8scel/schema"
"github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/k8scel/transform"
"github.com/open-policy-agent/frameworks/constraint/pkg/core/templates"
statusv1beta1 "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
Expand Down Expand Up @@ -63,8 +65,9 @@ const (
)

var (
logger = log.Log.V(logging.DebugLevel).WithName("controller").WithValues("kind", "ConstraintTemplate", logging.Process, "constraint_template_controller")
discoveryErr *apiutil.ErrResourceDiscoveryFailed
logger = log.Log.V(logging.DebugLevel).WithName("controller").WithValues("kind", "ConstraintTemplate", logging.Process, "constraint_template_controller")
discoveryErr *apiutil.ErrResourceDiscoveryFailed
vapEnforcement = flag.Bool("vap-enforcement", false, "control VAP resource generation. Allowed values are false: do not generate unless enforceVAP: true is added to policy explicitly, true: generate unless enforceVAP: false is added to policy explicitly.")
)

var gvkConstraintTemplate = schema.GroupVersionKind{
Expand Down Expand Up @@ -121,7 +124,6 @@ func (a *Adder) InjectGetPod(getPod func(context.Context) (*corev1.Pod, error))
// regEvents is the channel registered by Registrar to put the events in
// cstrEvents and regEvents point to same event channel except for testing.
func newReconciler(mgr manager.Manager, cfClient *constraintclient.Client, wm *watch.Manager, cs *watch.ControllerSwitch, tracker *readiness.Tracker, cstrEvents <-chan event.GenericEvent, regEvents chan<- event.GenericEvent, getPod func(context.Context) (*corev1.Pod, error)) (*ReconcileConstraintTemplate, error) {
constraint.VapEnforcement.SetDefaultIfEmpty()
// constraintsCache contains total number of constraints and shared mutex and vap label
constraintsCache := constraint.NewConstraintsCache()

Expand Down Expand Up @@ -380,27 +382,11 @@ func (r *ReconcileConstraintTemplate) Reconcile(ctx context.Context, request rec
return reconcile.Result{}, err
}

generateVap := false
labels := ct.GetLabels()
logger.Info("constraint template resource", "labels", labels)
useVap, ok := labels[constraint.VapGenerationLabel]
if !ok {
logger.Info("constraint template resource does not have a label for use-vap; will default to flag behavior", "VapEnforcement", constraint.VapEnforcement)
generateVap = constraint.ShouldGenerateVap("")
} else {
logger.Info("constraint template resource", "useVap", useVap)
generateVap = constraint.ShouldGenerateVap(useVap)
if useVap != constraint.No && useVap != constraint.Yes {
labelErr := &v1beta1.CreateCRDError{Code: ErrCreateCode, Message: fmt.Sprintf("constraint template resource has an invalid value for %s, allowed values are yes and no", constraint.VapGenerationLabel)}
status.Status.Errors = append(status.Status.Errors, labelErr)

if updateErr := r.Update(ctx, status); updateErr != nil {
logger.Error(updateErr, "update status error")
return reconcile.Result{Requeue: true}, nil
}
}
}
generateVap, err := shouldGenerateVAP(unversionedCT, *vapEnforcement)
logger.Info("generateVap", "r.generateVap", generateVap)
if err != nil {
return reconcile.Result{}, err
}

result, err := r.handleUpdate(ctx, ct, unversionedCT, proposedCRD, currentCRD, status, generateVap)
if err != nil {
Expand Down Expand Up @@ -752,3 +738,14 @@ func makeGvk(kind string) schema.GroupVersionKind {
Kind: kind,
}
}

func shouldGenerateVAP(ct *templates.ConstraintTemplate, generateVAPDefault bool) (bool, error) {
source, err := pSchema.GetSourceFromTemplate(ct)
if err != nil {
return false, err
}
if source.GenerateVAP == nil {
return generateVAPDefault, nil
}
return *source.GenerateVAP, nil
}
Loading

0 comments on commit 019c8a7

Please sign in to comment.