mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-14 19:58:45 +00:00
feat: change webhook configuration to better support wildcards (#6534)
* feat: change webhook configuration to better support wildcards Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * fix Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * kuttl Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * fix Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> --------- Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
parent
cc9b44eb19
commit
73d2063853
12 changed files with 111 additions and 87 deletions
|
@ -629,11 +629,6 @@ func (c *controller) buildResourceMutatingWebhookConfiguration(caBundle []byte)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
c.recordPolicyState(config.MutatingWebhookConfigurationName, policies...)
|
c.recordPolicyState(config.MutatingWebhookConfigurationName, policies...)
|
||||||
// TODO: shouldn't be per failure policy, depending of the policy/rules that apply ?
|
|
||||||
if hasWildcard(policies...) {
|
|
||||||
ignore.setWildcard()
|
|
||||||
fail.setWildcard()
|
|
||||||
} else {
|
|
||||||
for _, p := range policies {
|
for _, p := range policies {
|
||||||
spec := p.GetSpec()
|
spec := p.GetSpec()
|
||||||
if spec.HasMutate() || spec.HasVerifyImages() {
|
if spec.HasMutate() || spec.HasVerifyImages() {
|
||||||
|
@ -644,7 +639,6 @@ func (c *controller) buildResourceMutatingWebhookConfiguration(caBundle []byte)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
cfg := c.loadConfig()
|
cfg := c.loadConfig()
|
||||||
webhookCfg := config.WebhookConfig{}
|
webhookCfg := config.WebhookConfig{}
|
||||||
webhookCfgs := cfg.GetWebhooks()
|
webhookCfgs := cfg.GetWebhooks()
|
||||||
|
@ -736,11 +730,6 @@ func (c *controller) buildResourceValidatingWebhookConfiguration(caBundle []byte
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
c.recordPolicyState(config.ValidatingWebhookConfigurationName, policies...)
|
c.recordPolicyState(config.ValidatingWebhookConfigurationName, policies...)
|
||||||
// TODO: shouldn't be per failure policy, depending of the policy/rules that apply ?
|
|
||||||
if hasWildcard(policies...) {
|
|
||||||
ignore.setWildcard()
|
|
||||||
fail.setWildcard()
|
|
||||||
} else {
|
|
||||||
for _, p := range policies {
|
for _, p := range policies {
|
||||||
spec := p.GetSpec()
|
spec := p.GetSpec()
|
||||||
if spec.HasValidate() || spec.HasGenerate() || spec.HasMutate() || spec.HasImagesValidationChecks() || spec.HasYAMLSignatureVerify() {
|
if spec.HasValidate() || spec.HasGenerate() || spec.HasMutate() || spec.HasImagesValidationChecks() || spec.HasYAMLSignatureVerify() {
|
||||||
|
@ -751,7 +740,6 @@ func (c *controller) buildResourceValidatingWebhookConfiguration(caBundle []byte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
cfg := c.loadConfig()
|
cfg := c.loadConfig()
|
||||||
webhookCfg := config.WebhookConfig{}
|
webhookCfg := config.WebhookConfig{}
|
||||||
webhookCfgs := cfg.GetWebhooks()
|
webhookCfgs := cfg.GetWebhooks()
|
||||||
|
@ -848,6 +836,14 @@ func (c *controller) mergeWebhook(dst *webhook, policy kyvernov1.PolicyInterface
|
||||||
gvkMap[gvk] = 1
|
gvkMap[gvk] = 1
|
||||||
// NOTE: webhook stores GVR in its rules while policy stores GVK in its rules definition
|
// NOTE: webhook stores GVR in its rules while policy stores GVK in its rules definition
|
||||||
group, version, kind, subresource := kubeutils.ParseKindSelector(gvk)
|
group, version, kind, subresource := kubeutils.ParseKindSelector(gvk)
|
||||||
|
// if kind is `*` no need to lookup resources
|
||||||
|
if kind == "*" && subresource == "*" {
|
||||||
|
gvrList = append(gvrList, schema.GroupVersionResource{Group: group, Version: version, Resource: "*/*"})
|
||||||
|
} else if kind == "*" && subresource == "" {
|
||||||
|
gvrList = append(gvrList, schema.GroupVersionResource{Group: group, Version: version, Resource: "*"})
|
||||||
|
} else if kind == "*" && subresource != "" {
|
||||||
|
gvrList = append(gvrList, schema.GroupVersionResource{Group: group, Version: version, Resource: "*/" + subresource})
|
||||||
|
} else {
|
||||||
gvrs, err := c.discoveryClient.FindResources(group, version, kind, subresource)
|
gvrs, err := c.discoveryClient.FindResources(group, version, kind, subresource)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "unable to find resource", "group", group, "version", version, "kind", kind, "subresource", subresource)
|
logger.Error(err, "unable to find resource", "group", group, "version", version, "kind", kind, "subresource", subresource)
|
||||||
|
@ -859,6 +855,7 @@ func (c *controller) mergeWebhook(dst *webhook, policy kyvernov1.PolicyInterface
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
for _, gvr := range gvrList {
|
for _, gvr := range gvrList {
|
||||||
dst.set(gvr)
|
dst.set(gvr)
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ func (wh *webhook) buildRulesWithOperations(ops ...admissionregistrationv1.Opera
|
||||||
var rules []admissionregistrationv1.RuleWithOperations
|
var rules []admissionregistrationv1.RuleWithOperations
|
||||||
for gv, resources := range wh.rules {
|
for gv, resources := range wh.rules {
|
||||||
// if we have pods, we add pods/ephemeralcontainers by default
|
// if we have pods, we add pods/ephemeralcontainers by default
|
||||||
if gv.Group == "" && gv.Version == "v1" && resources.Has("pods") {
|
if (gv.Group == "" || gv.Group == "*") && (gv.Version == "v1" || gv.Version == "*") && (resources.Has("pods") || resources.Has("*")) {
|
||||||
resources.Insert("pods/ephemeralcontainers")
|
resources.Insert("pods/ephemeralcontainers")
|
||||||
}
|
}
|
||||||
rules = append(rules, admissionregistrationv1.RuleWithOperations{
|
rules = append(rules, admissionregistrationv1.RuleWithOperations{
|
||||||
|
@ -84,24 +84,6 @@ func (wh *webhook) isEmpty() bool {
|
||||||
return len(wh.rules) == 0
|
return len(wh.rules) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wh *webhook) setWildcard() {
|
|
||||||
wh.rules = map[schema.GroupVersion]sets.Set[string]{
|
|
||||||
{Group: "*", Version: "*"}: sets.New("*/*"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func hasWildcard(policies ...kyvernov1.PolicyInterface) bool {
|
|
||||||
for _, policy := range policies {
|
|
||||||
spec := policy.GetSpec()
|
|
||||||
for _, rule := range spec.Rules {
|
|
||||||
if kinds := rule.MatchResources.GetKinds(); slices.Contains(kinds, "*") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func objectMeta(name string, owner ...metav1.OwnerReference) metav1.ObjectMeta {
|
func objectMeta(name string, owner ...metav1.OwnerReference) metav1.ObjectMeta {
|
||||||
return metav1.ObjectMeta{
|
return metav1.ObjectMeta{
|
||||||
Name: name,
|
Name: name,
|
||||||
|
|
|
@ -9,13 +9,14 @@ import (
|
||||||
|
|
||||||
"gotest.tools/assert"
|
"gotest.tools/assert"
|
||||||
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
|
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_webhook_isEmpty(t *testing.T) {
|
func Test_webhook_isEmpty(t *testing.T) {
|
||||||
empty := newWebhook(DefaultWebhookTimeout, admissionregistrationv1.Ignore)
|
empty := newWebhook(DefaultWebhookTimeout, admissionregistrationv1.Ignore)
|
||||||
assert.Equal(t, empty.isEmpty(), true)
|
assert.Equal(t, empty.isEmpty(), true)
|
||||||
notEmpty := newWebhook(DefaultWebhookTimeout, admissionregistrationv1.Ignore)
|
notEmpty := newWebhook(DefaultWebhookTimeout, admissionregistrationv1.Ignore)
|
||||||
notEmpty.setWildcard()
|
notEmpty.set(schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"})
|
||||||
assert.Equal(t, notEmpty.isEmpty(), false)
|
assert.Equal(t, notEmpty.isEmpty(), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,28 +7,14 @@ metadata:
|
||||||
webhooks:
|
webhooks:
|
||||||
- rules:
|
- rules:
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- ""
|
- '*'
|
||||||
apiVersions:
|
apiVersions:
|
||||||
- v1
|
- '*'
|
||||||
operations:
|
operations:
|
||||||
- CREATE
|
- CREATE
|
||||||
- UPDATE
|
- UPDATE
|
||||||
- DELETE
|
- DELETE
|
||||||
- CONNECT
|
- CONNECT
|
||||||
resources:
|
resources:
|
||||||
- replicationcontrollers/scale
|
- '*/scale'
|
||||||
scope: '*'
|
|
||||||
- apiGroups:
|
|
||||||
- apps
|
|
||||||
apiVersions:
|
|
||||||
- v1
|
|
||||||
operations:
|
|
||||||
- CREATE
|
|
||||||
- UPDATE
|
|
||||||
- DELETE
|
|
||||||
- CONNECT
|
|
||||||
resources:
|
|
||||||
- deployments/scale
|
|
||||||
- replicasets/scale
|
|
||||||
- statefulsets/scale
|
|
||||||
scope: '*'
|
scope: '*'
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
apiVersion: kuttl.dev/v1beta1
|
||||||
|
kind: TestStep
|
||||||
|
apply:
|
||||||
|
- policy.yaml
|
||||||
|
assert:
|
||||||
|
- policy-assert.yaml
|
|
@ -0,0 +1,4 @@
|
||||||
|
apiVersion: kuttl.dev/v1beta1
|
||||||
|
kind: TestStep
|
||||||
|
assert:
|
||||||
|
- webhooks.yaml
|
|
@ -0,0 +1,9 @@
|
||||||
|
## Description
|
||||||
|
|
||||||
|
This test verifies the resource validation webhook is configured correctly when a policy targets all `*/*` resources and subresources.
|
||||||
|
|
||||||
|
## Steps
|
||||||
|
|
||||||
|
1. - Create a policy targeting `*/*`
|
||||||
|
- Assert policy gets ready
|
||||||
|
1. - Assert that the resource validation webhook is configured correctly
|
|
@ -0,0 +1,9 @@
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
name: require-labels
|
||||||
|
status:
|
||||||
|
conditions:
|
||||||
|
- reason: Succeeded
|
||||||
|
status: "True"
|
||||||
|
type: Ready
|
22
test/conformance/kuttl/webhooks/double-wildcard/policy.yaml
Normal file
22
test/conformance/kuttl/webhooks/double-wildcard/policy.yaml
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
name: require-labels
|
||||||
|
annotations:
|
||||||
|
pod-policies.kyverno.io/autogen-controllers: none
|
||||||
|
spec:
|
||||||
|
validationFailureAction: Audit
|
||||||
|
background: false
|
||||||
|
rules:
|
||||||
|
- name: require-team
|
||||||
|
match:
|
||||||
|
any:
|
||||||
|
- resources:
|
||||||
|
kinds:
|
||||||
|
- '*/*'
|
||||||
|
validate:
|
||||||
|
message: 'The label `team` is required.'
|
||||||
|
pattern:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
team: '?*'
|
|
@ -0,0 +1,21 @@
|
||||||
|
apiVersion: admissionregistration.k8s.io/v1
|
||||||
|
kind: ValidatingWebhookConfiguration
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
webhook.kyverno.io/managed-by: kyverno
|
||||||
|
name: kyverno-resource-validating-webhook-cfg
|
||||||
|
webhooks:
|
||||||
|
- failurePolicy: Fail
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- '*'
|
||||||
|
apiVersions:
|
||||||
|
- '*'
|
||||||
|
operations:
|
||||||
|
- CREATE
|
||||||
|
- UPDATE
|
||||||
|
- DELETE
|
||||||
|
- CONNECT
|
||||||
|
resources:
|
||||||
|
- '*/*'
|
||||||
|
scope: '*'
|
|
@ -1,6 +1,6 @@
|
||||||
## Description
|
## Description
|
||||||
|
|
||||||
This test verifies the resource validation webhook is configured correctly when a policy targets all `*` resource.
|
This test verifies the resource validation webhook is configured correctly when a policy targets all `*` resources.
|
||||||
|
|
||||||
## Steps
|
## Steps
|
||||||
|
|
||||||
|
|
|
@ -5,20 +5,6 @@ metadata:
|
||||||
webhook.kyverno.io/managed-by: kyverno
|
webhook.kyverno.io/managed-by: kyverno
|
||||||
name: kyverno-resource-validating-webhook-cfg
|
name: kyverno-resource-validating-webhook-cfg
|
||||||
webhooks:
|
webhooks:
|
||||||
- failurePolicy: Ignore
|
|
||||||
rules:
|
|
||||||
- apiGroups:
|
|
||||||
- '*'
|
|
||||||
apiVersions:
|
|
||||||
- '*'
|
|
||||||
operations:
|
|
||||||
- CREATE
|
|
||||||
- UPDATE
|
|
||||||
- DELETE
|
|
||||||
- CONNECT
|
|
||||||
resources:
|
|
||||||
- '*/*'
|
|
||||||
scope: '*'
|
|
||||||
- failurePolicy: Fail
|
- failurePolicy: Fail
|
||||||
rules:
|
rules:
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
|
@ -31,5 +17,6 @@ webhooks:
|
||||||
- DELETE
|
- DELETE
|
||||||
- CONNECT
|
- CONNECT
|
||||||
resources:
|
resources:
|
||||||
- '*/*'
|
- '*'
|
||||||
|
- pods/ephemeralcontainers
|
||||||
scope: '*'
|
scope: '*'
|
||||||
|
|
Loading…
Add table
Reference in a new issue