1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-28 10:28:36 +00:00

feat: separate webhook rules per GVK/rule (#4986)

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
Co-authored-by: shuting <shuting@nirmata.com>
This commit is contained in:
Charles-Edouard Brétéché 2022-11-07 17:05:56 +01:00 committed by GitHub
parent 2d475c1b85
commit e4c493093e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 67 additions and 52 deletions

View file

@ -646,11 +646,9 @@ func (c *controller) buildResourceMutatingWebhookConfiguration(caBundle []byte)
result.Webhooks = append(
result.Webhooks,
admissionregistrationv1.MutatingWebhook{
Name: config.MutatingWebhookName + "-ignore",
ClientConfig: c.clientConfig(caBundle, config.MutatingWebhookServicePath+"/ignore"),
Rules: []admissionregistrationv1.RuleWithOperations{
ignore.buildRuleWithOperations(admissionregistrationv1.Create, admissionregistrationv1.Update),
},
Name: config.MutatingWebhookName + "-ignore",
ClientConfig: c.clientConfig(caBundle, config.MutatingWebhookServicePath+"/ignore"),
Rules: ignore.buildRulesWithOperations(admissionregistrationv1.Create, admissionregistrationv1.Update),
FailurePolicy: &ignore.failurePolicy,
SideEffects: &noneOnDryRun,
AdmissionReviewVersions: []string{"v1beta1"},
@ -665,11 +663,9 @@ func (c *controller) buildResourceMutatingWebhookConfiguration(caBundle []byte)
result.Webhooks = append(
result.Webhooks,
admissionregistrationv1.MutatingWebhook{
Name: config.MutatingWebhookName + "-fail",
ClientConfig: c.clientConfig(caBundle, config.MutatingWebhookServicePath+"/fail"),
Rules: []admissionregistrationv1.RuleWithOperations{
fail.buildRuleWithOperations(admissionregistrationv1.Create, admissionregistrationv1.Update),
},
Name: config.MutatingWebhookName + "-fail",
ClientConfig: c.clientConfig(caBundle, config.MutatingWebhookServicePath+"/fail"),
Rules: fail.buildRulesWithOperations(admissionregistrationv1.Create, admissionregistrationv1.Update),
FailurePolicy: &fail.failurePolicy,
SideEffects: &noneOnDryRun,
AdmissionReviewVersions: []string{"v1beta1"},
@ -761,11 +757,9 @@ func (c *controller) buildResourceValidatingWebhookConfiguration(caBundle []byte
result.Webhooks = append(
result.Webhooks,
admissionregistrationv1.ValidatingWebhook{
Name: config.ValidatingWebhookName + "-ignore",
ClientConfig: c.clientConfig(caBundle, config.ValidatingWebhookServicePath+"/ignore"),
Rules: []admissionregistrationv1.RuleWithOperations{
ignore.buildRuleWithOperations(admissionregistrationv1.Create, admissionregistrationv1.Update, admissionregistrationv1.Delete, admissionregistrationv1.Connect),
},
Name: config.ValidatingWebhookName + "-ignore",
ClientConfig: c.clientConfig(caBundle, config.ValidatingWebhookServicePath+"/ignore"),
Rules: ignore.buildRulesWithOperations(admissionregistrationv1.Create, admissionregistrationv1.Update, admissionregistrationv1.Delete, admissionregistrationv1.Connect),
FailurePolicy: &ignore.failurePolicy,
SideEffects: sideEffects,
AdmissionReviewVersions: []string{"v1beta1"},
@ -779,11 +773,9 @@ func (c *controller) buildResourceValidatingWebhookConfiguration(caBundle []byte
result.Webhooks = append(
result.Webhooks,
admissionregistrationv1.ValidatingWebhook{
Name: config.ValidatingWebhookName + "-fail",
ClientConfig: c.clientConfig(caBundle, config.ValidatingWebhookServicePath+"/fail"),
Rules: []admissionregistrationv1.RuleWithOperations{
fail.buildRuleWithOperations(admissionregistrationv1.Create, admissionregistrationv1.Update, admissionregistrationv1.Delete, admissionregistrationv1.Connect),
},
Name: config.ValidatingWebhookName + "-fail",
ClientConfig: c.clientConfig(caBundle, config.ValidatingWebhookServicePath+"/fail"),
Rules: fail.buildRulesWithOperations(admissionregistrationv1.Create, admissionregistrationv1.Update, admissionregistrationv1.Delete, admissionregistrationv1.Connect),
FailurePolicy: &fail.failurePolicy,
SideEffects: sideEffects,
AdmissionReviewVersions: []string{"v1beta1"},
@ -878,20 +870,7 @@ func (c *controller) mergeWebhook(dst *webhook, policy kyvernov1.PolicyInterface
}
}
for _, gvr := range gvrList {
dst.groups.Insert(gvr.Group)
if gvr.Version == "*" {
dst.versions = sets.NewString()
dst.versions.Insert(gvr.Version)
} else if !dst.versions.Has("*") {
dst.versions.Insert(gvr.Version)
}
dst.resources.Insert(gvr.Resource)
}
if dst.resources.Has("pods") {
dst.resources.Insert("pods/ephemeralcontainers")
}
if dst.resources.Has("services") {
dst.resources.Insert("services/status")
dst.set(gvr)
}
spec := policy.GetSpec()
if spec.WebhookTimeoutSeconds != nil {

View file

@ -5,8 +5,10 @@ import (
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/utils"
"golang.org/x/exp/slices"
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/sets"
)
@ -15,40 +17,74 @@ import (
type webhook struct {
maxWebhookTimeout int32
failurePolicy admissionregistrationv1.FailurePolicyType
groups sets.String
versions sets.String
resources sets.String
rules map[schema.GroupVersionResource]struct{}
}
func newWebhook(timeout int32, failurePolicy admissionregistrationv1.FailurePolicyType) *webhook {
return &webhook{
maxWebhookTimeout: timeout,
failurePolicy: failurePolicy,
groups: sets.NewString(),
versions: sets.NewString(),
resources: sets.NewString(),
rules: map[schema.GroupVersionResource]struct{}{},
}
}
func (wh *webhook) buildRuleWithOperations(ops ...admissionregistrationv1.OperationType) admissionregistrationv1.RuleWithOperations {
return admissionregistrationv1.RuleWithOperations{
Rule: admissionregistrationv1.Rule{
APIGroups: wh.groups.List(),
APIVersions: wh.versions.List(),
Resources: wh.resources.List(),
},
Operations: ops,
func (wh *webhook) buildRulesWithOperations(ops ...admissionregistrationv1.OperationType) []admissionregistrationv1.RuleWithOperations {
var rules []admissionregistrationv1.RuleWithOperations
for gvr := range wh.rules {
resources := sets.NewString(gvr.Resource)
if resources.Has("pods") {
resources.Insert("pods/ephemeralcontainers")
}
if resources.Has("services") {
resources.Insert("services/status")
}
rules = append(rules, admissionregistrationv1.RuleWithOperations{
Rule: admissionregistrationv1.Rule{
APIGroups: []string{gvr.Group},
APIVersions: []string{gvr.Version},
Resources: resources.List(),
},
Operations: ops,
})
}
less := func(a []string, b []string) (bool, bool) {
if len(a) != len(b) {
return len(a) < len(b), true
}
for i := range a {
if a[i] != b[i] {
return a[i] < b[i], true
}
}
return false, false
}
slices.SortFunc(rules, func(a admissionregistrationv1.RuleWithOperations, b admissionregistrationv1.RuleWithOperations) bool {
if less, match := less(a.APIGroups, b.APIGroups); match {
return less
}
if less, match := less(a.APIVersions, b.APIVersions); match {
return less
}
if less, match := less(a.Resources, b.Resources); match {
return less
}
return false
})
return rules
}
func (wh *webhook) set(gvr schema.GroupVersionResource) {
wh.rules[gvr] = struct{}{}
}
func (wh *webhook) isEmpty() bool {
return wh.groups.Len() == 0 || wh.versions.Len() == 0 || wh.resources.Len() == 0
return len(wh.rules) == 0
}
func (wh *webhook) setWildcard() {
wh.groups = sets.NewString("*")
wh.versions = sets.NewString("*")
wh.resources = sets.NewString("*/*")
wh.rules = map[schema.GroupVersionResource]struct{}{
{Group: "*", Version: "*", Resource: "*/*"}: {},
}
}
func hasWildcard(policies ...kyvernov1.PolicyInterface) bool {