-
Notifications
You must be signed in to change notification settings - Fork 769
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
feat: adding scopedenforcementactions #3321
Conversation
87f4584
to
2f9f4bb
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #3321 +/- ##
==========================================
- Coverage 54.49% 48.25% -6.25%
==========================================
Files 134 219 +85
Lines 12329 14989 +2660
==========================================
+ Hits 6719 7233 +514
- Misses 5116 6946 +1830
- Partials 494 810 +316
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
wantViolation: true, | ||
}, | ||
{ | ||
name: "audit excluded from constraint", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
webhook?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you clarify a little more here wdym? @sozercan
This is a test for constraint without audit
enforcementPoint.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 14 days if no further activity occurs. Thank you for your contributions. |
main.go
Outdated
@@ -117,7 +117,7 @@ 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.") | |||
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.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Much of this logic goes away with #3398
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed.
pkg/audit/manager.go
Outdated
Name string `json:"name"` | ||
Namespace string `json:"namespace,omitempty"` | ||
Message string `json:"message"` | ||
EnforcementAction []string `json:"enforcementAction"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we can change the schema here without breaking backwards compatibility.
pkg/audit/manager.go
Outdated
@@ -1169,7 +1169,7 @@ func violationMsg(constraint *unstructured.Unstructured, enforcementAction util. | |||
Kind: constraint.GetKind(), | |||
Name: constraint.GetName(), | |||
Namespace: constraint.GetNamespace(), | |||
EnforcementAction: string(enforcementAction), | |||
EnforcementAction: enforcementAction, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Backwards compatibility concern?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To ensure backwards compatibility, we could add a new EnforcementActions
instead and not touch the existing field. wdyt? same would apply for logs and events.
pkg/audit/manager.go
Outdated
@@ -1182,7 +1182,7 @@ func violationMsg(constraint *unstructured.Unstructured, enforcementAction util. | |||
|
|||
func logViolation(l logr.Logger, | |||
constraint *unstructured.Unstructured, | |||
enforcementAction util.EnforcementAction, resourceGroupVersionKind schema.GroupVersionKind, rnamespace, rname, message string, details interface{}, rlabels map[string]string, | |||
enforcementAction []string, resourceGroupVersionKind schema.GroupVersionKind, rnamespace, rname, message string, details interface{}, rlabels map[string]string, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a backwards compatibility concern because it affects semantic logging. We could just log one message per enforcement action, though. Or add a new field (though what value would enforcementAction
have?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can probably serialize the array. Something like deny/warn
in-case if enforcemet point is duplicated in scopedEA
config.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to ensure backwards compat, the existing enforcementAction should remain untouched. lets create a new field instead.
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 enforcement actions for VAP") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This error is when updating constraint status failed right? please update the log message.
return reconcile.Result{}, err | ||
} | ||
isVAPBGenerationEnabled := generateVAPB && IsVapAPIEnabled() && HasVAPCel(ct) | ||
if generateVAPB != isVAPBGenerationEnabled { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably just calculate these errors directly, rather than packing multiple values into a bool and then unpacking them again.
pkg/gator/test/types.go
Outdated
@@ -66,8 +67,8 @@ func (r *GatorResponses) Results() []*GatorResult { | |||
// responses to individual constraints. This is a stopgap to make tests easier | |||
// to write until then. | |||
sort.Slice(res, func(i, j int) bool { | |||
if res[i].EnforcementAction != res[j].EnforcementAction { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
second instance of a concatenated string (backwards compatibility concern)
329b7e1
to
c81bc90
Compare
Signed-off-by: Jaydip Gabani <[email protected]>
Signed-off-by: Jaydip Gabani <[email protected]>
Signed-off-by: Jaydip Gabani <[email protected]>
Signed-off-by: Jaydip Gabani <[email protected]>
pkg/util/enforcement_action.go
Outdated
return ErrInvalidSpecEnforcementAction | ||
} | ||
for _, enforcementPoint := range scopedEnforcementAction.EnforcementPoints { | ||
switch strings.ToLower(enforcementPoint.Name) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will remove this if needed after we reach to a conclusion on - open-policy-agent/frameworks#403 (comment)
pkg/util/enforcement_action.go
Outdated
|
||
func enforcementPointEnabled(scopedEnforcementAction apiconstraints.ScopedEnforcementAction, enforcementPoint string) bool { | ||
for _, ep := range scopedEnforcementAction.EnforcementPoints { | ||
if strings.EqualFold(ep.Name, enforcementPoint) || ep.Name == AllEnforcementPoints { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove this if need be after we reach conclusion on - open-policy-agent/frameworks#403 (comment)
Signed-off-by: Jaydip Gabani <[email protected]>
Signed-off-by: Jaydip Gabani <[email protected]>
Signed-off-by: Jaydip Gabani <[email protected]>
Action: "warn", | ||
EnforcementPoints: []apiconstraints.EnforcementPoint{ | ||
{ | ||
Name: util.WebhookEnforcementPoint, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in this test, when webhookep has both action warn and deny, which one wins?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if both the actions are there ultimatly the request is denied but output containes warning and deny and looks like this -
Warning: [cm-must-have-gk-scoped] you must provide labels: {"gatekeeper"}
Error from server (Forbidden): error when creating "/mount/d/go/src/github.com/open-policy-agent/gatekeeper/test/bats/tests/bad/bad_cm_scoped.yaml": admission webhook "validation.gatekeeper.sh" denied the request: [cm-must-have-gk-scoped] you must provide labels: {"gatekeeper"}
switch r.EnforcementAction { | ||
case string(util.Scoped): | ||
for _, action := range r.ScopedEnforcementActions { | ||
if err := util.ValidateEnforcementAction(util.EnforcementAction(action), r.Constraint.Object); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
log error
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logging error
continue | ||
} | ||
default: | ||
if err := util.ValidateEnforcementAction(util.EnforcementAction(r.EnforcementAction), r.Constraint.Object); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
log error
@@ -303,8 +300,35 @@ func (r *ReconcileConstraint) Reconcile(ctx context.Context, request reconcile.R | |||
status.Status.Errors = nil | |||
|
|||
if c, err := r.cfClient.GetConstraint(instance); err != nil || !reflect.DeepEqual(instance, c) { | |||
err := util.ValidateEnforcementAction(enforcementAction, instance.Object) | |||
if err != nil { | |||
status.Status.Errors = append(status.Status.Errors, constraintstatusv1beta1.Error{Message: err.Error()}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there a test that validates this error is written to the constraint's status errors?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the test constrainttemplate_controller_test.go#L811
Signed-off-by: Jaydip Gabani <[email protected]>
Signed-off-by: Jaydip Gabani <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
website/docs/enforcement-points.md
Outdated
|
||
### How to use different enforcement points in constraint | ||
|
||
By default, a constraint will be enforced at all enforcement points with common enforcement action defined in `spec.enforcementAction`. However, you can chose to enforce a constraint at specific enforcement points different actions using `spec.scopedEnforcementActions`. Below are the different examples and use cases that utilizes different enforcement actions for different enforcement points. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By default, a constraint will be enforced at all enforcement points with common enforcement action defined in `spec.enforcementAction`. However, you can chose to enforce a constraint at specific enforcement points different actions using `spec.scopedEnforcementActions`. Below are the different examples and use cases that utilizes different enforcement actions for different enforcement points. | |
By default, a constraint will be enforced at all enforcement points with common enforcement action defined in `spec.enforcementAction`. However, you can choose to enforce a constraint at specific enforcement points with different actions using `enforcementAction: scoped` and `spec.scopedEnforcementActions`. Below are examples and use cases that utilize different enforcement actions for different enforcement points. |
website/docs/enforcement-points.md
Outdated
By default, a constraint will be enforced at all enforcement points with common enforcement action defined in `spec.enforcementAction`. However, you can chose to enforce a constraint at specific enforcement points different actions using `spec.scopedEnforcementActions`. Below are the different examples and use cases that utilizes different enforcement actions for different enforcement points. | ||
|
||
:::note | ||
`spec.enforcementAction: scoped` is needed to customize specific enforcement point/enforcement action behavior. If `spec.enforcementAction: scoped` is not provided, `spec.scopedEnforcementActions` is ignored and defined `enforcementAction` will be enforced at all enforcement points. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
`spec.enforcementAction: scoped` is needed to customize specific enforcement point/enforcement action behavior. If `spec.enforcementAction: scoped` is not provided, `spec.scopedEnforcementActions` is ignored and defined `enforcementAction` will be enforced at all enforcement points. | |
`spec.enforcementAction: scoped` is needed to customize specific enforcement point/enforcement action behavior. If `spec.enforcementAction: scoped` is not provided, `spec.scopedEnforcementActions` is ignored and the provided `enforcementAction` will be applied across all enforcement points. |
website/docs/enforcement-points.md
Outdated
|
||
###### Deny in shift-left and warn at admission | ||
|
||
You are trying out a new constraint template, and you want deny violating resources in shift-left testing, but do not want to block any resources when admitted to cluster to avoid faulty rejects. You may want to use `deny` action for `gator.gatekeeper.sh` enforcement point and `warn` for `validation.gatekeepet.sh`. The below constraint satisfies this use case. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are trying out a new constraint template, and you want deny violating resources in shift-left testing, but do not want to block any resources when admitted to cluster to avoid faulty rejects. You may want to use `deny` action for `gator.gatekeeper.sh` enforcement point and `warn` for `validation.gatekeepet.sh`. The below constraint satisfies this use case. | |
You are trying out a new constraint template, and you want to deny violating resources in shift-left testing, but do not want to block any resources admitted to clusters to reduce impact for faulty rejections. You may want to use `deny` action for the `gator.gatekeeper.sh` shift-left enforcement point and `warn` for `the validation.gatekeepet.sh` admission webhook enforcement point. The below constraint satisfies this use case. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a note for:
The audit enforcement point is not included unless explicitly added to scopedEnforcementActions.enforcementPoints or if scopedEnforcementActions.enforcementPoints is set to "*"
|
||
To summary, these are potential options when running Gatekeeper: | ||
To summarize, these are potential options when running Gatekeeper: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To summarize, these are potential options when running Gatekeeper: | |
In summary, these are potential options when running Gatekeeper: |
@@ -134,7 +136,46 @@ spec: | |||
... | |||
``` | |||
|
|||
Constraints will follow the behavior defined by `--default-create-vap-binding-for-constraints` flag to generate K8s Validating Admission Policy Binding. By default, `--default-create-vap-binding-for-constraints` is set to `false`. | |||
Constraints will follow the behavior defined in `spec.scopedEnforcementActions`. When `spec.scopedEnforcementAction` is not defined, constraints will follow behavior defined by the flag `--default-create-vap-binding-for-constraints`. By default, `--default-create-vap-binding-for-constraints` is set to `false`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Constraints will follow the behavior defined in `spec.scopedEnforcementActions`. When `spec.scopedEnforcementAction` is not defined, constraints will follow behavior defined by the flag `--default-create-vap-binding-for-constraints`. By default, `--default-create-vap-binding-for-constraints` is set to `false`. | |
Gatekeeper determines the intended enforcement actions for a given enforcement point by evaluating what is provided in `spec.scopedEnforcementActions` and `spec.enforcementAction: scoped` in the constraint. If these values are not provided in the constraint, then Gatekeeper will follow behavior defined by the flag `--default-create-vap-binding-for-constraints`. By default, `--default-create-vap-binding-for-constraints` is set to `false`. |
Signed-off-by: Jaydip Gabani <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great job! LGTM
Signed-off-by: Jaydip Gabani <[email protected]>
What this PR does / why we need it:
Which issue(s) this PR fixes (optional, using
fixes #<issue number>(, fixes #<issue_number>, ...)
format, will close the issue(s) when the PR gets merged):Fixes #2266 #2945
Special notes for your reviewer:
Depends on #frameworks/403