Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: check for CT generateVap intent before generating vapbinding #3479

Merged
merged 15 commits into from
Aug 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 55 additions & 20 deletions pkg/controller/constraint/constraint_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
celSchema "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"
constraintstatusv1beta1 "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
"github.com/open-policy-agent/gatekeeper/v3/pkg/controller/config/process"
"github.com/open-policy-agent/gatekeeper/v3/pkg/controller/constraintstatus"
Expand Down Expand Up @@ -63,11 +64,16 @@ import (
)

var (
log = logf.Log.V(logging.DebugLevel).WithName("controller").WithValues(logging.Process, "constraint_controller")
discoveryErr *apiutil.ErrResourceDiscoveryFailed
DefaultGenerateVAPB = flag.Bool("default-create-vap-binding-for-constraints", false, "Create VAPBinding resource for constraint of the template containing VAP-style CEL source. Allowed values are false: do not create Validating Admission Policy Binding, true: create Validating Admission Policy Binding.")
log = logf.Log.V(logging.DebugLevel).WithName("controller").WithValues(logging.Process, "constraint_controller")
discoveryErr *apiutil.ErrResourceDiscoveryFailed
DefaultGenerateVAPB = flag.Bool("default-create-vap-binding-for-constraints", false, "Create VAPBinding resource for constraint of the template containing VAP-style CEL source. Allowed values are false: do not create Validating Admission Policy Binding, true: create Validating Admission Policy Binding.")
DefaultGenerateVAP = flag.Bool("default-create-vap-for-templates", false, "Create VAP resource for template containing VAP-style CEL source. Allowed values are false: do not create Validating Admission Policy unless generateVAP: true is set on constraint template explicitly, true: create Validating Admission Policy unless generateVAP: false is set on constraint template explicitly.")
)

var (
ErrValidatingAdmissionPolicyAPIDisabled = errors.New("ValidatingAdmissionPolicy API is not enabled")
ErrVAPConditionsNotSatisfied = errors.New("Conditions are not satisfied to generate ValidatingAdmissionPolicy and ValidatingAdmissionPolicyBinding")
)
var vapMux sync.RWMutex

var VapAPIEnabled *bool
Expand Down Expand Up @@ -304,13 +310,14 @@ func (r *ReconcileConstraint) Reconcile(ctx context.Context, request reconcile.R
if err2 := r.writer.Update(ctx, status); err2 != nil {
log.Error(err2, "could not report error for validation of enforcement action")
}
return reconcile.Result{}, err
}
generateVAPB, VAPEnforcementActions, err := shouldGenerateVAPB(*DefaultGenerateVAPB, enforcementAction, instance)
if err != nil {
log.Error(err, "could not determine if VAPBinding should be generated")
status.Status.Errors = append(status.Status.Errors, constraintstatusv1beta1.Error{Message: err.Error()})
log.Error(err, "could not get enforcement actions for VAP")
if err2 := r.writer.Update(ctx, status); err2 != nil {
log.Error(err2, "could not report error for getting enforcement actions for VAP")
log.Error(err2, "could not report error when determining if VAPBinding should be generated")
}
return reconcile.Result{}, err
}
Expand All @@ -321,12 +328,38 @@ func (r *ReconcileConstraint) Reconcile(ctx context.Context, request reconcile.R
}
if generateVAPB {
if !isAPIEnabled {
r.log.V(1).Info("Warning: VAP API is not enabled, cannot create VAPBinding")
generateVAPB = false
}
if !HasVAPCel(ct) {
r.log.V(1).Info("Warning: ConstraintTemplate does not contain VAP-style CEL source, cannot create VAPBinding")
log.Error(ErrValidatingAdmissionPolicyAPIDisabled, "Cannot generate ValidatingAdmissionPolicyBinding", "constraint", instance.GetName())
status.Status.Errors = append(status.Status.Errors, constraintstatusv1beta1.Error{Message: fmt.Sprintf("%s, cannot generate ValidatingAdmissionPolicyBinding", ErrValidatingAdmissionPolicyAPIDisabled.Error())})
if err2 := r.writer.Update(ctx, status); err2 != nil {
log.Error(err2, "could not update constraint status error when ValidatingAdmissionPolicy API is not enabled")
}
generateVAPB = false
} else {
unversionedCT := &templates.ConstraintTemplate{}
if err := r.scheme.Convert(ct, unversionedCT, nil); err != nil {
status.Status.Errors = append(status.Status.Errors, constraintstatusv1beta1.Error{Message: err.Error()})
if err2 := r.writer.Update(ctx, status); err2 != nil {
log.Error(err2, "could not update constraint status error when converting ConstraintTemplate to unversioned")
}
return reconcile.Result{}, err
}
hasVAP, err := ShouldGenerateVAP(unversionedCT)
if err != nil {
log.Error(err, "could not determine if ConstraintTemplate is configured to generate ValidatingAdmissionPolicy", "constraint", instance.GetName(), "constraint_template", ct.GetName())
status.Status.Errors = append(status.Status.Errors, constraintstatusv1beta1.Error{Message: err.Error()})
if err2 := r.writer.Update(ctx, status); err2 != nil {
log.Error(err2, "could not update constraint status error when determining if ConstraintTemplate is configured to generate ValidatingAdmissionPolicy")
}
generateVAPB = false
}
if !hasVAP {
log.Error(ErrVAPConditionsNotSatisfied, "Cannot generate ValidatingAdmissionPolicyBinding", "constraint", instance.GetName(), "constraint_template", ct.GetName())
status.Status.Errors = append(status.Status.Errors, constraintstatusv1beta1.Error{Message: fmt.Sprintf("%s, cannot generate ValidatingAdmissionPolicyBinding", ErrVAPConditionsNotSatisfied.Error())})
if err2 := r.writer.Update(ctx, status); err2 != nil {
log.Error(err2, "could not update constraint status error when conditions are not satisfied to generate ValidatingAdmissionPolicy and ValidatingAdmissionPolicyBinding")
}
generateVAPB = false
}
}
}
r.log.Info("constraint controller", "generateVAPB", generateVAPB)
Expand Down Expand Up @@ -361,7 +394,7 @@ func (r *ReconcileConstraint) Reconcile(ctx context.Context, request reconcile.R
if err != nil {
status.Status.Errors = append(status.Status.Errors, constraintstatusv1beta1.Error{Message: err.Error()})
if err2 := r.writer.Update(ctx, status); err2 != nil {
log.Error(err2, "could not get VAP object with runtime group version", "vapBindingName", vapBindingName)
log.Error(err2, "could not get VAPBinding object with runtime group version", "vapBindingName", vapBindingName)
}
return reconcile.Result{}, err
}
Expand Down Expand Up @@ -526,16 +559,18 @@ func (r *ReconcileConstraint) getOrCreatePodStatus(ctx context.Context, constrai
return statusObj, nil
}

func HasVAPCel(ct *v1beta1.ConstraintTemplate) bool {
if len(ct.Spec.Targets[0].Code) == 0 {
return false
func ShouldGenerateVAP(ct *templates.ConstraintTemplate) (bool, error) {
source, err := celSchema.GetSourceFromTemplate(ct)
if errors.Is(err, celSchema.ErrCodeNotDefined) {
return false, nil
}
for _, code := range ct.Spec.Targets[0].Code {
if code.Engine == celSchema.Name {
return true
}
if err != nil {
return false, err
}
if source.GenerateVAP == nil {
return *DefaultGenerateVAP, nil
}
return false
return *source.GenerateVAP, nil
}

func logAddition(l logr.Logger, constraint *unstructured.Unstructured, enforcementAction util.EnforcementAction) {
Expand Down Expand Up @@ -683,7 +718,7 @@ func IsVapAPIEnabled() (bool, *schema.GroupVersion) {
}
}

log.Error(err, "error checking VAP api availability", "IsVapAPIEnabled", "false")
log.Error(err, "error checking VAP API availability", "IsVapAPIEnabled", "false")
VapAPIEnabled = new(bool)
*VapAPIEnabled = false
return false, nil
Expand Down
Loading
Loading