1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-05 07:26:55 +00:00

merge main

This commit is contained in:
Jim Bugwadia 2020-12-04 16:52:10 -08:00
commit 1c2262b6e2
12 changed files with 69 additions and 91 deletions

View file

@ -83,7 +83,6 @@ func validateResourceElement(log logr.Logger, resourceElement, patternElement, o
func validateMap(log logr.Logger, resourceMap, patternMap map[string]interface{}, origPattern interface{}, path string, ac *common.AnchorKey) (string, error) {
patternMap = wildcards.ExpandInMetadata(patternMap, resourceMap)
// check if there is anchor in pattern
// Phase 1 : Evaluate all the anchors
// Phase 2 : Evaluate non-anchors

View file

@ -174,8 +174,6 @@ func validateResource(log logr.Logger, ctx context.EvalInterface, policy kyverno
}
// check if the resource satisfies the filter conditions defined in the rule
// TODO: this needs to be extracted, to filter the resource so that we can avoid passing resources that
// dont satisfy a policy rule resource description
if err := MatchesResourceDescription(resource, rule, admissionInfo, excludeResource); err != nil {
log.V(4).Info("resource fails the match description", "reason", err.Error())
continue
@ -190,7 +188,7 @@ func validateResource(log logr.Logger, ctx context.EvalInterface, policy kyverno
// operate on the copy of the conditions, as we perform variable substitution
preconditionsCopy := copyConditions(rule.Conditions)
// evaluate pre-conditions
// - handle variable subsitutions
// - handle variable substitutions
if !variables.EvaluateConditions(log, ctx, preconditionsCopy) {
log.V(4).Info("resource fails the preconditions")
continue
@ -296,13 +294,13 @@ func validatePatterns(log logr.Logger, ctx context.EvalInterface, resource unstr
anyPatterns, err := rule.Validation.DeserializeAnyPattern()
if err != nil {
resp.Success = false
resp.Message = fmt.Sprintf("Failed to deserialze anyPattern, expect type array: %v", err)
resp.Message = fmt.Sprintf("Failed to deserialize anyPattern, expect type array: %v", err)
return resp
}
for idx, pattern := range anyPatterns {
if pattern, err = variables.SubstituteVars(logger, ctx, pattern); err != nil {
// variable subsitution failed
// variable substitution failed
failedSubstitutionsErrors = append(failedSubstitutionsErrors, err)
continue
}
@ -317,7 +315,7 @@ func validatePatterns(log logr.Logger, ctx context.EvalInterface, resource unstr
failedAnyPatternsErrors = append(failedAnyPatternsErrors, patternErr)
}
// Subsitution falures
// Substitution failures
if len(failedSubstitutionsErrors) > 0 {
resp.Success = false
resp.Message = fmt.Sprintf("Substitutions failed: %v", failedSubstitutionsErrors)

View file

@ -13,6 +13,7 @@ import (
dclient "github.com/kyverno/kyverno/pkg/dclient"
"github.com/kyverno/kyverno/pkg/engine"
"github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/utils"
"github.com/kyverno/kyverno/pkg/engine/validate"
"github.com/kyverno/kyverno/pkg/engine/variables"
apierrors "k8s.io/apimachinery/pkg/api/errors"
@ -257,12 +258,32 @@ func updateGenerateExecutionTime(newTime time.Duration, oldAverageTimeString str
return time.Duration(newAverageTimeInNanoSeconds) * time.Nanosecond
}
func getResourceInfo(object map[string]interface{}) (kind, name, namespace, apiversion string, err error) {
if kind, _, err = unstructured.NestedString(object, "kind"); err != nil {
return "", "", "", "", err
}
if name, _, err = unstructured.NestedString(object, "name"); err != nil {
return "", "", "", "", err
}
if namespace, _, err = unstructured.NestedString(object, "namespace"); err != nil {
return "", "", "", "", err
}
if apiversion, _, err = unstructured.NestedString(object, "apiVersion"); err != nil {
return "", "", "", "", err
}
return
}
func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resource unstructured.Unstructured, ctx context.EvalInterface, policy string, gr kyverno.GenerateRequest, processExisting bool) (kyverno.ResourceSpec, error) {
var rdata map[string]interface{}
var err error
var mode ResourceMode
var noGenResource kyverno.ResourceSpec
// convert to unstructured Resource
genUnst, err := getUnstrRule(rule.Generation.DeepCopy())
if err != nil {
return noGenResource, err
@ -275,25 +296,13 @@ func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resou
if err != nil {
return noGenResource, err
}
genUnst.Object, _ = object.(map[string]interface{})
genKind, _, err := unstructured.NestedString(genUnst.Object, "kind")
if err != nil {
return noGenResource, err
}
genName, _, err := unstructured.NestedString(genUnst.Object, "name")
if err != nil {
return noGenResource, err
}
genNamespace, _, err := unstructured.NestedString(genUnst.Object, "namespace")
genKind, genName, genNamespace, genAPIVersion, err := getResourceInfo(genUnst.Object)
if err != nil {
return noGenResource, err
}
genAPIVersion, _, err := unstructured.NestedString(genUnst.Object, "apiVersion")
if err != nil {
return noGenResource, err
}
// Resource to be generated
newGenResource := kyverno.ResourceSpec{
APIVersion: genAPIVersion,
@ -301,14 +310,17 @@ func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resou
Namespace: genNamespace,
Name: genName,
}
genData, _, err := unstructured.NestedMap(genUnst.Object, "data")
if err != nil {
return noGenResource, err
}
genCopy, _, err := unstructured.NestedMap(genUnst.Object, "clone")
if err != nil {
return noGenResource, err
}
if genData != nil {
rdata, mode, err = manageData(log, genAPIVersion, genKind, genNamespace, genName, genData, client, resource)
} else {
@ -317,10 +329,6 @@ func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resou
logger := log.WithValues("genKind", genKind, "genAPIVersion", genAPIVersion, "genNamespace", genNamespace, "genName", genName)
if err != nil {
return noGenResource, err
}
if rdata == nil {
// existing resource contains the configuration
return newGenResource, nil
@ -373,15 +381,17 @@ func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resou
isUpdate = true
}
} else {
if label["policy.kyverno.io/synchronize"] == "enable" {
isUpdate = true
if label["policy.kyverno.io/synchronize"] == "disable" {
isUpdate = false
}
}
if rule.Generation.Synchronize {
label["policy.kyverno.io/synchronize"] = "enable"
} else {
label["policy.kyverno.io/synchronize"] = "disable"
}
if isUpdate {
logger.V(4).Info("updating existing resource")
newResource.SetLabels(label)
@ -402,8 +412,6 @@ func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resou
}
logger.V(2).Info("updated generated resource")
}
logger.V(2).Info("Synchronize resource is disabled")
}
return newGenResource, nil
}
@ -493,15 +501,5 @@ func getUnstrRule(rule *kyverno.Generation) (*unstructured.Unstructured, error)
if err != nil {
return nil, err
}
return ConvertToUnstructured(ruleData)
}
//ConvertToUnstructured converts the resource to unstructured format
func ConvertToUnstructured(data []byte) (*unstructured.Unstructured, error) {
resource := &unstructured.Unstructured{}
err := resource.UnmarshalJSON(data)
if err != nil {
return nil, err
}
return resource, nil
return utils.ConvertToUnstructured(ruleData)
}

View file

@ -29,7 +29,7 @@ func ContainsVariablesOtherThanObject(policy kyverno.ClusterPolicy) error {
ctx := context.NewContext(filterVars...)
for condIdx, condition := range rule.Conditions {
if condition.Key, err = variables.SubstituteVars(log.Log, ctx, condition.Key); !checkNotFoundErr(err) {
return fmt.Errorf("invalid variable %s used at spec/rules[%d]/condition[%d]/key",condition.Key, idx, condIdx)
return fmt.Errorf("invalid variable %s used at spec/rules[%d]/condition[%d]/key", condition.Key, idx, condIdx)
}
if condition.Value, err = variables.SubstituteVars(log.Log, ctx, condition.Value); !checkNotFoundErr(err) {

View file

@ -137,18 +137,12 @@ func (builder *requestBuilder) build(info Info) (req *unstructured.Unstructured,
}
// deletion of a result entry
// - on resource deleteion:
// - info.Rules == 0 && info.PolicyName == ""
// - set label delete.resource=resourceKind-resourceNamespace-resourceName
// - on policy deleteion:
// - info.PolicyName != "" && info.Resource == {}
// - set label delete.policy=policyName
if len(info.Rules) == 0 && info.PolicyName == "" {
if len(info.Rules) == 0 && info.PolicyName == "" { // on resource deleteion
req.SetLabels(map[string]string{
resourceLabelNamespace: info.Resource.GetNamespace(),
deletedLabelResource: info.Resource.GetName(),
deletedLabelResourceKind: info.Resource.GetKind()})
} else if info.PolicyName != "" && reflect.DeepEqual(info.Resource, unstructured.Unstructured{}) {
} else if info.PolicyName != "" && reflect.DeepEqual(info.Resource, unstructured.Unstructured{}) { // on policy deleteion
req.SetKind("ReportChangeRequest")
if len(info.Rules) == 0 {

View file

@ -230,7 +230,7 @@ func (g *ReportGenerator) handleErr(err error, key interface{}) {
}
// syncHandler reconciles clusterPolicyReport if namespace == ""
// otherwise it updates policyrReport
// otherwise it updates policyReport
func (g *ReportGenerator) syncHandler(key string) error {
if policy, rule, ok := isDeletedPolicyKey(key); ok {
return g.removePolicyEntryFromReport(policy, rule)
@ -251,7 +251,7 @@ func (g *ReportGenerator) syncHandler(key string) error {
return err
}
g.cleanupReportRequets(aggregatedRequests)
g.cleanupReportRequests(aggregatedRequests)
return nil
}
@ -274,7 +274,7 @@ func (g *ReportGenerator) createReportIfNotPresent(namespace string, new *unstru
}
log.V(2).Info("successfully created policyReport", "namespace", new.GetNamespace(), "name", new.GetName())
g.cleanupReportRequets(aggregatedRequests)
g.cleanupReportRequests(aggregatedRequests)
return nil, nil
}
@ -290,7 +290,7 @@ func (g *ReportGenerator) createReportIfNotPresent(namespace string, new *unstru
}
log.V(2).Info("successfully created ClusterPolicyReport")
g.cleanupReportRequets(aggregatedRequests)
g.cleanupReportRequests(aggregatedRequests)
return nil, nil
}
return nil, nil
@ -373,7 +373,7 @@ func (g *ReportGenerator) removePolicyEntryFromReport(policyName, ruleName strin
return err
}
g.cleanupReportRequets(aggregatedRequests)
g.cleanupReportRequests(aggregatedRequests)
return nil
}
@ -381,7 +381,7 @@ func (g *ReportGenerator) aggregateReports(namespace string) (
report *unstructured.Unstructured, aggregatedRequests interface{}, err error) {
if namespace == "" {
requests, err := g.clusterReportLister.List(labels.Everything())
requests, err := g.clusterReportChangeRequestLister.List(labels.Everything())
if err != nil {
return nil, nil, fmt.Errorf("unable to list ClusterReportChangeRequests within: %v", err)
}
@ -505,14 +505,14 @@ func (g *ReportGenerator) updateReport(old interface{}, new *unstructured.Unstru
return nil
}
oldUnstructed := make(map[string]interface{})
oldUnstructured := make(map[string]interface{})
if oldTyped, ok := old.(*report.ClusterPolicyReport); ok {
if oldTyped.GetDeletionTimestamp() != nil {
return g.dclient.DeleteResource(oldTyped.APIVersion, "ClusterPolicyReport", oldTyped.Namespace, oldTyped.Name, false)
}
if oldUnstructed, err = runtime.DefaultUnstructuredConverter.ToUnstructured(oldTyped); err != nil {
if oldUnstructured, err = runtime.DefaultUnstructuredConverter.ToUnstructured(oldTyped); err != nil {
return fmt.Errorf("unable to convert clusterPolicyReport: %v", err)
}
new.SetUID(oldTyped.GetUID())
@ -522,7 +522,7 @@ func (g *ReportGenerator) updateReport(old interface{}, new *unstructured.Unstru
return g.dclient.DeleteResource(oldTyped.APIVersion, "PolicyReport", oldTyped.Namespace, oldTyped.Name, false)
}
if oldUnstructed, err = runtime.DefaultUnstructuredConverter.ToUnstructured(oldTyped); err != nil {
if oldUnstructured, err = runtime.DefaultUnstructuredConverter.ToUnstructured(oldTyped); err != nil {
return fmt.Errorf("unable to convert policyReport: %v", err)
}
@ -530,13 +530,13 @@ func (g *ReportGenerator) updateReport(old interface{}, new *unstructured.Unstru
new.SetResourceVersion(oldTyped.GetResourceVersion())
}
obj, err := updateResults(oldUnstructed, new.UnstructuredContent(), aggregatedRequests)
obj, err := updateResults(oldUnstructured, new.UnstructuredContent(), aggregatedRequests)
if err != nil {
return fmt.Errorf("failed to update results entry: %v", err)
}
new.Object = obj
if !hasResultsChanged(oldUnstructed, new.UnstructuredContent()) {
if !hasResultsChanged(oldUnstructured, new.UnstructuredContent()) {
g.log.V(4).Info("unchanged policy report", "namespace", new.GetNamespace(), "name", new.GetName())
return nil
}
@ -549,7 +549,7 @@ func (g *ReportGenerator) updateReport(old interface{}, new *unstructured.Unstru
return
}
func (g *ReportGenerator) cleanupReportRequets(requestsGeneral interface{}) {
func (g *ReportGenerator) cleanupReportRequests(requestsGeneral interface{}) {
defer g.log.V(5).Info("successfully cleaned up report requests")
if requests, ok := requestsGeneral.([]*changerequest.ReportChangeRequest); ok {
for _, request := range requests {

View file

@ -310,23 +310,23 @@ func (gen *Generator) sync(reportReq *unstructured.Unstructured, info Info) erro
}
func updateReportChangeRequest(dClient *client.Client, old interface{}, new *unstructured.Unstructured, log logr.Logger) (err error) {
oldUnstructed := make(map[string]interface{})
oldUnstructured := make(map[string]interface{})
if oldTyped, ok := old.(*changerequest.ReportChangeRequest); ok {
if oldUnstructed, err = runtime.DefaultUnstructuredConverter.ToUnstructured(oldTyped); err != nil {
if oldUnstructured, err = runtime.DefaultUnstructuredConverter.ToUnstructured(oldTyped); err != nil {
return fmt.Errorf("unable to convert reportChangeRequest: %v", err)
}
new.SetResourceVersion(oldTyped.GetResourceVersion())
new.SetUID(oldTyped.GetUID())
} else {
oldTyped := old.(*changerequest.ClusterReportChangeRequest)
if oldUnstructed, err = runtime.DefaultUnstructuredConverter.ToUnstructured(oldTyped); err != nil {
if oldUnstructured, err = runtime.DefaultUnstructuredConverter.ToUnstructured(oldTyped); err != nil {
return fmt.Errorf("unable to convert clusterReportChangeRequest: %v", err)
}
new.SetUID(oldTyped.GetUID())
new.SetResourceVersion(oldTyped.GetResourceVersion())
}
if !hasResultsChanged(oldUnstructed, new.UnstructuredContent()) {
if !hasResultsChanged(oldUnstructured, new.UnstructuredContent()) {
log.V(4).Info("unchanged report request", "name", new.GetName())
return nil
}

View file

@ -126,7 +126,6 @@ func generateDebugValidatingWebhook(name, url string, caData []byte, validate bo
}
}
// mutating webhook
func generateMutatingWebhook(name, servicePath string, caData []byte, validation bool, timeoutSeconds int32, resources []string, apiGroups, apiVersions string, operationTypes []admregapi.OperationType) admregapi.MutatingWebhook {
sideEffect := admregapi.SideEffectClassNoneOnDryRun

View file

@ -28,8 +28,8 @@ const (
// 4. Resource Mutation
// 5. Webhook Status Mutation
type Register struct {
client *client.Client
clientConfig *rest.Config
client *client.Client
clientConfig *rest.Config
serverIP string // when running outside a cluster
timeoutSeconds int32
log logr.Logger
@ -293,7 +293,7 @@ func (wrc *Register) removePolicyMutatingWebhookConfiguration(wg *sync.WaitGroup
if errorsapi.IsNotFound(err) {
logger.V(5).Info("policy mutating webhook configuration not found")
return
}
}
if err != nil {
logger.Error(err, "failed to delete policy mutating webhook configuration")
@ -423,8 +423,6 @@ func (wrc *Register) getVerifyWebhookMutatingWebhookName() string {
return mutatingConfig
}
// GetWebhookTimeOut returns the value of webhook timeout
func (wrc *Register) GetWebhookTimeOut() time.Duration {
return time.Duration(wrc.timeoutSeconds)

View file

@ -160,4 +160,3 @@ func (wrc *Register) removeResourceValidatingWebhookConfiguration(wg *sync.WaitG
logger.Info("webhook configuration deleted")
return
}

View file

@ -540,38 +540,31 @@ func (ws *WebhookServer) bodyToAdmissionReview(request *http.Request, writer htt
return admissionReview
}
// excludeKyvernoResources will check resource can have acces or not
// excludeKyvernoResources will check resource can have access or not
func (ws *WebhookServer) excludeKyvernoResources(request *v1beta1.AdmissionRequest) error {
logger := ws.log.WithName("resourceValidation").WithValues("uid", request.UID, "kind", request.Kind.Kind, "namespace", request.Namespace, "name", request.Name, "operation", request.Operation)
var resource *unstructured.Unstructured
var err error
var isManagedResourceCheck bool
if request.Operation == v1beta1.Delete {
resource, err = enginutils.ConvertToUnstructured(request.OldObject.Raw)
isManagedResourceCheck = true
} else if request.Operation == v1beta1.Update {
resource, err = enginutils.ConvertToUnstructured(request.Object.Raw)
isManagedResourceCheck = true
}
if err != nil {
logger.Error(err, "failed to convert object resource to unstructured format")
return err
}
if isManagedResourceCheck {
labels := resource.GetLabels()
if labels != nil {
if labels["app.kubernetes.io/managed-by"] == "kyverno" && labels["policy.kyverno.io/synchronize"] == "enable" {
isAuthorized, err := userinfo.IsRoleAuthorize(ws.rbLister, ws.crbLister, ws.rLister, ws.crLister, request, ws.configHandler)
if err != nil {
return fmt.Errorf("failed to get RBAC information for request %v", err)
}
if !isAuthorized {
// convert RAW to unstructured
return fmt.Errorf("resource is managed by a Kyverno policy and cannot be update manually. You can edit the policy %s to update this resource", labels["policy.kyverno.io/policy-name"])
}
}
labels := resource.GetLabels()
if labels["app.kubernetes.io/managed-by"] == "kyverno" && labels["policy.kyverno.io/synchronize"] == "enable" {
isAuthorized, err := userinfo.IsRoleAuthorize(ws.rbLister, ws.crbLister, ws.rLister, ws.crLister, request, ws.configHandler)
if err != nil {
return fmt.Errorf("failed to get RBAC information for request %v", err)
}
if !isAuthorized {
return fmt.Errorf("resource is managed by a Kyverno policy and cannot be update manually. You can edit the policy %s to update this resource", labels["policy.kyverno.io/policy-name"])
}
}

View file

@ -115,7 +115,7 @@ func HandleValidation(
// resource is blocked, as there is a policy in "enforce" mode that failed.
// create an event on the policy to inform the resource request was blocked
// Scenario 2:
// some/all policies failed to apply on the resource. a policy volation is generated.
// some/all policies failed to apply on the resource. a policy violation is generated.
// create an event on the resource and the policy that failed
// Scenario 3:
// all policies were applied successfully.