2022-05-02 05:14:32 +00:00
package event
import (
"fmt"
"strings"
2022-05-17 11:12:43 +00:00
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
2024-06-26 08:48:32 +00:00
kyvernov2 "github.com/kyverno/kyverno/api/kyverno/v2"
2023-01-30 11:41:09 +00:00
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
2023-12-22 10:47:22 +00:00
corev1 "k8s.io/api/core/v1"
2022-05-02 05:14:32 +00:00
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2023-12-22 10:47:22 +00:00
"k8s.io/apimachinery/pkg/types"
2022-05-02 05:14:32 +00:00
)
2023-04-05 22:55:42 +00:00
func NewPolicyFailEvent ( source Source , reason Reason , engineResponse engineapi . EngineResponse , ruleResp engineapi . RuleResponse , blocked bool ) Info {
2023-07-26 14:06:51 +00:00
action := ResourcePassed
if blocked {
action = ResourceBlocked
}
2023-09-05 11:42:17 +00:00
pol := engineResponse . Policy ( )
2023-12-22 10:47:22 +00:00
regarding := corev1 . ObjectReference {
2024-01-18 14:02:07 +00:00
APIVersion : pol . GetAPIVersion ( ) ,
2023-12-22 10:47:22 +00:00
Kind : pol . GetKind ( ) ,
Name : pol . GetName ( ) ,
Namespace : pol . GetNamespace ( ) ,
UID : pol . MetaObject ( ) . GetUID ( ) ,
}
related := engineResponse . GetResourceSpec ( )
2022-06-22 16:37:46 +00:00
return Info {
2023-12-22 10:47:22 +00:00
Regarding : regarding ,
Related : & corev1 . ObjectReference {
APIVersion : related . APIVersion ,
Kind : related . Kind ,
Name : related . Name ,
Namespace : related . Namespace ,
UID : types . UID ( related . UID ) ,
} ,
Reason : reason ,
Source : source ,
Message : buildPolicyEventMessage ( ruleResp , engineResponse . GetResourceSpec ( ) , blocked ) ,
Action : action ,
2022-05-02 05:14:32 +00:00
}
}
2023-04-05 22:55:42 +00:00
func buildPolicyEventMessage ( resp engineapi . RuleResponse , resource engineapi . ResourceSpec , blocked bool ) string {
2022-05-02 05:14:32 +00:00
var b strings . Builder
if resource . Namespace != "" {
fmt . Fprintf ( & b , "%s %s/%s" , resource . Kind , resource . Namespace , resource . Name )
} else {
fmt . Fprintf ( & b , "%s %s" , resource . Kind , resource . Name )
}
2023-04-05 10:35:38 +00:00
fmt . Fprintf ( & b , ": [%s] %s" , resp . Name ( ) , resp . Status ( ) )
2022-05-02 05:14:32 +00:00
if blocked {
fmt . Fprintf ( & b , " (blocked)" )
}
2023-04-05 10:35:38 +00:00
if resp . Message ( ) != "" {
fmt . Fprintf ( & b , "; %s" , resp . Message ( ) )
2022-05-02 05:14:32 +00:00
}
2024-07-10 14:31:32 +00:00
return b . String ( )
2022-05-02 05:14:32 +00:00
}
2023-03-23 12:58:52 +00:00
func NewPolicyAppliedEvent ( source Source , engineResponse engineapi . EngineResponse ) Info {
2023-02-10 14:04:41 +00:00
resource := engineResponse . Resource
2022-06-22 16:37:46 +00:00
var bldr strings . Builder
defer bldr . Reset ( )
2022-05-02 05:14:32 +00:00
2023-07-10 11:22:28 +00:00
var res string
2023-02-10 14:04:41 +00:00
if resource . GetNamespace ( ) != "" {
2023-07-10 11:22:28 +00:00
res = fmt . Sprintf ( "%s %s/%s" , resource . GetKind ( ) , resource . GetNamespace ( ) , resource . GetName ( ) )
2022-05-02 05:14:32 +00:00
} else {
2023-07-10 11:22:28 +00:00
res = fmt . Sprintf ( "%s %s" , resource . GetKind ( ) , resource . GetName ( ) )
}
2023-07-26 14:06:51 +00:00
var action Action
2023-10-31 13:53:28 +00:00
policy := engineResponse . Policy ( )
if policy . GetType ( ) == engineapi . KyvernoPolicyType {
2024-01-20 17:20:22 +00:00
pol := engineResponse . Policy ( ) . AsKyvernoPolicy ( )
2023-10-31 13:53:28 +00:00
hasValidate := pol . GetSpec ( ) . HasValidate ( )
hasVerifyImages := pol . GetSpec ( ) . HasVerifyImages ( )
hasMutate := pol . GetSpec ( ) . HasMutate ( )
if hasValidate || hasVerifyImages {
fmt . Fprintf ( & bldr , "%s: pass" , res )
action = ResourcePassed
} else if hasMutate {
fmt . Fprintf ( & bldr , "%s is successfully mutated" , res )
action = ResourceMutated
}
} else {
2023-07-10 11:22:28 +00:00
fmt . Fprintf ( & bldr , "%s: pass" , res )
2023-07-26 14:06:51 +00:00
action = ResourcePassed
2022-05-02 05:14:32 +00:00
}
2023-12-22 10:47:22 +00:00
regarding := corev1 . ObjectReference {
2024-01-18 14:02:07 +00:00
APIVersion : policy . GetAPIVersion ( ) ,
2023-12-22 10:47:22 +00:00
Kind : policy . GetKind ( ) ,
Name : policy . GetName ( ) ,
Namespace : policy . GetNamespace ( ) ,
UID : policy . MetaObject ( ) . GetUID ( ) ,
}
related := engineResponse . GetResourceSpec ( )
2022-06-22 16:37:46 +00:00
return Info {
2023-12-22 10:47:22 +00:00
Regarding : regarding ,
Related : & corev1 . ObjectReference {
APIVersion : related . APIVersion ,
Kind : related . Kind ,
Name : related . Name ,
Namespace : related . Namespace ,
UID : types . UID ( related . UID ) ,
} ,
Reason : PolicyApplied ,
Source : source ,
Message : bldr . String ( ) ,
Action : action ,
2022-05-02 05:14:32 +00:00
}
}
2023-04-05 22:55:42 +00:00
func NewResourceViolationEvent ( source Source , reason Reason , engineResponse engineapi . EngineResponse , ruleResp engineapi . RuleResponse ) Info {
2022-06-22 16:37:46 +00:00
var bldr strings . Builder
defer bldr . Reset ( )
2023-09-05 11:42:17 +00:00
pol := engineResponse . Policy ( )
2023-08-15 19:41:43 +00:00
fmt . Fprintf ( & bldr , "policy %s/%s %s: %s" , pol . GetName ( ) ,
2023-04-05 10:35:38 +00:00
ruleResp . Name ( ) , ruleResp . Status ( ) , ruleResp . Message ( ) )
2022-05-02 05:14:32 +00:00
resource := engineResponse . GetResourceSpec ( )
2023-12-22 10:47:22 +00:00
regarding := corev1 . ObjectReference {
APIVersion : resource . APIVersion ,
Kind : resource . Kind ,
Name : resource . Name ,
Namespace : resource . Namespace ,
UID : types . UID ( resource . UID ) ,
}
2022-06-22 16:37:46 +00:00
return Info {
2023-12-22 10:47:22 +00:00
Regarding : regarding ,
2023-01-26 21:19:02 +00:00
Reason : reason ,
2022-05-02 05:14:32 +00:00
Source : source ,
2022-06-22 16:37:46 +00:00
Message : bldr . String ( ) ,
2023-07-26 14:06:51 +00:00
Action : ResourcePassed ,
2022-05-02 05:14:32 +00:00
}
}
2023-07-10 11:22:28 +00:00
func NewResourceGenerationEvent ( policy , rule string , source Source , resource kyvernov1 . ResourceSpec ) Info {
msg := fmt . Sprintf ( "Created %s %s as a result of applying policy %s/%s" , resource . GetKind ( ) , resource . GetName ( ) , policy , rule )
2023-12-22 10:47:22 +00:00
regarding := corev1 . ObjectReference {
APIVersion : resource . APIVersion ,
Kind : resource . Kind ,
Name : resource . Name ,
Namespace : resource . Namespace ,
UID : resource . UID ,
}
2023-07-10 11:22:28 +00:00
return Info {
2023-12-22 10:47:22 +00:00
Regarding : regarding ,
2023-07-10 11:22:28 +00:00
Source : source ,
Reason : PolicyApplied ,
Message : msg ,
2023-07-26 14:06:51 +00:00
Action : None ,
2023-07-10 11:22:28 +00:00
}
}
2023-07-26 14:06:51 +00:00
func NewBackgroundFailedEvent ( err error , policy kyvernov1 . PolicyInterface , rule string , source Source , resource kyvernov1 . ResourceSpec ) [ ] Info {
2022-05-02 05:14:32 +00:00
var events [ ] Info
2023-12-22 10:47:22 +00:00
regarding := corev1 . ObjectReference {
// TODO: iirc it's not safe to assume api version is set
APIVersion : "kyverno.io/v1" ,
Kind : policy . GetKind ( ) ,
Name : policy . GetName ( ) ,
Namespace : policy . GetNamespace ( ) ,
UID : policy . GetUID ( ) ,
}
2024-08-13 17:14:06 +00:00
var msg string
if rule == "" {
msg = fmt . Sprintf ( "policy %s error: %v" , policy . GetName ( ) , err )
} else {
msg = fmt . Sprintf ( "policy %s/%s error: %v" , policy . GetName ( ) , rule , err )
}
2022-05-02 05:14:32 +00:00
events = append ( events , Info {
2023-12-22 10:47:22 +00:00
Regarding : regarding ,
Related : & corev1 . ObjectReference {
APIVersion : resource . APIVersion ,
Kind : resource . Kind ,
Name : resource . Name ,
Namespace : resource . Namespace ,
UID : resource . UID ,
} ,
Source : source ,
Reason : PolicyError ,
2024-08-13 17:14:06 +00:00
Message : msg ,
2023-12-22 10:47:22 +00:00
Action : None ,
2022-05-02 05:14:32 +00:00
} )
return events
}
2023-07-26 14:06:51 +00:00
func NewBackgroundSuccessEvent ( source Source , policy kyvernov1 . PolicyInterface , resources [ ] kyvernov1 . ResourceSpec ) [ ] Info {
2024-05-20 09:16:35 +00:00
events := make ( [ ] Info , 0 , len ( resources ) )
2023-07-10 11:22:28 +00:00
msg := "resource generated"
2023-07-26 14:06:51 +00:00
action := ResourceGenerated
2023-07-10 11:22:28 +00:00
if source == MutateExistingController {
msg = "resource mutated"
2023-07-26 14:06:51 +00:00
action = ResourceMutated
2023-07-10 11:22:28 +00:00
}
2023-12-22 10:47:22 +00:00
regarding := corev1 . ObjectReference {
// TODO: iirc it's not safe to assume api version is set
APIVersion : "kyverno.io/v1" ,
Kind : policy . GetKind ( ) ,
Name : policy . GetName ( ) ,
Namespace : policy . GetNamespace ( ) ,
UID : policy . GetUID ( ) ,
}
2023-07-26 14:06:51 +00:00
for _ , res := range resources {
events = append ( events , Info {
2023-12-22 10:47:22 +00:00
Regarding : regarding ,
Related : & corev1 . ObjectReference {
APIVersion : res . APIVersion ,
Kind : res . Kind ,
Name : res . Name ,
Namespace : res . Namespace ,
UID : res . UID ,
} ,
Source : source ,
Reason : PolicyApplied ,
Message : msg ,
Action : action ,
2023-07-26 14:06:51 +00:00
} )
}
2022-05-02 05:14:32 +00:00
return events
}
2022-12-22 23:34:09 +00:00
2023-04-05 22:55:42 +00:00
func NewPolicyExceptionEvents ( engineResponse engineapi . EngineResponse , ruleResp engineapi . RuleResponse , source Source ) [ ] Info {
2023-01-13 09:18:14 +00:00
var exceptionMessage string
2024-07-25 17:36:19 +00:00
exceptions := ruleResp . Exceptions ( )
exceptionNames := make ( [ ] string , 0 , len ( exceptions ) )
events := make ( [ ] Info , 0 , len ( exceptions ) )
// build the events of the policy exceptions
pol := engineResponse . Policy ( ) . AsKyvernoPolicy ( )
2023-08-15 19:41:43 +00:00
if pol . GetNamespace ( ) == "" {
exceptionMessage = fmt . Sprintf ( "resource %s was skipped from policy rule %s/%s" , resourceKey ( engineResponse . PatchedResource ) , pol . GetName ( ) , ruleResp . Name ( ) )
2023-01-13 09:18:14 +00:00
} else {
2023-08-15 19:41:43 +00:00
exceptionMessage = fmt . Sprintf ( "resource %s was skipped from policy rule %s/%s/%s" , resourceKey ( engineResponse . PatchedResource ) , pol . GetNamespace ( ) , pol . GetName ( ) , ruleResp . Name ( ) )
2023-01-13 09:18:14 +00:00
}
2024-07-25 17:36:19 +00:00
related := engineResponse . GetResourceSpec ( )
for _ , exception := range exceptions {
ns := exception . GetNamespace ( )
name := exception . GetName ( )
exceptionNames = append ( exceptionNames , ns + "/" + name )
exceptionEvent := Info {
Regarding : corev1 . ObjectReference {
// TODO: iirc it's not safe to assume api version is set
APIVersion : "kyverno.io/v2" ,
Kind : "PolicyException" ,
Name : name ,
Namespace : ns ,
UID : exception . GetUID ( ) ,
} ,
Related : & corev1 . ObjectReference {
APIVersion : related . APIVersion ,
Kind : related . Kind ,
Name : related . Name ,
Namespace : related . Namespace ,
UID : types . UID ( related . UID ) ,
} ,
Reason : PolicySkipped ,
Message : exceptionMessage ,
Source : source ,
Action : ResourcePassed ,
}
events = append ( events , exceptionEvent )
}
// build the policy events
policyMessage := fmt . Sprintf ( "resource %s was skipped from rule %s due to policy exceptions %s" , resourceKey ( engineResponse . PatchedResource ) , ruleResp . Name ( ) , strings . Join ( exceptionNames , ", " ) )
2023-12-22 10:47:22 +00:00
regarding := corev1 . ObjectReference {
// TODO: iirc it's not safe to assume api version is set
APIVersion : "kyverno.io/v1" ,
Kind : pol . GetKind ( ) ,
Name : pol . GetName ( ) ,
Namespace : pol . GetNamespace ( ) ,
UID : pol . GetUID ( ) ,
}
2023-01-13 09:18:14 +00:00
policyEvent := Info {
2023-12-22 10:47:22 +00:00
Regarding : regarding ,
Related : & corev1 . ObjectReference {
APIVersion : related . APIVersion ,
Kind : related . Kind ,
Name : related . Name ,
Namespace : related . Namespace ,
UID : types . UID ( related . UID ) ,
} ,
Reason : PolicySkipped ,
Message : policyMessage ,
Source : source ,
Action : ResourcePassed ,
2023-01-13 09:18:14 +00:00
}
2024-07-25 17:36:19 +00:00
events = append ( events , policyEvent )
return events
2022-12-22 23:34:09 +00:00
}
2023-03-02 17:19:32 +00:00
2024-06-26 08:48:32 +00:00
func NewCleanupPolicyEvent ( policy kyvernov2 . CleanupPolicyInterface , resource unstructured . Unstructured , err error ) Info {
2023-12-22 10:47:22 +00:00
regarding := corev1 . ObjectReference {
// TODO: iirc it's not safe to assume api version is set
2024-06-24 11:54:57 +00:00
APIVersion : "kyverno.io/v2" ,
2023-12-22 10:47:22 +00:00
Kind : policy . GetKind ( ) ,
Name : policy . GetName ( ) ,
Namespace : policy . GetNamespace ( ) ,
UID : policy . GetUID ( ) ,
}
related := & corev1 . ObjectReference {
APIVersion : resource . GetAPIVersion ( ) ,
Kind : resource . GetKind ( ) ,
Namespace : resource . GetNamespace ( ) ,
Name : resource . GetName ( ) ,
}
2023-07-18 10:01:09 +00:00
if err == nil {
return Info {
2023-12-22 10:47:22 +00:00
Regarding : regarding ,
Related : related ,
Source : CleanupController ,
Action : ResourceCleanedUp ,
Reason : PolicyApplied ,
Message : fmt . Sprintf ( "successfully cleaned up the target resource %v/%v/%v" , resource . GetKind ( ) , resource . GetNamespace ( ) , resource . GetName ( ) ) ,
2023-07-18 10:01:09 +00:00
}
} else {
return Info {
2023-12-22 10:47:22 +00:00
Regarding : regarding ,
Related : related ,
Source : CleanupController ,
Action : None ,
Reason : PolicyError ,
Message : fmt . Sprintf ( "failed to clean up the target resource %v/%v/%v: %v" , resource . GetKind ( ) , resource . GetNamespace ( ) , resource . GetName ( ) , err . Error ( ) ) ,
2023-07-18 10:01:09 +00:00
}
}
}
2023-10-09 10:16:35 +00:00
func NewValidatingAdmissionPolicyEvent ( policy kyvernov1 . PolicyInterface , vapName , vapBindingName string ) [ ] Info {
2023-12-22 10:47:22 +00:00
regarding := corev1 . ObjectReference {
// TODO: iirc it's not safe to assume api version is set
APIVersion : "kyverno.io/v1" ,
Kind : policy . GetKind ( ) ,
Name : policy . GetName ( ) ,
Namespace : policy . GetNamespace ( ) ,
UID : policy . GetUID ( ) ,
}
2023-10-09 10:16:35 +00:00
vapEvent := Info {
2023-12-22 10:47:22 +00:00
Regarding : regarding ,
Related : & corev1 . ObjectReference {
2024-08-29 15:31:25 +00:00
APIVersion : "admissionregistration.k8s.io/v1beta1" ,
2023-12-22 10:47:22 +00:00
Kind : "ValidatingAdmissionPolicy" ,
Name : vapName ,
} ,
Source : GeneratePolicyController ,
Action : ResourceGenerated ,
Reason : PolicyApplied ,
Message : fmt . Sprintf ( "successfully generated validating admission policy %s from policy %s" , vapName , policy . GetName ( ) ) ,
2023-10-09 10:16:35 +00:00
}
vapBindingEvent := Info {
2023-12-22 10:47:22 +00:00
Regarding : regarding ,
Related : & corev1 . ObjectReference {
2024-08-29 15:31:25 +00:00
APIVersion : "admissionregistration.k8s.io/v1beta1" ,
2023-12-22 10:47:22 +00:00
Kind : "ValidatingAdmissionPolicyBinding" ,
Name : vapBindingName ,
} ,
Source : GeneratePolicyController ,
Action : ResourceGenerated ,
Reason : PolicyApplied ,
Message : fmt . Sprintf ( "successfully generated validating admission policy binding %s from policy %s" , vapBindingName , policy . GetName ( ) ) ,
2023-10-09 10:16:35 +00:00
}
return [ ] Info { vapEvent , vapBindingEvent }
}
2023-03-10 17:17:10 +00:00
func NewFailedEvent ( err error , policy , rule string , source Source , resource kyvernov1 . ResourceSpec ) Info {
2024-08-13 17:14:06 +00:00
var msg string
if rule == "" {
msg = fmt . Sprintf ( "policy %s error: %v" , policy , err )
} else {
msg = fmt . Sprintf ( "policy %s/%s error: %v" , policy , rule , err )
}
2023-03-10 17:17:10 +00:00
return Info {
2023-12-22 10:47:22 +00:00
Regarding : corev1 . ObjectReference {
APIVersion : resource . APIVersion ,
Kind : resource . Kind ,
Name : resource . Name ,
Namespace : resource . Namespace ,
UID : resource . UID ,
} ,
Source : source ,
Reason : PolicyError ,
2024-08-13 17:14:06 +00:00
Message : msg ,
2023-12-22 10:47:22 +00:00
Action : None ,
2023-03-10 17:17:10 +00:00
}
}
2023-03-02 17:19:32 +00:00
func resourceKey ( resource unstructured . Unstructured ) string {
if resource . GetNamespace ( ) != "" {
return strings . Join ( [ ] string { resource . GetKind ( ) , resource . GetNamespace ( ) , resource . GetName ( ) } , "/" )
}
return strings . Join ( [ ] string { resource . GetKind ( ) , resource . GetName ( ) } , "/" )
}