1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-07 00:17:13 +00:00
kyverno/pkg/controllers/webhook/utils.go
shuting 97ed53f6bb
feat: register webhook configurations for validatingpolicies (#11892)
* feat: add spec.webhookConfiguration

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* chore: refactor build webhook for kyverno policies

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* chore: update yamls

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* chore: add listers

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* feat: update api

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* chore: remove matchPolicy

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* chore: update crd yaml

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* chore: add short name

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* chore: update deepcopy

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* chore: upadte spec

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* chore: fix description

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* chore: add missing files

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* feat: register webhook for validatingpolicies

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* chore: fix import

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* chore: add unit tests

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* chore: update docs

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* chore: update manifests

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* chore: update unit tests

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* chore: update manifests

Signed-off-by: ShutingZhao <shuting@nirmata.com>

---------

Signed-off-by: ShutingZhao <shuting@nirmata.com>
2025-01-17 11:33:47 +02:00

176 lines
4.6 KiB
Go

package webhook
import (
"cmp"
"fmt"
"strings"
"github.com/kyverno/kyverno/api/kyverno"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/config"
"golang.org/x/exp/maps"
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/sets"
)
func collectResourceDescriptions(rule kyvernov1.Rule, defaultOps ...kyvernov1.AdmissionOperation) webhookConfig {
out := map[string]sets.Set[kyvernov1.AdmissionOperation]{}
for _, kind := range rule.MatchResources.ResourceDescription.Kinds {
if out[kind] == nil {
out[kind] = sets.New[kyvernov1.AdmissionOperation]()
}
ops := rule.MatchResources.ResourceDescription.Operations
if len(ops) == 0 {
ops = defaultOps
}
out[kind].Insert(ops...)
}
for _, value := range rule.MatchResources.All {
for _, kind := range value.Kinds {
if out[kind] == nil {
out[kind] = sets.New[kyvernov1.AdmissionOperation]()
}
ops := value.Operations
if len(ops) == 0 {
ops = defaultOps
}
out[kind].Insert(ops...)
}
}
for _, value := range rule.MatchResources.Any {
for _, kind := range value.Kinds {
if out[kind] == nil {
out[kind] = sets.New[kyvernov1.AdmissionOperation]()
}
ops := value.Operations
if len(ops) == 0 {
ops = defaultOps
}
out[kind].Insert(ops...)
}
}
// we consider only `exclude.any` elements and only if `kinds` is empty or if there's a corresponding kind in the match statement
// nothing else than `kinds` and `operations` must be set
if rule.ExcludeResources != nil {
for _, value := range rule.ExcludeResources.Any {
if !value.UserInfo.IsEmpty() {
continue
}
if value.Name != "" ||
len(value.Names) != 0 ||
len(value.Namespaces) != 0 ||
len(value.Annotations) != 0 ||
value.Selector != nil ||
value.NamespaceSelector != nil {
continue
}
kinds := value.Kinds
if len(kinds) == 0 {
kinds = maps.Keys(out)
}
ops := value.Operations
if len(ops) == 0 {
// if only kind was specified, clear all operations
ops = allOperations
}
for _, kind := range kinds {
if out[kind] != nil {
out[kind] = out[kind].Delete(ops...)
}
}
}
}
return out
}
func objectMeta(name string, annotations map[string]string, labels map[string]string, owner ...metav1.OwnerReference) metav1.ObjectMeta {
desiredLabels := make(map[string]string)
defaultLabels := map[string]string{
kyverno.LabelWebhookManagedBy: kyverno.ValueKyvernoApp,
}
maps.Copy(desiredLabels, labels)
maps.Copy(desiredLabels, defaultLabels)
return metav1.ObjectMeta{
Name: name,
Labels: desiredLabels,
Annotations: annotations,
OwnerReferences: owner,
}
}
func setRuleCount(rules []kyvernov1.Rule, status *kyvernov1.PolicyStatus) {
validateCount, generateCount, mutateCount, verifyImagesCount := 0, 0, 0, 0
for _, rule := range rules {
if !strings.HasPrefix(rule.Name, "autogen-") {
if rule.HasGenerate() {
generateCount += 1
}
if rule.HasValidate() {
validateCount += 1
}
if rule.HasMutate() {
mutateCount += 1
}
if rule.HasVerifyImages() {
verifyImagesCount += 1
}
}
}
status.RuleCount.Validate = validateCount
status.RuleCount.Generate = generateCount
status.RuleCount.Mutate = mutateCount
status.RuleCount.VerifyImages = verifyImagesCount
}
func capTimeout(maxWebhookTimeout int32) int32 {
if maxWebhookTimeout > 30 {
return 30
}
return maxWebhookTimeout
}
func newClientConfig(server string, servicePort int32, caBundle []byte, path string) admissionregistrationv1.WebhookClientConfig {
clientConfig := admissionregistrationv1.WebhookClientConfig{
CABundle: caBundle,
}
if server == "" {
clientConfig.Service = &admissionregistrationv1.ServiceReference{
Namespace: config.KyvernoNamespace(),
Name: config.KyvernoServiceName(),
Path: &path,
Port: &servicePort,
}
} else {
url := fmt.Sprintf("https://%s%s", server, path)
clientConfig.URL = &url
}
return clientConfig
}
func webhookNameAndPath(wh webhook, baseName, basePath string) (name string, path string) {
if wh.failurePolicy == ignore {
name = baseName + "-ignore"
path = basePath + "/ignore"
} else {
name = baseName + "-fail"
path = basePath + "/fail"
}
if wh.policyMeta.Name != "" {
name = name + "-finegrained-" + wh.key("-")
path = path + config.FineGrainedWebhookPath + "/" + wh.key("/")
}
return name, path
}
func less[T cmp.Ordered](a []T, b []T) int {
if x := cmp.Compare(len(a), len(b)); x != 0 {
return x
}
for i := range a {
if x := cmp.Compare(a[i], b[i]); x != 0 {
return x
}
}
return 0
}