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

feat: adding scopedenforcementactions #3321

Merged
merged 26 commits into from
Jul 31, 2024

Conversation

JaydipGabani
Copy link
Contributor

@JaydipGabani JaydipGabani commented Mar 18, 2024

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

@JaydipGabani JaydipGabani force-pushed the multi-ea branch 2 times, most recently from 87f4584 to 2f9f4bb Compare March 21, 2024 15:55
@codecov-commenter
Copy link

codecov-commenter commented Mar 21, 2024

Codecov Report

Attention: Patch coverage is 52.83843% with 108 lines in your changes missing coverage. Please review.

Project coverage is 48.25%. Comparing base (3350319) to head (ee74b6c).
Report is 112 commits behind head on master.

Files Patch % Lines
pkg/webhook/policy.go 26.31% 42 Missing ⚠️
pkg/audit/manager.go 3.12% 31 Missing ⚠️
pkg/controller/constraint/constraint_controller.go 30.30% 23 Missing ⚠️
pkg/util/enforcement_action.go 87.87% 4 Missing and 4 partials ⚠️
cmd/gator/test/test.go 0.00% 3 Missing ⚠️
pkg/gator/test/test.go 66.66% 1 Missing ⚠️

❗ There is a different number of reports uploaded between BASE (3350319) and HEAD (ee74b6c). Click for more details.

HEAD has 1 upload less than BASE
Flag BASE (3350319) HEAD (ee74b6c)
unittests 2 1
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     
Flag Coverage Δ
unittests 48.25% <52.83%> (-6.25%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

pkg/audit/manager_test.go Outdated Show resolved Hide resolved
go.mod Outdated Show resolved Hide resolved
wantViolation: true,
},
{
name: "audit excluded from constraint",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

webhook?

Copy link
Contributor Author

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.

Copy link

stale bot commented Jun 18, 2024

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.")
Copy link
Contributor

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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed.

Name string `json:"name"`
Namespace string `json:"namespace,omitempty"`
Message string `json:"message"`
EnforcementAction []string `json:"enforcementAction"`
Copy link
Contributor

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.

@@ -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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Backwards compatibility concern?

Copy link
Member

@ritazh ritazh Jul 24, 2024

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.

@@ -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,
Copy link
Contributor

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?)

Copy link
Contributor Author

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.

Copy link
Member

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")
Copy link
Member

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.

pkg/audit/manager.go Outdated Show resolved Hide resolved
return reconcile.Result{}, err
}
isVAPBGenerationEnabled := generateVAPB && IsVapAPIEnabled() && HasVAPCel(ct)
if generateVAPB != isVAPBGenerationEnabled {
Copy link
Contributor

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.

@@ -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 {
Copy link
Contributor

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)

@JaydipGabani JaydipGabani force-pushed the multi-ea branch 2 times, most recently from 329b7e1 to c81bc90 Compare July 25, 2024 16:22
Signed-off-by: Jaydip Gabani <gabanijaydip@gmail.com>
Signed-off-by: Jaydip Gabani <gabanijaydip@gmail.com>
Signed-off-by: Jaydip Gabani <gabanijaydip@gmail.com>
Signed-off-by: Jaydip Gabani <gabanijaydip@gmail.com>
@JaydipGabani JaydipGabani requested a review from ritazh July 25, 2024 17:50
return ErrInvalidSpecEnforcementAction
}
for _, enforcementPoint := range scopedEnforcementAction.EnforcementPoints {
switch strings.ToLower(enforcementPoint.Name) {
Copy link
Contributor Author

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)


func enforcementPointEnabled(scopedEnforcementAction apiconstraints.ScopedEnforcementAction, enforcementPoint string) bool {
for _, ep := range scopedEnforcementAction.EnforcementPoints {
if strings.EqualFold(ep.Name, enforcementPoint) || ep.Name == AllEnforcementPoints {
Copy link
Contributor Author

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)

@JaydipGabani JaydipGabani requested a review from ritazh July 30, 2024 02:30
Signed-off-by: Jaydip Gabani <gabanijaydip@gmail.com>
Signed-off-by: Jaydip Gabani <gabanijaydip@gmail.com>
Signed-off-by: Jaydip Gabani <gabanijaydip@gmail.com>
Action: "warn",
EnforcementPoints: []apiconstraints.EnforcementPoint{
{
Name: util.WebhookEnforcementPoint,
Copy link
Member

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?

Copy link
Contributor Author

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 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

log error

Copy link
Contributor Author

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 {
Copy link
Member

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()})
Copy link
Member

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Signed-off-by: Jaydip Gabani <gabanijaydip@gmail.com>
@JaydipGabani JaydipGabani requested a review from ritazh July 31, 2024 06:53
Signed-off-by: Jaydip Gabani <gabanijaydip@gmail.com>
Copy link
Member

@ritazh ritazh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM


### 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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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.

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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
`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.


###### 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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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.

Copy link
Member

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:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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 <gabanijaydip@gmail.com>
Copy link
Contributor

@maxsmythe maxsmythe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Member

@sozercan sozercan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great job! LGTM

@sozercan sozercan merged commit 23fa58c into open-policy-agent:master Jul 31, 2024
21 checks passed
@JaydipGabani JaydipGabani deleted the multi-ea branch July 31, 2024 23:59
Ankurk99 pushed a commit to Ankurk99/gatekeeper that referenced this pull request Aug 1, 2024
Signed-off-by: Jaydip Gabani <gabanijaydip@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Disable audit for constraint
5 participants