2022-09-28 13:45:16 +02:00
|
|
|
package report
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/md5" //nolint:gosec
|
|
|
|
"encoding/hex"
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
|
2023-07-06 10:00:36 +02:00
|
|
|
"github.com/kyverno/kyverno/api/kyverno"
|
2022-09-28 13:45:16 +02:00
|
|
|
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
|
|
|
kyvernov1alpha2 "github.com/kyverno/kyverno/api/kyverno/v1alpha2"
|
2024-01-17 20:00:15 +02:00
|
|
|
kyvernov2beta1 "github.com/kyverno/kyverno/api/kyverno/v2beta1"
|
2023-09-05 14:42:17 +03:00
|
|
|
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
2022-09-28 13:45:16 +02:00
|
|
|
controllerutils "github.com/kyverno/kyverno/pkg/utils/controller"
|
2024-01-29 13:49:17 +02:00
|
|
|
"k8s.io/api/admissionregistration/v1alpha1"
|
|
|
|
admissionregistrationv1alpha1 "k8s.io/api/admissionregistration/v1alpha1"
|
2022-09-28 13:45:16 +02:00
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
2023-03-17 13:07:17 +01:00
|
|
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
2022-09-28 13:45:16 +02:00
|
|
|
"k8s.io/apimachinery/pkg/types"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2023-06-05 12:37:28 +02:00
|
|
|
LabelDomain = "kyverno.io"
|
2022-09-28 13:45:16 +02:00
|
|
|
// resource labels
|
2023-09-26 13:44:35 +02:00
|
|
|
LabelResourceHash = "audit.kyverno.io/resource.hash"
|
|
|
|
LabelResourceUid = "audit.kyverno.io/resource.uid"
|
|
|
|
LabelResourceGVR = "audit.kyverno.io/resource.gvr"
|
2024-01-30 15:53:37 +01:00
|
|
|
LabelResourceGroup = "audit.kyverno.io/resource.group"
|
|
|
|
LabelResourceVersion = "audit.kyverno.io/resource.version"
|
|
|
|
LabelResourceKind = "audit.kyverno.io/resource.kind"
|
|
|
|
LabelSource = "audit.kyverno.io/source"
|
2023-09-26 13:44:35 +02:00
|
|
|
AnnotationResourceNamespace = "audit.kyverno.io/resource.namespace"
|
|
|
|
AnnotationResourceName = "audit.kyverno.io/resource.name"
|
2022-09-28 13:45:16 +02:00
|
|
|
// policy labels
|
2024-01-29 13:49:17 +02:00
|
|
|
LabelDomainClusterPolicy = "cpol.kyverno.io"
|
|
|
|
LabelDomainPolicy = "pol.kyverno.io"
|
|
|
|
LabelPrefixClusterPolicy = LabelDomainClusterPolicy + "/"
|
|
|
|
LabelPrefixPolicy = LabelDomainPolicy + "/"
|
|
|
|
LabelPrefixPolicyException = "polex.kyverno.io/"
|
|
|
|
LabelPrefixValidatingAdmissionPolicy = "validatingadmissionpolicy.apiserver.io/"
|
|
|
|
LabelPrefixValidatingAdmissionPolicyBinding = "validatingadmissionpolicybinding.apiserver.io/"
|
2022-11-24 14:21:08 +01:00
|
|
|
// aggregated admission report label
|
|
|
|
LabelAggregatedReport = "audit.kyverno.io/report.aggregate"
|
2022-09-28 13:45:16 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
func IsPolicyLabel(label string) bool {
|
2024-01-29 13:49:17 +02:00
|
|
|
return strings.HasPrefix(label, LabelPrefixPolicy) ||
|
|
|
|
strings.HasPrefix(label, LabelPrefixClusterPolicy) ||
|
|
|
|
strings.HasPrefix(label, LabelPrefixPolicyException) ||
|
|
|
|
strings.HasPrefix(label, LabelPrefixValidatingAdmissionPolicy) ||
|
|
|
|
strings.HasPrefix(label, LabelPrefixValidatingAdmissionPolicyBinding)
|
2022-09-28 13:45:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func PolicyNameFromLabel(namespace, label string) (string, error) {
|
|
|
|
names := strings.Split(label, "/")
|
|
|
|
if len(names) == 2 {
|
|
|
|
if names[0] == LabelDomainClusterPolicy {
|
|
|
|
return names[1], nil
|
|
|
|
} else if names[0] == LabelDomainPolicy {
|
|
|
|
return namespace + "/" + names[1], nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return "", fmt.Errorf("cannot get policy name from label, incorrect format: %s", label)
|
|
|
|
}
|
|
|
|
|
2023-09-05 14:42:17 +03:00
|
|
|
func PolicyLabelPrefix(policy engineapi.GenericPolicy) string {
|
2022-09-28 13:45:16 +02:00
|
|
|
if policy.IsNamespaced() {
|
|
|
|
return LabelPrefixPolicy
|
|
|
|
}
|
2023-09-05 14:42:17 +03:00
|
|
|
if policy.GetType() == engineapi.KyvernoPolicyType {
|
|
|
|
return LabelPrefixClusterPolicy
|
|
|
|
}
|
|
|
|
return LabelPrefixValidatingAdmissionPolicy
|
2022-09-28 13:45:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func PolicyLabelDomain(policy kyvernov1.PolicyInterface) string {
|
|
|
|
if policy.IsNamespaced() {
|
|
|
|
return LabelDomainPolicy
|
|
|
|
}
|
|
|
|
return LabelDomainClusterPolicy
|
|
|
|
}
|
|
|
|
|
2023-09-05 14:42:17 +03:00
|
|
|
func PolicyLabel(policy engineapi.GenericPolicy) string {
|
2022-09-28 13:45:16 +02:00
|
|
|
return PolicyLabelPrefix(policy) + policy.GetName()
|
|
|
|
}
|
|
|
|
|
2024-01-17 20:00:15 +02:00
|
|
|
func PolicyExceptionLabel(exception kyvernov2beta1.PolicyException) string {
|
|
|
|
return LabelPrefixPolicyException + exception.GetName()
|
|
|
|
}
|
|
|
|
|
2024-01-29 13:49:17 +02:00
|
|
|
func ValidatingAdmissionPolicyBindingLabel(binding admissionregistrationv1alpha1.ValidatingAdmissionPolicyBinding) string {
|
|
|
|
return LabelPrefixValidatingAdmissionPolicyBinding + binding.GetName()
|
|
|
|
}
|
|
|
|
|
2023-06-05 12:37:28 +02:00
|
|
|
func CleanupKyvernoLabels(obj metav1.Object) {
|
|
|
|
labels := obj.GetLabels()
|
|
|
|
for key := range labels {
|
|
|
|
if strings.Contains(key, LabelDomain) {
|
|
|
|
delete(labels, key)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-28 13:45:16 +02:00
|
|
|
func SetManagedByKyvernoLabel(obj metav1.Object) {
|
2023-07-06 10:00:36 +02:00
|
|
|
controllerutils.SetLabel(obj, kyverno.LabelAppManagedBy, kyverno.ValueKyvernoApp)
|
2022-09-28 13:45:16 +02:00
|
|
|
}
|
|
|
|
|
2024-01-30 15:53:37 +01:00
|
|
|
func SetSource(obj metav1.Object, source string) {
|
|
|
|
controllerutils.SetLabel(obj, LabelSource, source)
|
|
|
|
}
|
|
|
|
|
2023-03-17 13:07:17 +01:00
|
|
|
func SetResourceUid(report kyvernov1alpha2.ReportInterface, uid types.UID) {
|
2022-09-28 13:45:16 +02:00
|
|
|
controllerutils.SetLabel(report, LabelResourceUid, string(uid))
|
|
|
|
}
|
|
|
|
|
2023-03-17 13:07:17 +01:00
|
|
|
func SetResourceGVR(report kyvernov1alpha2.ReportInterface, gvr schema.GroupVersionResource) {
|
|
|
|
if gvr.Group != "" {
|
|
|
|
controllerutils.SetLabel(report, LabelResourceGVR, gvr.Resource+"."+gvr.Version+"."+gvr.Group)
|
|
|
|
} else {
|
|
|
|
controllerutils.SetLabel(report, LabelResourceGVR, gvr.Resource+"."+gvr.Version)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-30 15:53:37 +01:00
|
|
|
func SetResourceGVK(report kyvernov1alpha2.ReportInterface, gvk schema.GroupVersionKind) {
|
|
|
|
controllerutils.SetLabel(report, LabelResourceGroup, gvk.Group)
|
|
|
|
controllerutils.SetLabel(report, LabelResourceVersion, gvk.Version)
|
|
|
|
controllerutils.SetLabel(report, LabelResourceKind, gvk.Kind)
|
|
|
|
}
|
|
|
|
|
2023-03-17 13:07:17 +01:00
|
|
|
func SetResourceNamespaceAndName(report kyvernov1alpha2.ReportInterface, namespace, name string) {
|
2023-09-26 13:44:35 +02:00
|
|
|
controllerutils.SetAnnotation(report, AnnotationResourceNamespace, namespace)
|
|
|
|
controllerutils.SetAnnotation(report, AnnotationResourceName, name)
|
2023-03-17 13:07:17 +01:00
|
|
|
}
|
|
|
|
|
2022-09-28 13:45:16 +02:00
|
|
|
func CalculateResourceHash(resource unstructured.Unstructured) string {
|
|
|
|
copy := resource.DeepCopy()
|
|
|
|
obj := copy.Object
|
|
|
|
labels := copy.GetLabels()
|
|
|
|
annotations := copy.GetAnnotations()
|
|
|
|
unstructured.RemoveNestedField(obj, "metadata")
|
|
|
|
unstructured.RemoveNestedField(obj, "status")
|
|
|
|
unstructured.RemoveNestedField(obj, "scale")
|
|
|
|
// fix for pods
|
|
|
|
unstructured.RemoveNestedField(obj, "spec", "nodeName")
|
|
|
|
input := []interface{}{labels, annotations, obj}
|
|
|
|
data, err := json.Marshal(input)
|
|
|
|
if err != nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
hash := md5.Sum(data) //nolint:gosec
|
|
|
|
return hex.EncodeToString(hash[:])
|
|
|
|
}
|
|
|
|
|
|
|
|
func SetResourceVersionLabels(report kyvernov1alpha2.ReportInterface, resource *unstructured.Unstructured) {
|
|
|
|
if resource != nil {
|
|
|
|
controllerutils.SetLabel(report, LabelResourceHash, CalculateResourceHash(*resource))
|
|
|
|
} else {
|
|
|
|
controllerutils.SetLabel(report, LabelResourceHash, "")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-05 14:42:17 +03:00
|
|
|
func SetPolicyLabel(report kyvernov1alpha2.ReportInterface, policy engineapi.GenericPolicy) {
|
2022-09-28 13:45:16 +02:00
|
|
|
controllerutils.SetLabel(report, PolicyLabel(policy), policy.GetResourceVersion())
|
|
|
|
}
|
|
|
|
|
2024-01-17 20:00:15 +02:00
|
|
|
func SetPolicyExceptionLabel(report kyvernov1alpha2.ReportInterface, exception kyvernov2beta1.PolicyException) {
|
|
|
|
controllerutils.SetLabel(report, PolicyExceptionLabel(exception), exception.GetResourceVersion())
|
|
|
|
}
|
|
|
|
|
2024-01-29 13:49:17 +02:00
|
|
|
func SetValidatingAdmissionPolicyBindingLabel(report kyvernov1alpha2.ReportInterface, binding v1alpha1.ValidatingAdmissionPolicyBinding) {
|
|
|
|
controllerutils.SetLabel(report, ValidatingAdmissionPolicyBindingLabel(binding), binding.GetResourceVersion())
|
|
|
|
}
|
|
|
|
|
2024-01-30 15:53:37 +01:00
|
|
|
func GetSource(report metav1.Object) string {
|
|
|
|
return controllerutils.GetLabel(report, LabelSource)
|
|
|
|
}
|
|
|
|
|
2022-09-28 13:45:16 +02:00
|
|
|
func GetResourceUid(report metav1.Object) types.UID {
|
2023-03-17 13:07:17 +01:00
|
|
|
return types.UID(controllerutils.GetLabel(report, LabelResourceUid))
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetResourceGVR(report metav1.Object) schema.GroupVersionResource {
|
|
|
|
arg := controllerutils.GetLabel(report, LabelResourceGVR)
|
|
|
|
dots := strings.Count(arg, ".")
|
|
|
|
if dots >= 2 {
|
|
|
|
s := strings.SplitN(arg, ".", 3)
|
|
|
|
return schema.GroupVersionResource{Group: s[2], Version: s[1], Resource: s[0]}
|
|
|
|
} else if dots == 1 {
|
|
|
|
s := strings.SplitN(arg, ".", 2)
|
|
|
|
return schema.GroupVersionResource{Version: s[1], Resource: s[0]}
|
|
|
|
}
|
|
|
|
return schema.GroupVersionResource{Resource: arg}
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetResourceNamespaceAndName(report kyvernov1alpha2.ReportInterface) (string, string) {
|
2023-09-26 13:44:35 +02:00
|
|
|
return controllerutils.GetAnnotation(report, AnnotationResourceNamespace), controllerutils.GetAnnotation(report, AnnotationResourceName)
|
2022-09-28 13:45:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func GetResourceHash(report metav1.Object) string {
|
|
|
|
return report.GetLabels()[LabelResourceHash]
|
|
|
|
}
|
|
|
|
|
|
|
|
func CompareHash(report metav1.Object, hash string) bool {
|
|
|
|
return GetResourceHash(report) == hash
|
|
|
|
}
|