1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-14 11:57:48 +00:00

update validation logic

This commit is contained in:
Jim Bugwadia 2020-12-23 15:10:07 -08:00
parent d0347afa59
commit e2f10c6f83
30 changed files with 393 additions and 377 deletions

View file

@ -15,14 +15,19 @@ import (
//Interface to manage context operations
type Interface interface {
//AddJSON merges the json with context
// AddJSON merges the json with context
AddJSON(dataRaw []byte) error
//AddResource merges resource json under request.object
// AddResource merges resource json under request.object
AddResource(dataRaw []byte) error
//AddUserInfo merges userInfo json under kyverno.userInfo
// AddUserInfo merges userInfo json under kyverno.userInfo
AddUserInfo(userInfo kyverno.UserInfo) error
//AddSA merges serrviceaccount
AddSA(userName string) error
// AddServiceAccount merges ServiceAccount types
AddServiceAccount(userName string) error
EvalInterface
}
@ -126,8 +131,8 @@ func (ctx *Context) AddUserInfo(userRequestInfo kyverno.RequestInfo) error {
return ctx.AddJSON(objRaw)
}
//AddSA removes prefix 'system:serviceaccount:' and namespace, then loads only SA name and SA namespace
func (ctx *Context) AddSA(userName string) error {
//AddServiceAccount removes prefix 'system:serviceaccount:' and namespace, then loads only SA name and SA namespace
func (ctx *Context) AddServiceAccount(userName string) error {
saPrefix := "system:serviceaccount:"
var sa string
saName := ""

View file

@ -93,7 +93,7 @@ func Test_addResourceAndUserContext(t *testing.T) {
t.Error("exected result does not match")
}
// Add service account Name
err = ctx.AddSA(userRequestInfo.AdmissionUserInfo.Username)
err = ctx.AddServiceAccount(userRequestInfo.AdmissionUserInfo.Username)
if err != nil {
t.Error(err)
}

View file

@ -12,16 +12,16 @@ import (
// 1. validate variables to be substitute in the general ruleInfo (match,exclude,condition)
// - the caller has to check the ruleResponse to determine whether the path exist
// 2. returns the list of rules that are applicable on this policy and resource, if 1 succeed
func Generate(policyContext PolicyContext) (resp response.EngineResponse) {
func Generate(policyContext PolicyContext) (resp *response.EngineResponse) {
return filterRules(policyContext)
}
func filterRules(policyContext PolicyContext) response.EngineResponse {
func filterRules(policyContext PolicyContext) *response.EngineResponse {
kind := policyContext.NewResource.GetKind()
name := policyContext.NewResource.GetName()
namespace := policyContext.NewResource.GetNamespace()
resp := response.EngineResponse{
resp := &response.EngineResponse{
PolicyResponse: response.PolicyResponse{
Policy: policyContext.Policy.Name,
Resource: response.ResourceSpec{
@ -57,7 +57,7 @@ func filterRule(rule kyverno.Rule, policyContext PolicyContext) *response.RuleRe
newResource := policyContext.NewResource
oldResource := policyContext.OldResource
admissionInfo := policyContext.AdmissionInfo
ctx := policyContext.Context
ctx := policyContext.JSONContext
resCache := policyContext.ResourceCache
jsonContext := policyContext.JSONContext
excludeGroupRole := policyContext.ExcludeGroupRole

View file

@ -22,11 +22,12 @@ const (
)
// Mutate performs mutation. Overlay first and then mutation patches
func Mutate(policyContext PolicyContext) (resp response.EngineResponse) {
func Mutate(policyContext *PolicyContext) (resp *response.EngineResponse) {
resp = &response.EngineResponse{}
startTime := time.Now()
policy := policyContext.Policy
patchedResource := policyContext.NewResource
ctx := policyContext.Context
ctx := policyContext.JSONContext
resCache := policyContext.ResourceCache
jsonContext := policyContext.JSONContext
@ -35,10 +36,10 @@ func Mutate(policyContext PolicyContext) (resp response.EngineResponse) {
logger.V(4).Info("start policy processing", "startTime", startTime)
startMutateResultResponse(&resp, policy, patchedResource)
defer endMutateResultResponse(logger, &resp, startTime)
startMutateResultResponse(resp, policy, patchedResource)
defer endMutateResultResponse(logger, resp, startTime)
if SkipPolicyApplication(policy, patchedResource) {
if ManagedPodResource(policy, patchedResource) {
logger.V(5).Info("skip applying policy as direct changes to pods managed by workload controllers are not allowed", "policy", policy.GetName())
resp.PatchedResource = patchedResource
return
@ -58,6 +59,7 @@ func Mutate(policyContext PolicyContext) (resp response.EngineResponse) {
if len(policyContext.ExcludeGroupRole) > 0 {
excludeResource = policyContext.ExcludeGroupRole
}
if err := MatchesResourceDescription(patchedResource, rule, policyContext.AdmissionInfo, excludeResource); err != nil {
logger.V(3).Info("resource not matched", "reason", err.Error())
continue
@ -79,7 +81,6 @@ func Mutate(policyContext PolicyContext) (resp response.EngineResponse) {
}
mutation := rule.Mutation.DeepCopy()
mutateHandler := mutate.CreateMutateHandler(rule.Name, mutation, patchedResource, ctx, logger)
ruleResponse, patchedResource = mutateHandler.Handle()
if ruleResponse.Success {
@ -87,11 +88,12 @@ func Mutate(policyContext PolicyContext) (resp response.EngineResponse) {
if ruleResponse.Patches == nil {
continue
}
logger.V(4).Info("mutate rule applied successfully", "ruleName", rule.Name)
}
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResponse)
incrementAppliedRuleCount(&resp)
incrementAppliedRuleCount(resp)
}
resp.PatchedResource = patchedResource
@ -103,9 +105,11 @@ func incrementAppliedRuleCount(resp *response.EngineResponse) {
}
func startMutateResultResponse(resp *response.EngineResponse, policy kyverno.ClusterPolicy, resource unstructured.Unstructured) {
// set policy information
if resp == nil {
return
}
resp.PolicyResponse.Policy = policy.Name
// resource details
resp.PolicyResponse.Resource.Name = resource.GetName()
resp.PolicyResponse.Resource.Namespace = resource.GetNamespace()
resp.PolicyResponse.Resource.Kind = resource.GetKind()
@ -113,6 +117,10 @@ func startMutateResultResponse(resp *response.EngineResponse, policy kyverno.Clu
}
func endMutateResultResponse(logger logr.Logger, resp *response.EngineResponse, startTime time.Time) {
if resp == nil {
return
}
resp.PolicyResponse.ProcessingTime = time.Since(startTime)
logger.V(4).Info("finished processing policy", "processingTime", resp.PolicyResponse.ProcessingTime.String(), "mutationRulesApplied", resp.PolicyResponse.RulesAppliedCount)
}

View file

@ -84,9 +84,9 @@ func Test_VariableSubstitutionOverlay(t *testing.T) {
if err != nil {
t.Error(err)
}
policyContext := PolicyContext{
policyContext := &PolicyContext{
Policy: policy,
Context: ctx,
JSONContext: ctx,
NewResource: *resourceUnstructured}
er := Mutate(policyContext)
t.Log(string(expectedPatch))
@ -155,9 +155,9 @@ func Test_variableSubstitutionPathNotExist(t *testing.T) {
err = ctx.AddResource(resourceRaw)
assert.NilError(t, err)
policyContext := PolicyContext{
policyContext := &PolicyContext{
Policy: policy,
Context: ctx,
JSONContext: ctx,
NewResource: *resourceUnstructured}
er := Mutate(policyContext)
expectedErrorStr := "variable request.object.metadata.name1 not resolved at path /spec/name"

View file

@ -26,9 +26,6 @@ type PolicyContext struct {
// Dynamic client - used by generate
Client *client.Client
// Contexts to store resources
Context context.EvalInterface
// Config handler
ExcludeGroupRole []string

View file

@ -269,10 +269,15 @@ func MatchesResourceDescription(resourceRef unstructured.Unstructured, ruleRef k
return nil
}
func copyConditions(original []kyverno.Condition) []kyverno.Condition {
if original == nil || len(original) == 0 {
return []kyverno.Condition{}
}
var copy []kyverno.Condition
for _, condition := range original {
copy = append(copy, *condition.DeepCopy())
}
return copy
}
@ -288,10 +293,10 @@ func excludeResource(resource unstructured.Unstructured) bool {
return false
}
// SkipPolicyApplication returns true:
// ManagedPodResource returns true:
// - if the policy has auto-gen annotation && resource == Pod
// - if the auto-gen contains cronJob && resource == Job
func SkipPolicyApplication(policy kyverno.ClusterPolicy, resource unstructured.Unstructured) bool {
func ManagedPodResource(policy kyverno.ClusterPolicy, resource unstructured.Unstructured) bool {
if policy.HasAutoGenAnnotation() && excludeResource(resource) {
return true
}

View file

@ -14,238 +14,192 @@ import (
"github.com/kyverno/kyverno/pkg/engine/utils"
"github.com/kyverno/kyverno/pkg/engine/validate"
"github.com/kyverno/kyverno/pkg/engine/variables"
"github.com/kyverno/kyverno/pkg/resourcecache"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/log"
)
//Validate applies validation rules from policy on the resource
func Validate(policyContext PolicyContext) (resp response.EngineResponse) {
func Validate(policyContext *PolicyContext) (resp *response.EngineResponse) {
resp = &response.EngineResponse{}
startTime := time.Now()
policy := policyContext.Policy
newR := policyContext.NewResource
oldR := policyContext.OldResource
ctx := policyContext.Context
admissionInfo := policyContext.AdmissionInfo
resCache := policyContext.ResourceCache
jsonContext := policyContext.JSONContext
logger := log.Log.WithName("EngineValidate").WithValues("policy", policy.Name)
if reflect.DeepEqual(newR, unstructured.Unstructured{}) {
logger = logger.WithValues("kind", oldR.GetKind(), "namespace", oldR.GetNamespace(), "name", oldR.GetName())
} else {
logger = logger.WithValues("kind", newR.GetKind(), "namespace", newR.GetNamespace(), "name", newR.GetName())
}
logger := buildLogger(policyContext)
logger.V(4).Info("start processing", "startTime", startTime)
defer func() {
if reflect.DeepEqual(resp, response.EngineResponse{}) {
return
}
var resource unstructured.Unstructured
if reflect.DeepEqual(resp.PatchedResource, unstructured.Unstructured{}) {
// for delete requests patched resource will be oldR since newR is empty
if reflect.DeepEqual(newR, unstructured.Unstructured{}) {
resource = oldR
} else {
resource = newR
}
}
for i := range resp.PolicyResponse.Rules {
messageInterface, err := variables.SubstituteVars(logger, ctx, resp.PolicyResponse.Rules[i].Message)
if err != nil {
logger.V(4).Info("failed to substitute variables", "error", err.Error())
continue
}
resp.PolicyResponse.Rules[i].Message, _ = messageInterface.(string)
}
resp.PatchedResource = resource
startResultResponse(&resp, policy, resource)
endResultResponse(logger, &resp, startTime)
buildResponse(logger, policyContext, resp, startTime)
logger.V(4).Info("finished processing", "processingTime", resp.PolicyResponse.ProcessingTime.String(), "validationRulesApplied", resp.PolicyResponse.RulesAppliedCount)
}()
// If request is delete, newR will be empty
if reflect.DeepEqual(newR, unstructured.Unstructured{}) {
return *isRequestDenied(logger, ctx, policy, oldR, admissionInfo, policyContext.ExcludeGroupRole, resCache, jsonContext)
}
if denyResp := isRequestDenied(logger, ctx, policy, newR, admissionInfo, policyContext.ExcludeGroupRole, resCache, jsonContext); !denyResp.IsSuccessful() {
return *denyResp
}
if reflect.DeepEqual(oldR, unstructured.Unstructured{}) {
return *validateResource(logger, ctx, policy, newR, admissionInfo, policyContext.ExcludeGroupRole, resCache, jsonContext)
}
oldResponse := validateResource(logger, ctx, policy, oldR, admissionInfo, policyContext.ExcludeGroupRole, resCache, jsonContext)
newResponse := validateResource(logger, ctx, policy, newR, admissionInfo, policyContext.ExcludeGroupRole, resCache, jsonContext)
if !isSameResponse(oldResponse, newResponse) {
return *newResponse
}
return response.EngineResponse{}
return validateResource(logger, policyContext)
}
func startResultResponse(resp *response.EngineResponse, policy kyverno.ClusterPolicy, newR unstructured.Unstructured) {
// set policy information
func buildLogger(ctx *PolicyContext) logr.Logger {
logger := log.Log.WithName("EngineValidate").WithValues("policy", ctx.Policy.Name)
if reflect.DeepEqual(ctx.NewResource, unstructured.Unstructured{}) {
logger = logger.WithValues("kind", ctx.OldResource.GetKind(), "namespace", ctx.OldResource.GetNamespace(), "name", ctx.OldResource.GetName())
} else {
logger = logger.WithValues("kind", ctx.NewResource.GetKind(), "namespace", ctx.NewResource.GetNamespace(), "name", ctx.NewResource.GetName())
}
return logger
}
func buildResponse(logger logr.Logger, ctx *PolicyContext, resp *response.EngineResponse, startTime time.Time) {
if reflect.DeepEqual(resp, response.EngineResponse{}) {
return
}
var resource unstructured.Unstructured
if reflect.DeepEqual(resp.PatchedResource, unstructured.Unstructured{}) {
// for delete requests patched resource will be oldResource since newResource is empty
if reflect.DeepEqual(ctx.NewResource, unstructured.Unstructured{}) {
resource = ctx.OldResource
} else {
resource = ctx.NewResource
}
}
for i := range resp.PolicyResponse.Rules {
messageInterface, err := variables.SubstituteVars(logger, ctx.JSONContext, resp.PolicyResponse.Rules[i].Message)
if err != nil {
logger.V(4).Info("failed to substitute variables", "error", err.Error())
continue
}
resp.PolicyResponse.Rules[i].Message, _ = messageInterface.(string)
}
resp.PatchedResource = resource
setResponse(resp, ctx.Policy, resource, startTime)
}
func setResponse(resp *response.EngineResponse, policy kyverno.ClusterPolicy, resource unstructured.Unstructured, startTime time.Time) {
resp.PolicyResponse.Policy = policy.Name
// resource details
resp.PolicyResponse.Resource.Name = newR.GetName()
resp.PolicyResponse.Resource.Namespace = newR.GetNamespace()
resp.PolicyResponse.Resource.Kind = newR.GetKind()
resp.PolicyResponse.Resource.APIVersion = newR.GetAPIVersion()
resp.PolicyResponse.Resource.Name = resource.GetName()
resp.PolicyResponse.Resource.Namespace = resource.GetNamespace()
resp.PolicyResponse.Resource.Kind = resource.GetKind()
resp.PolicyResponse.Resource.APIVersion = resource.GetAPIVersion()
resp.PolicyResponse.ValidationFailureAction = policy.Spec.ValidationFailureAction
}
func endResultResponse(log logr.Logger, resp *response.EngineResponse, startTime time.Time) {
resp.PolicyResponse.ProcessingTime = time.Since(startTime)
log.V(4).Info("finished processing", "processingTime", resp.PolicyResponse.ProcessingTime.String(), "validationRulesApplied", resp.PolicyResponse.RulesAppliedCount)
}
func incrementAppliedCount(resp *response.EngineResponse) {
// rules applied successfully count
resp.PolicyResponse.RulesAppliedCount++
}
func isRequestDenied(log logr.Logger, ctx context.EvalInterface, policy kyverno.ClusterPolicy, resource unstructured.Unstructured, admissionInfo kyverno.RequestInfo, excludeGroupRole []string, resCache resourcecache.ResourceCacheIface, jsonContext *context.Context) *response.EngineResponse {
func validateResource(log logr.Logger, ctx *PolicyContext) *response.EngineResponse {
resp := &response.EngineResponse{}
if SkipPolicyApplication(policy, resource) {
log.V(5).Info("skip applying policy as direct changes to pods managed by workload controllers are not allowed", "policy", policy.GetName())
if ManagedPodResource(ctx.Policy, ctx.NewResource) {
log.V(5).Info("skip applying policy as direct changes to pods managed by workload controllers are not allowed", "policy", ctx.Policy.GetName())
return resp
}
excludeResource := []string{}
if len(excludeGroupRole) > 0 {
excludeResource = excludeGroupRole
}
for _, rule := range policy.Spec.Rules {
for _, rule := range ctx.Policy.Spec.Rules {
if !rule.HasValidate() {
continue
}
// add configmap json data to context
if err := AddResourceToContext(log, rule.Context, resCache, jsonContext); err != nil {
if err := AddResourceToContext(log, rule.Context, ctx.ResourceCache, ctx.JSONContext); err != nil {
log.V(4).Info("cannot add configmaps to context", "reason", err.Error())
continue
}
if err := MatchesResourceDescription(resource, rule, admissionInfo, excludeResource); err != nil {
log.V(4).Info("resource fails the match description", "reason", err.Error())
continue
}
preconditionsCopy := copyConditions(rule.Conditions)
if !variables.EvaluateConditions(log, ctx, preconditionsCopy) {
log.V(4).Info("resource fails the preconditions")
continue
}
if rule.Validation.Deny != nil {
denyConditionsCopy := copyConditions(rule.Validation.Deny.Conditions)
if len(rule.Validation.Deny.Conditions) == 0 || variables.EvaluateConditions(log, ctx, denyConditionsCopy) {
ruleResp := response.RuleResponse{
Name: rule.Name,
Type: utils.Validation.String(),
Message: rule.Validation.Message,
Success: false,
}
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResp)
}
continue
}
}
return resp
}
func validateResource(log logr.Logger, ctx context.EvalInterface, policy kyverno.ClusterPolicy, resource unstructured.Unstructured, admissionInfo kyverno.RequestInfo, excludeGroupRole []string, resCache resourcecache.ResourceCacheIface, jsonContext *context.Context) *response.EngineResponse {
resp := &response.EngineResponse{}
if SkipPolicyApplication(policy, resource) {
log.V(5).Info("skip applying policy as direct changes to pods managed by workload controllers are not allowed", "policy", policy.GetName())
return resp
}
excludeResource := []string{}
if len(excludeGroupRole) > 0 {
excludeResource = excludeGroupRole
}
for _, rule := range policy.Spec.Rules {
if !rule.HasValidate() {
continue
}
// check if the resource satisfies the filter conditions defined in the rule
if err := MatchesResourceDescription(resource, rule, admissionInfo, excludeResource); err != nil {
log.V(4).Info("resource fails the match description", "reason", err.Error())
continue
}
// add configmap json data to context
if err := AddResourceToContext(log, rule.Context, resCache, jsonContext); err != nil {
log.V(4).Info("cannot add configmaps to context", "reason", err.Error())
if !matches(log, rule, ctx) {
continue
}
// operate on the copy of the conditions, as we perform variable substitution
preconditionsCopy := copyConditions(rule.Conditions)
// evaluate pre-conditions
// - handle variable substitutions
if !variables.EvaluateConditions(log, ctx, preconditionsCopy) {
if !variables.EvaluateConditions(log, ctx.JSONContext, preconditionsCopy) {
log.V(4).Info("resource fails the preconditions")
continue
}
if rule.Validation.Pattern != nil || rule.Validation.AnyPattern != nil {
ruleResponse := validatePatterns(log, ctx, resource, rule)
if common.IsConditionalAnchorError(ruleResponse.Message) {
continue
ruleResponse := validateResourceWithRule(log, ctx, rule)
if !common.IsConditionalAnchorError(ruleResponse.Message) {
incrementAppliedCount(resp)
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResponse)
}
} else if rule.Validation.Deny != nil {
// validate new resource if available - otherwise old resource
resource := ctx.NewResource
if reflect.DeepEqual(resource, unstructured.Unstructured{}) {
resource = ctx.OldResource
}
denyConditionsCopy := copyConditions(rule.Validation.Deny.Conditions)
deny := variables.EvaluateConditions(log, ctx.JSONContext, denyConditionsCopy)
ruleResp := response.RuleResponse{
Name: rule.Name,
Type: utils.Validation.String(),
Message: rule.Validation.Message,
Success: !deny,
}
incrementAppliedCount(resp)
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResponse)
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResp)
}
}
return resp
}
func isSameResponse(oldResponse, newResponse *response.EngineResponse) bool {
// if the response are same then return true
return isSamePolicyResponse(oldResponse.PolicyResponse, newResponse.PolicyResponse)
func validateResourceWithRule(log logr.Logger, ctx *PolicyContext, rule kyverno.Rule) (resp response.RuleResponse) {
if reflect.DeepEqual(ctx.OldResource, unstructured.Unstructured{}) {
return validatePatterns(log, ctx.JSONContext, ctx.NewResource, rule)
}
oldResp := validatePatterns(log, ctx.JSONContext, ctx.OldResource, rule)
newResp := validatePatterns(log, ctx.JSONContext, ctx.NewResource, rule)
if !isSameRuleResponse(oldResp, newResp) {
return newResp
}
return response.RuleResponse{}
}
func isSamePolicyResponse(oldPolicyRespone, newPolicyResponse response.PolicyResponse) bool {
// can skip policy and resource checks as they will be same
// compare rules
return isSameRules(oldPolicyRespone.Rules, newPolicyResponse.Rules)
// matches checks if either the new or old resource satisfies the filter conditions defined in the rule
func matches(logger logr.Logger, rule kyverno.Rule, ctx *PolicyContext) bool {
err := MatchesResourceDescription(ctx.NewResource, rule, ctx.AdmissionInfo, ctx.ExcludeGroupRole)
if err == nil {
return true
}
if !reflect.DeepEqual(ctx.OldResource, unstructured.Unstructured{}) {
err := MatchesResourceDescription(ctx.OldResource, rule, ctx.AdmissionInfo, ctx.ExcludeGroupRole)
if err == nil {
return true
}
}
logger.V(4).Info("resource fails the match description", "reason", err.Error())
return false
}
func isSameRules(oldRules []response.RuleResponse, newRules []response.RuleResponse) bool {
if len(oldRules) != len(newRules) {
func isSameRuleResponse(r1 response.RuleResponse, r2 response.RuleResponse) bool {
if r1.Name != r2.Name {
return false
}
// as the rules are always processed in order the indices wil be same
for idx, oldrule := range oldRules {
newrule := newRules[idx]
// Name
if oldrule.Name != newrule.Name {
return false
}
// Type
if oldrule.Type != newrule.Type {
return false
}
// Message
if oldrule.Message != newrule.Message {
return false
}
// skip patches
if oldrule.Success != newrule.Success {
return false
}
if r1.Type != r2.Type {
return false
}
if r1.Message != r2.Message {
return false
}
if r1.Success != r2.Success {
return false
}
return true
}

File diff suppressed because one or more lines are too long

View file

@ -17,13 +17,13 @@ func Evaluate(log logr.Logger, ctx context.EvalInterface, condition kyverno.Cond
return handle.Evaluate(condition.Key, condition.Value)
}
//EvaluateConditions evaluates multiple conditions
//EvaluateConditions evaluates multiple conditions as a logical AND operation
func EvaluateConditions(log logr.Logger, ctx context.EvalInterface, conditions []kyverno.Condition) bool {
// AND the conditions
for _, condition := range conditions {
if !Evaluate(log, ctx, condition) {
return false
}
}
return true
}

View file

@ -115,7 +115,7 @@ func (c *Controller) applyGenerate(resource unstructured.Unstructured, gr kyvern
return nil, err
}
err = ctx.AddSA(gr.Spec.Context.UserRequestInfo.AdmissionUserInfo.Username)
err = ctx.AddServiceAccount(gr.Spec.Context.UserRequestInfo.AdmissionUserInfo.Username)
if err != nil {
logger.Error(err, "failed to load UserInfo in context")
return nil, err
@ -124,7 +124,6 @@ func (c *Controller) applyGenerate(resource unstructured.Unstructured, gr kyvern
policyContext := engine.PolicyContext{
NewResource: resource,
Policy: *policyObj,
Context: ctx,
AdmissionInfo: gr.Spec.Context.UserRequestInfo,
ExcludeGroupRole: c.Config.GetExcludeGroupRole(),
ExcludeResourceFunc: c.Config.ToFilter,
@ -187,7 +186,6 @@ func (c *Controller) applyGeneratePolicy(log logr.Logger, policyContext engine.P
// - - substitute values
policy := policyContext.Policy
resource := policyContext.NewResource
ctx := policyContext.Context
resCache := policyContext.ResourceCache
jsonContext := policyContext.JSONContext
@ -222,7 +220,7 @@ func (c *Controller) applyGeneratePolicy(log logr.Logger, policyContext engine.P
return nil, err
}
genResource, err := applyRule(log, c.client, rule, resource, ctx, policy.Name, gr, processExisting)
genResource, err := applyRule(log, c.client, rule, resource, jsonContext, policy.Name, gr, processExisting)
if err != nil {
log.Error(err, "failed to apply generate rule", "policy", policy.Name,
"rule", rule.Name, "resource", resource.GetName())

View file

@ -144,7 +144,9 @@ func Command() *cobra.Command {
return cmd
}
func applyCommandHelper(resourcePaths []string, cluster bool, policyReport bool, mutateLogPath string, variablesString string, valuesFile string, namespace string, policyPaths []string) (validateEngineResponses []response.EngineResponse, rc *resultCounts, resources []*unstructured.Unstructured, skippedPolicies []SkippedPolicy, err error) {
func applyCommandHelper(resourcePaths []string, cluster bool, policyReport bool, mutateLogPath string,
variablesString string, valuesFile string, namespace string, policyPaths []string) (validateEngineResponses []*response.EngineResponse, rc *resultCounts, resources []*unstructured.Unstructured, skippedPolicies []SkippedPolicy, err error) {
kubernetesConfig := genericclioptions.NewConfigFlags(true)
if valuesFile != "" && variablesString != "" {
@ -230,8 +232,8 @@ func applyCommandHelper(resourcePaths []string, cluster bool, policyReport bool,
}
rc = &resultCounts{}
engineResponses := make([]response.EngineResponse, 0)
validateEngineResponses = make([]response.EngineResponse, 0)
engineResponses := make([]*response.EngineResponse, 0)
validateEngineResponses = make([]*response.EngineResponse, 0)
skippedPolicies = make([]SkippedPolicy, 0)
for _, policy := range mutatedPolicies {
@ -276,6 +278,7 @@ func applyCommandHelper(resourcePaths []string, cluster bool, policyReport bool,
if err != nil {
return validateEngineResponses, rc, resources, skippedPolicies, sanitizederror.NewWithError(fmt.Errorf("failed to apply policy %v on resource %v", policy.Name, resource.GetName()).Error(), err)
}
engineResponses = append(engineResponses, ers...)
validateEngineResponses = append(validateEngineResponses, validateErs)
}
@ -407,7 +410,7 @@ func getResourceAccordingToResourcePath(resourcePaths []string, cluster bool, po
}
// printReportOrViolation - printing policy report/violations
func printReportOrViolation(policyReport bool, validateEngineResponses []response.EngineResponse, rc *resultCounts, resourcePaths []string, resourcesLen int, skippedPolicies []SkippedPolicy) {
func printReportOrViolation(policyReport bool, validateEngineResponses []*response.EngineResponse, rc *resultCounts, resourcePaths []string, resourcesLen int, skippedPolicies []SkippedPolicy) {
if policyReport {
os.Setenv("POLICY-TYPE", pkgCommon.PolicyReport)
resps := buildPolicyReports(validateEngineResponses, skippedPolicies)
@ -435,9 +438,12 @@ func printReportOrViolation(policyReport bool, validateEngineResponses []respons
}
// applyPolicyOnResource - function to apply policy on resource
func applyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unstructured, mutateLogPath string, mutateLogPathIsDir bool, variables map[string]string, rc *resultCounts, policyReport bool) ([]response.EngineResponse, response.EngineResponse, error) {
func applyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unstructured,
mutateLogPath string, mutateLogPathIsDir bool, variables map[string]string,
rc *resultCounts, policyReport bool) ([]*response.EngineResponse, *response.EngineResponse, error) {
responseError := false
engineResponses := make([]response.EngineResponse, 0)
engineResponses := make([]*response.EngineResponse, 0)
resPath := fmt.Sprintf("%s/%s/%s", resource.GetNamespace(), resource.GetKind(), resource.GetName())
log.Log.V(3).Info("applying policy on resource", "policy", policy.Name, "resource", resPath)
@ -457,7 +463,7 @@ func applyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unst
ctx.AddJSON(jsonData)
}
mutateResponse := engine.Mutate(engine.PolicyContext{Policy: *policy, NewResource: *resource, Context: ctx})
mutateResponse := engine.Mutate(&engine.PolicyContext{Policy: *policy, NewResource: *resource, JSONContext: ctx})
engineResponses = append(engineResponses, mutateResponse)
if !mutateResponse.IsSuccessful() {
@ -483,7 +489,7 @@ func applyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unst
} else {
err := printMutatedOutput(mutateLogPath, mutateLogPathIsDir, string(yamlEncodedResource), resource.GetName()+"-mutated")
if err != nil {
return engineResponses, response.EngineResponse{}, sanitizederror.NewWithError("failed to print mutated result", err)
return engineResponses, &response.EngineResponse{}, sanitizederror.NewWithError("failed to print mutated result", err)
}
fmt.Printf("\n\nMutation:\nMutation has been applied successfully. Check the files.")
}
@ -499,7 +505,8 @@ func applyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unst
}
}
validateResponse := engine.Validate(engine.PolicyContext{Policy: *policy, NewResource: mutateResponse.PatchedResource, Context: ctx})
policyCtx := &engine.PolicyContext{Policy: *policy, NewResource: mutateResponse.PatchedResource, JSONContext: ctx}
validateResponse := engine.Validate(policyCtx)
if !policyReport {
if !validateResponse.IsSuccessful() {
fmt.Printf("\npolicy %s -> resource %s failed: \n", policy.Name, resPath)

View file

@ -20,7 +20,7 @@ import (
const clusterpolicyreport = "clusterpolicyreport"
// resps is the engine responses generated for a single policy
func buildPolicyReports(resps []response.EngineResponse, skippedPolicies []SkippedPolicy) (res []*unstructured.Unstructured) {
func buildPolicyReports(resps []*response.EngineResponse, skippedPolicies []SkippedPolicy) (res []*unstructured.Unstructured) {
var raw []byte
var err error
@ -107,7 +107,7 @@ func buildPolicyReports(resps []response.EngineResponse, skippedPolicies []Skipp
// buildPolicyResults returns a string-PolicyReportResult map
// the key of the map is one of "clusterpolicyreport", "policyreport-ns-<namespace>"
func buildPolicyResults(resps []response.EngineResponse) map[string][]*report.PolicyReportResult {
func buildPolicyResults(resps []*response.EngineResponse) map[string][]*report.PolicyReportResult {
results := make(map[string][]*report.PolicyReportResult)
infos := policyreport.GeneratePRsFromEngineResponse(resps, log.Log)

View file

@ -14,7 +14,7 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
var engineResponses = []response.EngineResponse{
var engineResponses = []*response.EngineResponse{
{
PatchedResource: unstructured.Unstructured{
Object: map[string]interface{}{

View file

@ -19,7 +19,8 @@ import (
)
// applyPolicy applies policy on a resource
func applyPolicy(policy kyverno.ClusterPolicy, resource unstructured.Unstructured, logger logr.Logger, excludeGroupRole []string, resCache resourcecache.ResourceCacheIface) (responses []response.EngineResponse) {
func applyPolicy(policy kyverno.ClusterPolicy, resource unstructured.Unstructured,
logger logr.Logger, excludeGroupRole []string, resCache resourcecache.ResourceCacheIface) (responses []*response.EngineResponse) {
startTime := time.Now()
defer func() {
name := resource.GetKind() + "/" + resource.GetName()
@ -31,8 +32,8 @@ func applyPolicy(policy kyverno.ClusterPolicy, resource unstructured.Unstructure
logger.V(3).Info("applyPolicy", "resource", name, "processingTime", time.Since(startTime).String())
}()
var engineResponses []response.EngineResponse
var engineResponseMutation, engineResponseValidation response.EngineResponse
var engineResponses []*response.EngineResponse
var engineResponseMutation, engineResponseValidation *response.EngineResponse
var err error
ctx := context.NewContext()
@ -41,20 +42,27 @@ func applyPolicy(policy kyverno.ClusterPolicy, resource unstructured.Unstructure
logger.Error(err, "enable to add transform resource to ctx")
}
engineResponseMutation, err = mutation(policy, resource, ctx, logger, resCache, ctx)
engineResponseMutation, err = mutation(policy, resource, logger, resCache, ctx)
if err != nil {
logger.Error(err, "failed to process mutation rule")
}
engineResponseValidation = engine.Validate(engine.PolicyContext{Policy: policy, Context: ctx, NewResource: resource, ExcludeGroupRole: excludeGroupRole, ResourceCache: resCache, JSONContext: ctx})
engineResponseValidation = engine.Validate(&engine.PolicyContext{Policy: policy, NewResource: resource, ExcludeGroupRole: excludeGroupRole, ResourceCache: resCache, JSONContext: ctx})
engineResponses = append(engineResponses, mergeRuleRespose(engineResponseMutation, engineResponseValidation))
return engineResponses
}
func mutation(policy kyverno.ClusterPolicy, resource unstructured.Unstructured, ctx context.EvalInterface, log logr.Logger, resCache resourcecache.ResourceCacheIface, jsonContext *context.Context) (response.EngineResponse, error) {
func mutation(policy kyverno.ClusterPolicy, resource unstructured.Unstructured, log logr.Logger, resCache resourcecache.ResourceCacheIface, jsonContext *context.Context) (*response.EngineResponse, error) {
engineResponse := engine.Mutate(engine.PolicyContext{Policy: policy, NewResource: resource, Context: ctx, ResourceCache: resCache, JSONContext: jsonContext})
policyContext := &engine.PolicyContext{
Policy: policy,
NewResource: resource,
ResourceCache: resCache,
JSONContext: jsonContext,
}
engineResponse := engine.Mutate(policyContext)
if !engineResponse.IsSuccessful() {
log.V(4).Info("failed to apply mutation rules; reporting them")
return engineResponse, nil
@ -69,11 +77,11 @@ func mutation(policy kyverno.ClusterPolicy, resource unstructured.Unstructured,
}
// getFailedOverallRuleInfo gets detailed info for over-all mutation failure
func getFailedOverallRuleInfo(resource unstructured.Unstructured, engineResponse response.EngineResponse, log logr.Logger) (response.EngineResponse, error) {
func getFailedOverallRuleInfo(resource unstructured.Unstructured, engineResponse *response.EngineResponse, log logr.Logger) (*response.EngineResponse, error) {
rawResource, err := resource.MarshalJSON()
if err != nil {
log.Error(err, "failed to marshall resource")
return response.EngineResponse{}, err
return &response.EngineResponse{}, err
}
// resource does not match so there was a mutation rule violated
@ -85,14 +93,14 @@ func getFailedOverallRuleInfo(resource unstructured.Unstructured, engineResponse
patch, err := jsonpatch.DecodePatch(utils.JoinPatches(patches))
if err != nil {
log.Error(err, "failed to decode JSON patch", "patches", patches)
return response.EngineResponse{}, err
return &response.EngineResponse{}, err
}
// apply the patches returned by mutate to the original resource
patchedResource, err := patch.Apply(rawResource)
if err != nil {
log.Error(err, "failed to apply JSON patch", "patches", patches)
return response.EngineResponse{}, err
return &response.EngineResponse{}, err
}
if !jsonpatch.Equal(patchedResource, rawResource) {
@ -126,7 +134,7 @@ func extractPatchPath(patches [][]byte, log logr.Logger) string {
return strings.Join(resultPath, ";")
}
func mergeRuleRespose(mutation, validation response.EngineResponse) response.EngineResponse {
func mergeRuleRespose(mutation, validation *response.EngineResponse) *response.EngineResponse {
mutation.PolicyResponse.Rules = append(mutation.PolicyResponse.Rules, validation.PolicyResponse.Rules...)
return mutation
}

View file

@ -59,7 +59,7 @@ func (pc *PolicyController) applyAndReportPerNamespace(policy *kyverno.ClusterPo
return
}
var engineResponses []response.EngineResponse
var engineResponses []*response.EngineResponse
for _, resource := range rMap {
responses := pc.applyPolicy(policy, resource, logger)
engineResponses = append(engineResponses, responses...)
@ -68,7 +68,7 @@ func (pc *PolicyController) applyAndReportPerNamespace(policy *kyverno.ClusterPo
pc.report(policy.Name, engineResponses, logger)
}
func (pc *PolicyController) applyPolicy(policy *kyverno.ClusterPolicy, resource unstructured.Unstructured, logger logr.Logger) (engineResponses []response.EngineResponse) {
func (pc *PolicyController) applyPolicy(policy *kyverno.ClusterPolicy, resource unstructured.Unstructured, logger logr.Logger) (engineResponses []*response.EngineResponse) {
// pre-processing, check if the policy and resource version has been processed before
if !pc.rm.ProcessResource(policy.Name, policy.ResourceVersion, resource.GetKind(), resource.GetNamespace(), resource.GetName(), resource.GetResourceVersion()) {
logger.V(4).Info("policy and resource already processed", "policyResourceVersion", policy.ResourceVersion, "resourceResourceVersion", resource.GetResourceVersion(), "kind", resource.GetKind(), "namespace", resource.GetNamespace(), "name", resource.GetName())
@ -86,7 +86,7 @@ func (pc *PolicyController) applyPolicy(policy *kyverno.ClusterPolicy, resource
// excludeAutoGenResources filter out the pods / jobs with ownerReference
func excludeAutoGenResources(policy kyverno.ClusterPolicy, resourceMap map[string]unstructured.Unstructured, log logr.Logger) {
for uid, r := range resourceMap {
if engine.SkipPolicyApplication(policy, r) {
if engine.ManagedPodResource(policy, r) {
log.V(4).Info("exclude resource", "namespace", r.GetNamespace(), "kind", r.GetKind(), "name", r.GetName())
delete(resourceMap, uid)
}

View file

@ -9,7 +9,7 @@ import (
"github.com/kyverno/kyverno/pkg/policyreport"
)
func (pc *PolicyController) report(policy string, engineResponses []response.EngineResponse, logger logr.Logger) {
func (pc *PolicyController) report(policy string, engineResponses []*response.EngineResponse, logger logr.Logger) {
eventInfos := generateEvents(logger, engineResponses)
pc.eventGen.Add(eventInfos...)
@ -22,7 +22,7 @@ func (pc *PolicyController) report(policy string, engineResponses []response.Eng
logger.V(4).Info("added a request to RCR generator", "key", info.ToKey())
}
func generateEvents(log logr.Logger, ers []response.EngineResponse) []event.Info {
func generateEvents(log logr.Logger, ers []*response.EngineResponse) []event.Info {
var eventInfos []event.Info
for _, er := range ers {
if er.IsSuccessful() {
@ -33,7 +33,7 @@ func generateEvents(log logr.Logger, ers []response.EngineResponse) []event.Info
return eventInfos
}
func generateEventsPerEr(log logr.Logger, er response.EngineResponse) []event.Info {
func generateEventsPerEr(log logr.Logger, er *response.EngineResponse) []event.Info {
var eventInfos []event.Info
logger := log.WithValues("policy", er.PolicyResponse.Policy, "kind", er.PolicyResponse.Resource.Kind, "namespace", er.PolicyResponse.Resource.Namespace, "name", er.PolicyResponse.Resource.Name)

View file

@ -41,7 +41,7 @@ func generatePolicyReportName(ns string) string {
}
//GeneratePRsFromEngineResponse generate Violations from engine responses
func GeneratePRsFromEngineResponse(ers []response.EngineResponse, log logr.Logger) (pvInfos []Info) {
func GeneratePRsFromEngineResponse(ers []*response.EngineResponse, log logr.Logger) (pvInfos []Info) {
for _, er := range ers {
// ignore creation of PV for resources that are yet to be assigned a name
if er.PolicyResponse.Resource.Name == "" {
@ -210,7 +210,7 @@ func calculateSummary(results []*report.PolicyReportResult) (summary report.Poli
return
}
func buildPVInfo(er response.EngineResponse) Info {
func buildPVInfo(er *response.EngineResponse) Info {
info := Info{
PolicyName: er.PolicyResponse.Policy,
Namespace: er.PatchedResource.GetNamespace(),
@ -224,7 +224,7 @@ func buildPVInfo(er response.EngineResponse) Info {
return info
}
func buildViolatedRules(er response.EngineResponse) []kyverno.ViolatedRule {
func buildViolatedRules(er *response.EngineResponse) []kyverno.ViolatedRule {
var violatedRules []kyverno.ViolatedRule
for _, rule := range er.PolicyResponse.Rules {
vrule := kyverno.ViolatedRule{

View file

@ -126,9 +126,7 @@ func runTestCase(t *testing.T, tc scaseT) bool {
t.FailNow()
}
var er response.EngineResponse
er = engine.Mutate(engine.PolicyContext{Policy: *policy, NewResource: *resource, ExcludeGroupRole: []string{}})
er := engine.Mutate(&engine.PolicyContext{Policy: *policy, NewResource: *resource, ExcludeGroupRole: []string{}})
t.Log("---Mutation---")
validateResource(t, er.PatchedResource, tc.Expected.Mutation.PatchedResource)
validateResponse(t, er.PolicyResponse, tc.Expected.Mutation.PolicyResponse)
@ -138,7 +136,7 @@ func runTestCase(t *testing.T, tc scaseT) bool {
resource = &er.PatchedResource
}
er = engine.Validate(engine.PolicyContext{Policy: *policy, NewResource: *resource, ExcludeGroupRole: []string{}})
er = engine.Validate(&engine.PolicyContext{Policy: *policy, NewResource: *resource, ExcludeGroupRole: []string{}})
t.Log("---Validation---")
validateResponse(t, er.PolicyResponse, tc.Expected.Validation.PolicyResponse)
@ -235,7 +233,7 @@ func validateResponse(t *testing.T, er response.PolicyResponse, expected respons
// rules
if len(er.Rules) != len(expected.Rules) {
t.Errorf("rule count error, er.Rules=%d, expected.Rules=%d", len(er.Rules), len(expected.Rules))
t.Errorf("rule count error, er.Rules=%v, expected.Rules=%v", er.Rules, expected.Rules)
return
}
if len(er.Rules) == len(expected.Rules) {

View file

@ -36,7 +36,7 @@ var operationToPastTense = map[string]string{
"test": "tested",
}
func generateAnnotationPatches(engineResponses []response.EngineResponse, log logr.Logger) []byte {
func generateAnnotationPatches(engineResponses []*response.EngineResponse, log logr.Logger) []byte {
var annotations map[string]string
for _, er := range engineResponses {
@ -94,7 +94,7 @@ func generateAnnotationPatches(engineResponses []response.EngineResponse, log lo
return patchByte
}
func annotationFromEngineResponses(engineResponses []response.EngineResponse, log logr.Logger) []byte {
func annotationFromEngineResponses(engineResponses []*response.EngineResponse, log logr.Logger) []byte {
var annotationContent = make(map[string]string)
for _, engineResponse := range engineResponses {
if !engineResponse.IsSuccessful() {

View file

@ -26,8 +26,8 @@ func newPolicyResponse(policy, rule string, patchesStr []string, success bool) r
}
}
func newEngineResponse(policy, rule string, patchesStr []string, success bool, annotation map[string]string) response.EngineResponse {
return response.EngineResponse{
func newEngineResponse(policy, rule string, patchesStr []string, success bool, annotation map[string]string) *response.EngineResponse {
return &response.EngineResponse{
PatchedResource: unstructured.Unstructured{
Object: map[string]interface{}{
"metadata": map[string]interface{}{
@ -43,7 +43,7 @@ func Test_empty_annotation(t *testing.T) {
patchStr := `{ "op": "replace", "path": "/spec/containers/0/imagePullPolicy", "value": "IfNotPresent" }`
engineResponse := newEngineResponse("mutate-container", "default-imagepullpolicy", []string{patchStr}, true, nil)
annPatches := generateAnnotationPatches([]response.EngineResponse{engineResponse}, log.Log)
annPatches := generateAnnotationPatches([]*response.EngineResponse{engineResponse}, log.Log)
expectedPatches := `{"op":"add","path":"/metadata/annotations","value":{"policies.kyverno.io/patches":"default-imagepullpolicy.mutate-container.kyverno.io: replaced /spec/containers/0/imagePullPolicy\n"}}`
assert.Assert(t, string(annPatches) == expectedPatches)
}
@ -55,7 +55,7 @@ func Test_exist_annotation(t *testing.T) {
patchStr := `{ "op": "replace", "path": "/spec/containers/0/imagePullPolicy", "value": "IfNotPresent" }`
engineResponse := newEngineResponse("mutate-container", "default-imagepullpolicy", []string{patchStr}, true, annotation)
annPatches := generateAnnotationPatches([]response.EngineResponse{engineResponse}, log.Log)
annPatches := generateAnnotationPatches([]*response.EngineResponse{engineResponse}, log.Log)
expectedPatches := `{"op":"add","path":"/metadata/annotations","value":{"policies.kyverno.io/patches":"default-imagepullpolicy.mutate-container.kyverno.io: replaced /spec/containers/0/imagePullPolicy\n"}}`
assert.Assert(t, string(annPatches) == expectedPatches)
@ -68,7 +68,7 @@ func Test_exist_kyverno_annotation(t *testing.T) {
patchStr := `{ "op": "replace", "path": "/spec/containers/0/imagePullPolicy", "value": "IfNotPresent" }`
engineResponse := newEngineResponse("mutate-container", "default-imagepullpolicy", []string{patchStr}, true, annotation)
annPatches := generateAnnotationPatches([]response.EngineResponse{engineResponse}, log.Log)
annPatches := generateAnnotationPatches([]*response.EngineResponse{engineResponse}, log.Log)
expectedPatches := `{"op":"add","path":"/metadata/annotations","value":{"policies.kyverno.io/patches":"default-imagepullpolicy.mutate-container.kyverno.io: replaced /spec/containers/0/imagePullPolicy\n"}}`
assert.Assert(t, string(annPatches) == expectedPatches)
@ -80,11 +80,11 @@ func Test_annotation_nil_patch(t *testing.T) {
}
engineResponse := newEngineResponse("mutate-container", "default-imagepullpolicy", nil, true, annotation)
annPatches := generateAnnotationPatches([]response.EngineResponse{engineResponse}, log.Log)
annPatches := generateAnnotationPatches([]*response.EngineResponse{engineResponse}, log.Log)
assert.Assert(t, annPatches == nil)
engineResponseNew := newEngineResponse("mutate-container", "default-imagepullpolicy", []string{""}, true, annotation)
annPatchesNew := generateAnnotationPatches([]response.EngineResponse{engineResponseNew}, log.Log)
annPatchesNew := generateAnnotationPatches([]*response.EngineResponse{engineResponseNew}, log.Log)
assert.Assert(t, annPatchesNew == nil)
}
@ -94,7 +94,7 @@ func Test_annotation_failed_Patch(t *testing.T) {
}
engineResponse := newEngineResponse("mutate-container", "default-imagepullpolicy", nil, false, annotation)
annPatches := generateAnnotationPatches([]response.EngineResponse{engineResponse}, log.Log)
annPatches := generateAnnotationPatches([]*response.EngineResponse{engineResponse}, log.Log)
assert.Assert(t, annPatches == nil)
}

View file

@ -16,7 +16,7 @@ import (
)
// isResponseSuccessful return true if all responses are successful
func isResponseSuccessful(engineReponses []response.EngineResponse) bool {
func isResponseSuccessful(engineReponses []*response.EngineResponse) bool {
for _, er := range engineReponses {
if !er.IsSuccessful() {
return false
@ -27,7 +27,7 @@ func isResponseSuccessful(engineReponses []response.EngineResponse) bool {
// returns true -> if there is even one policy that blocks resource request
// returns false -> if all the policies are meant to report only, we dont block resource request
func toBlockResource(engineReponses []response.EngineResponse, log logr.Logger) bool {
func toBlockResource(engineReponses []*response.EngineResponse, log logr.Logger) bool {
for _, er := range engineReponses {
if !er.IsSuccessful() && er.PolicyResponse.ValidationFailureAction == common.Enforce {
log.Info("spec.ValidationFailureAction set to enforce blocking resource request", "policy", er.PolicyResponse.Policy)
@ -39,7 +39,7 @@ func toBlockResource(engineReponses []response.EngineResponse, log logr.Logger)
}
// getEnforceFailureErrorMsg gets the error messages for failed enforce policy
func getEnforceFailureErrorMsg(engineResponses []response.EngineResponse) string {
func getEnforceFailureErrorMsg(engineResponses []*response.EngineResponse) string {
policyToRule := make(map[string]interface{})
var resourceName string
for _, er := range engineResponses {
@ -61,7 +61,7 @@ func getEnforceFailureErrorMsg(engineResponses []response.EngineResponse) string
}
// getErrorMsg gets all failed engine response message
func getErrorMsg(engineReponses []response.EngineResponse) string {
func getErrorMsg(engineReponses []*response.EngineResponse) string {
var str []string
var resourceInfo string

View file

@ -29,7 +29,7 @@ import (
func (ws *WebhookServer) HandleGenerate(request *v1beta1.AdmissionRequest, policies []*kyverno.ClusterPolicy, ctx *context.Context, userRequestInfo kyverno.RequestInfo, dynamicConfig config.Interface) {
logger := ws.log.WithValues("action", "generation", "uid", request.UID, "kind", request.Kind, "namespace", request.Namespace, "name", request.Name, "operation", request.Operation)
logger.V(4).Info("incoming request")
var engineResponses []response.EngineResponse
var engineResponses []*response.EngineResponse
if len(policies) == 0 {
return
@ -44,7 +44,6 @@ func (ws *WebhookServer) HandleGenerate(request *v1beta1.AdmissionRequest, polic
NewResource: new,
OldResource: old,
AdmissionInfo: userRequestInfo,
Context: ctx,
ExcludeGroupRole: dynamicConfig.GetExcludeGroupRole(),
ExcludeResourceFunc: ws.configHandler.ToFilter,
ResourceCache: ws.resCache,
@ -86,7 +85,7 @@ func (ws *WebhookServer) HandleGenerate(request *v1beta1.AdmissionRequest, polic
return
}
func (ws *WebhookServer) deleteGR(logger logr.Logger, engineResponse response.EngineResponse) {
func (ws *WebhookServer) deleteGR(logger logr.Logger, engineResponse *response.EngineResponse) {
logger.V(4).Info("querying all generate requests")
selector := labels.SelectorFromSet(labels.Set(map[string]string{
"policyName": engineResponse.PolicyResponse.Policy,
@ -110,7 +109,7 @@ func (ws *WebhookServer) deleteGR(logger logr.Logger, engineResponse response.En
}
func applyGenerateRequest(gnGenerator generate.GenerateRequests, userRequestInfo kyverno.RequestInfo,
action v1beta1.Operation, engineResponses ...response.EngineResponse) (failedGenerateRequest []generateRequestResponse) {
action v1beta1.Operation, engineResponses ...*response.EngineResponse) (failedGenerateRequest []generateRequestResponse) {
for _, er := range engineResponses {
gr := transform(userRequestInfo, er)
@ -122,8 +121,7 @@ func applyGenerateRequest(gnGenerator generate.GenerateRequests, userRequestInfo
return
}
func transform(userRequestInfo kyverno.RequestInfo, er response.EngineResponse) kyverno.GenerateRequestSpec {
func transform(userRequestInfo kyverno.RequestInfo, er *response.EngineResponse) kyverno.GenerateRequestSpec {
gr := kyverno.GenerateRequestSpec{
Policy: er.PolicyResponse.Policy,
Resource: kyverno.ResourceSpec{
@ -135,11 +133,12 @@ func transform(userRequestInfo kyverno.RequestInfo, er response.EngineResponse)
UserRequestInfo: userRequestInfo,
},
}
return gr
}
type generateStats struct {
resp response.EngineResponse
resp *response.EngineResponse
}
func (gs generateStats) PolicyName() string {

View file

@ -36,11 +36,10 @@ func (ws *WebhookServer) HandleMutation(
logger := ws.log.WithValues("action", "mutate", "resource", resourceName, "operation", request.Operation)
var patches [][]byte
var engineResponses []response.EngineResponse
policyContext := engine.PolicyContext{
var engineResponses []*response.EngineResponse
policyContext := &engine.PolicyContext{
NewResource: resource,
AdmissionInfo: userRequestInfo,
Context: ctx,
ExcludeGroupRole: ws.configHandler.GetExcludeGroupRole(),
ExcludeResourceFunc: ws.configHandler.ToFilter,
ResourceCache: ws.resCache,
@ -117,7 +116,7 @@ func (ws *WebhookServer) HandleMutation(
}
type mutateStats struct {
resp response.EngineResponse
resp *response.EngineResponse
namespace string
}

View file

@ -12,11 +12,11 @@ import (
func Test_GenerateStats(t *testing.T) {
testCase := struct {
generateStats []response.EngineResponse
generateStats []*response.EngineResponse
expectedOutput []byte
}{
expectedOutput: []byte(`{"policy1":{"averageExecutionTime":"494ns","rulesFailedCount":1,"rulesAppliedCount":1,"ruleStatus":[{"ruleName":"rule5","averageExecutionTime":"243ns","appliedCount":1},{"ruleName":"rule6","averageExecutionTime":"251ns","failedCount":1}]},"policy2":{"averageExecutionTime":"433ns","rulesFailedCount":1,"rulesAppliedCount":1,"ruleStatus":[{"ruleName":"rule5","averageExecutionTime":"222ns","appliedCount":1},{"ruleName":"rule6","averageExecutionTime":"211ns","failedCount":1}]}}`),
generateStats: []response.EngineResponse{
generateStats: []*response.EngineResponse{
{
PolicyResponse: response.PolicyResponse{
Policy: "policy1",
@ -79,11 +79,11 @@ func Test_GenerateStats(t *testing.T) {
func Test_MutateStats(t *testing.T) {
testCase := struct {
mutateStats []response.EngineResponse
mutateStats []*response.EngineResponse
expectedOutput []byte
}{
expectedOutput: []byte(`{"policy1":{"averageExecutionTime":"494ns","rulesFailedCount":1,"rulesAppliedCount":1,"resourcesMutatedCount":1,"ruleStatus":[{"ruleName":"rule1","averageExecutionTime":"243ns","appliedCount":1,"resourcesMutatedCount":1},{"ruleName":"rule2","averageExecutionTime":"251ns","failedCount":1}]},"policy2":{"averageExecutionTime":"433ns","rulesFailedCount":1,"rulesAppliedCount":1,"resourcesMutatedCount":1,"ruleStatus":[{"ruleName":"rule1","averageExecutionTime":"222ns","appliedCount":1,"resourcesMutatedCount":1},{"ruleName":"rule2","averageExecutionTime":"211ns","failedCount":1}]}}`),
mutateStats: []response.EngineResponse{
mutateStats: []*response.EngineResponse{
{
PolicyResponse: response.PolicyResponse{
Policy: "policy1",
@ -145,11 +145,11 @@ func Test_MutateStats(t *testing.T) {
func Test_ValidateStats(t *testing.T) {
testCase := struct {
validateStats []response.EngineResponse
validateStats []*response.EngineResponse
expectedOutput []byte
}{
expectedOutput: []byte(`{"policy1":{"averageExecutionTime":"494ns","rulesFailedCount":1,"rulesAppliedCount":1,"resourcesBlockedCount":1,"ruleStatus":[{"ruleName":"rule3","averageExecutionTime":"243ns","appliedCount":1},{"ruleName":"rule4","averageExecutionTime":"251ns","failedCount":1,"resourcesBlockedCount":1}]},"policy2":{"averageExecutionTime":"433ns","rulesFailedCount":1,"rulesAppliedCount":1,"ruleStatus":[{"ruleName":"rule3","averageExecutionTime":"222ns","appliedCount":1},{"ruleName":"rule4","averageExecutionTime":"211ns","failedCount":1}]}}`),
validateStats: []response.EngineResponse{
validateStats: []*response.EngineResponse{
{
PolicyResponse: response.PolicyResponse{
Policy: "policy1",

View file

@ -10,7 +10,7 @@ import (
)
//generateEvents generates event info for the engine responses
func generateEvents(engineResponses []response.EngineResponse, blocked, onUpdate bool, log logr.Logger) []event.Info {
func generateEvents(engineResponses []*response.EngineResponse, blocked, onUpdate bool, log logr.Logger) []event.Info {
var events []event.Info
// - Admission-Response is SUCCESS

View file

@ -330,7 +330,7 @@ func (ws *WebhookServer) ResourceMutation(request *v1beta1.AdmissionRequest) *v1
if err != nil {
logger.Error(err, "failed to load userInfo in context")
}
err = ctx.AddSA(userRequestInfo.AdmissionUserInfo.Username)
err = ctx.AddServiceAccount(userRequestInfo.AdmissionUserInfo.Username)
if err != nil {
logger.Error(err, "failed to load service account in context")
}
@ -441,7 +441,7 @@ func (ws *WebhookServer) resourceValidation(request *v1beta1.AdmissionRequest) *
if err != nil {
logger.Error(err, "failed to load userInfo in context")
}
err = ctx.AddSA(userRequestInfo.AdmissionUserInfo.Username)
err = ctx.AddServiceAccount(userRequestInfo.AdmissionUserInfo.Username)
if err != nil {
logger.Error(err, "failed to load service account in context")
}

View file

@ -166,7 +166,7 @@ func (h *auditHandler) process(request *v1beta1.AdmissionRequest) error {
if err != nil {
return errors.Wrap(err, "failed to load userInfo in context")
}
err = ctx.AddSA(userRequestInfo.AdmissionUserInfo.Username)
err = ctx.AddServiceAccount(userRequestInfo.AdmissionUserInfo.Username)
if err != nil {
return errors.Wrap(err, "failed to load service account in context")
}

View file

@ -68,10 +68,9 @@ func HandleValidation(
return true, ""
}
policyContext := engine.PolicyContext{
policyContext := &engine.PolicyContext{
NewResource: newR,
OldResource: oldR,
Context: ctx,
AdmissionInfo: userRequestInfo,
ExcludeGroupRole: dynamicConfig.GetExcludeGroupRole(),
ExcludeResourceFunc: dynamicConfig.ToFilter,
@ -79,7 +78,7 @@ func HandleValidation(
JSONContext: ctx,
}
var engineResponses []response.EngineResponse
var engineResponses []*response.EngineResponse
for _, policy := range policies {
logger.V(3).Info("evaluating policy", "policy", policy.Name)
@ -152,7 +151,7 @@ func buildDeletionPrInfo(oldR unstructured.Unstructured) policyreport.Info {
}
type validateStats struct {
resp response.EngineResponse
resp *response.EngineResponse
namespace string
}

View file

@ -10,7 +10,7 @@ expected:
kind: Pod
apiVersion: v1
# this is set to pass resource NS check
# actual valiation is defined through rule success=false
# actual validation is defined through rule success=false
namespace: 'default'
name: myapp-pod
rules: