mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-13 19:28:55 +00:00
Merge branch 'wildcard_support' into feature_add_pkg_engine
* wildcard_support: parse regex from policyResourceName violation framework updates implement wildcard support
This commit is contained in:
commit
0ec59e2d63
5 changed files with 75 additions and 51 deletions
|
@ -80,7 +80,7 @@ func NewPolicyController(config *rest.Config, logger *log.Logger) (*PolicyContro
|
|||
func (c *PolicyController) Run(stopCh <-chan struct{}) {
|
||||
c.policyInformerFactory.Start(stopCh)
|
||||
// Un-comment to run the violation Builder
|
||||
// c.violationBuilder.Run(1, stopCh)
|
||||
c.violationBuilder.Run(1, stopCh)
|
||||
}
|
||||
|
||||
// GetPolicies retrieves all policy resources
|
||||
|
@ -135,12 +135,12 @@ func (c *PolicyController) addPolicyLog(name, text string) {
|
|||
|
||||
// Add new log record
|
||||
text = time.Now().Format("2006 Jan 02 15:04:05.999 ") + text
|
||||
policy.Status.Logs = append(policy.Status.Logs, text)
|
||||
//policy.Status.Logs = append(policy.Status.Logs, text)
|
||||
// Pop front extra log records
|
||||
logsCount := len(policy.Status.Logs)
|
||||
if logsCount > policyLogMaxRecords {
|
||||
policy.Status.Logs = policy.Status.Logs[logsCount-policyLogMaxRecords:]
|
||||
}
|
||||
// logsCount := len(policy.Status.Logs)
|
||||
// if logsCount > policyLogMaxRecords {
|
||||
// policy.Status.Logs = policy.Status.Logs[logsCount-policyLogMaxRecords:]
|
||||
// }
|
||||
// Save logs to policy object
|
||||
_, err = c.policiesInterface.UpdateStatus(policy)
|
||||
if err != nil {
|
||||
|
|
|
@ -3,6 +3,7 @@ package v1alpha1
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
@ -65,6 +66,14 @@ func (pr *PolicyResource) Validate() error {
|
|||
}
|
||||
}
|
||||
|
||||
if pr.Name != nil {
|
||||
// // make non-regexp a regexp to match exactly to the given name
|
||||
// *pr.Name = "^" + *pr.Name + "$"
|
||||
if _, err := regexp.Compile(*pr.Name); err != nil {
|
||||
return fmt.Errorf("invalied regex, err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package webhooks
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
types "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1"
|
||||
"k8s.io/api/admission/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
@ -43,65 +46,55 @@ func AdmissionIsRequired(request *v1beta1.AdmissionRequest) bool {
|
|||
}
|
||||
|
||||
// Checks requests kind, name and labels to fit the policy
|
||||
func IsRuleApplicableToRequest(policyResource types.PolicyResource, request *v1beta1.AdmissionRequest) bool {
|
||||
func IsRuleApplicableToRequest(policyResource types.PolicyResource, request *v1beta1.AdmissionRequest) (bool, error) {
|
||||
return IsRuleApplicableToResource(request.Kind.Kind, request.Object.Raw, policyResource)
|
||||
// if policyResource.Kind != request.Kind.Kind {
|
||||
// return false
|
||||
// }
|
||||
|
||||
// if request.Object.Raw != nil {
|
||||
// meta := parseMetadataFromObject(request.Object.Raw)
|
||||
// name := parseNameFromMetadata(meta)
|
||||
|
||||
// if policyResource.Name != nil && *policyResource.Name != name {
|
||||
// return false
|
||||
// }
|
||||
|
||||
// if policyResource.Selector != nil {
|
||||
// selector, err := metav1.LabelSelectorAsSelector(policyResource.Selector)
|
||||
|
||||
// if err != nil {
|
||||
// return false
|
||||
// }
|
||||
|
||||
// labelMap := parseLabelsFromMetadata(meta)
|
||||
|
||||
// if !selector.Matches(labelMap) {
|
||||
// return false
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return true
|
||||
}
|
||||
|
||||
// kind is the type of object being manipulated
|
||||
func IsRuleApplicableToResource(kind string, resourceRaw []byte, policyResource types.PolicyResource) bool {
|
||||
// Checks requests kind, name and labels to fit the policy
|
||||
func IsRuleApplicableToResource(kind string, resourceRaw []byte, policyResource types.PolicyResource) (bool, error) {
|
||||
if policyResource.Kind != kind {
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if resourceRaw != nil {
|
||||
meta := parseMetadataFromObject(resourceRaw)
|
||||
name := parseNameFromMetadata(meta)
|
||||
|
||||
if policyResource.Name != nil && *policyResource.Name != name {
|
||||
return false
|
||||
if policyResource.Name != nil {
|
||||
|
||||
policyResourceName, isRegex := parseRegexPolicyResourceName(*policyResource.Name)
|
||||
fmt.Println("policyResourceName, name, isRegex", policyResourceName, name, isRegex)
|
||||
|
||||
// if no regex used, check if names are matched, return directly
|
||||
if !isRegex && policyResourceName != name {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// validation of regex is peformed when validating the policyResource
|
||||
// refer to policyResource.Validate()
|
||||
if isRegex {
|
||||
match, _ := regexp.MatchString(policyResourceName, name)
|
||||
if !match {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if policyResource.Selector != nil {
|
||||
selector, err := metav1.LabelSelectorAsSelector(policyResource.Selector)
|
||||
|
||||
if err != nil {
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
labelMap := parseLabelsFromMetadata(meta)
|
||||
|
||||
if !selector.Matches(labelMap) {
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ func (mw *MutationWebhook) Mutate(request *v1beta1.AdmissionRequest) *v1beta1.Ad
|
|||
for _, policy := range policies {
|
||||
mw.logger.Printf("Applying policy %s with %d rules", policy.ObjectMeta.Name, len(policy.Spec.Rules))
|
||||
|
||||
policyPatches, err := mw.applyPolicyRules(request, policy)
|
||||
policyPatches, _, err := mw.applyPolicyRules(request, policy)
|
||||
if err != nil {
|
||||
mw.controller.LogPolicyError(policy.Name, err.Error())
|
||||
|
||||
|
@ -78,6 +78,7 @@ func (mw *MutationWebhook) Mutate(request *v1beta1.AdmissionRequest) *v1beta1.Ad
|
|||
namespace := parseNamespaceFromMetadata(meta)
|
||||
name := parseNameFromMetadata(meta)
|
||||
mw.controller.LogPolicyInfo(policy.Name, fmt.Sprintf("Applied to %s %s/%s", request.Kind.Kind, namespace, name))
|
||||
mw.logger.Printf("%s applied to %s %s/%s", policy.Name, request.Kind.Kind, namespace, name)
|
||||
|
||||
allPatches = append(allPatches, policyPatches...)
|
||||
}
|
||||
|
@ -103,37 +104,43 @@ func getPolicyPatchingSets(policy types.Policy) PatchingSets {
|
|||
// Applies all policy rules to the created object and returns list of processed JSON patches.
|
||||
// May return nil patches if it is not necessary to create patches for requested object.
|
||||
// Returns error ONLY in case when creation of resource should be denied.
|
||||
func (mw *MutationWebhook) applyPolicyRules(request *v1beta1.AdmissionRequest, policy types.Policy) ([]PatchBytes, error) {
|
||||
func (mw *MutationWebhook) applyPolicyRules(request *v1beta1.AdmissionRequest, policy types.Policy) ([]PatchBytes, int, error) {
|
||||
return mw.applyPolicyRulesOnResource(request.Kind.Kind, request.Object.Raw, policy)
|
||||
}
|
||||
|
||||
// TODO: add another violation field in return elements
|
||||
// kind is the type of object being manipulated
|
||||
func (mw *MutationWebhook) applyPolicyRulesOnResource(kind string, rawResource []byte, policy types.Policy) ([]PatchBytes, error) {
|
||||
func (mw *MutationWebhook) applyPolicyRulesOnResource(kind string, rawResource []byte, policy types.Policy) ([]PatchBytes, int, error) {
|
||||
patchingSets := getPolicyPatchingSets(policy)
|
||||
var policyPatches []PatchBytes
|
||||
violationCount := 0
|
||||
|
||||
for ruleIdx, rule := range policy.Spec.Rules {
|
||||
err := rule.Validate()
|
||||
if err != nil {
|
||||
mw.logger.Printf("Invalid rule detected: #%d in policy %s", ruleIdx, policy.ObjectMeta.Name)
|
||||
mw.logger.Printf("Invalid rule detected: #%d in policy %s, err: %v\n", ruleIdx, policy.ObjectMeta.Name, err)
|
||||
violationCount++
|
||||
continue
|
||||
}
|
||||
|
||||
if !IsRuleApplicableToResource(kind, rawResource, rule.Resource) {
|
||||
return nil, nil
|
||||
if ok, err := IsRuleApplicableToResource(kind, rawResource, rule.Resource); !ok {
|
||||
mw.logger.Printf("Rule %d of policy %s does not match the request", ruleIdx, policy.Name)
|
||||
violationCount++
|
||||
return nil, violationCount, err
|
||||
}
|
||||
|
||||
// configMapGenerator and secretGenerator can be applied only to namespaces
|
||||
if kind == "Namespace" {
|
||||
err = mw.applyRuleGenerators(rawResource, rule)
|
||||
if err != nil && patchingSets == PatchingSetsStopOnError {
|
||||
return nil, fmt.Errorf("Failed to apply generators from rule #%d: %s", ruleIdx, err)
|
||||
violationCount++
|
||||
return nil, violationCount, fmt.Errorf("Failed to apply generators from rule #%d: %s", ruleIdx, err)
|
||||
}
|
||||
}
|
||||
rulePatchesProcessed, err := ProcessPatches(rule.Patches, rawResource, patchingSets)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to process patches from rule #%d: %s", ruleIdx, err)
|
||||
violationCount++
|
||||
return nil, violationCount, fmt.Errorf("Failed to process patches from rule #%d: %s", ruleIdx, err)
|
||||
}
|
||||
|
||||
if rulePatchesProcessed != nil {
|
||||
|
@ -144,7 +151,12 @@ func (mw *MutationWebhook) applyPolicyRulesOnResource(kind string, rawResource [
|
|||
}
|
||||
}
|
||||
|
||||
return policyPatches, nil
|
||||
// if no rules are validate, return error to deny resource creation
|
||||
if policyPatches == nil {
|
||||
return nil, violationCount, fmt.Errorf("no patches prepared, violations: %v", violationCount)
|
||||
}
|
||||
|
||||
return policyPatches, violationCount, nil
|
||||
}
|
||||
|
||||
// Applies "configMapGenerator" and "secretGenerator" described in PolicyRule
|
||||
|
|
|
@ -2,6 +2,7 @@ package webhooks
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
@ -38,3 +39,12 @@ func parseNamespaceFromMetadata(meta map[string]interface{}) string {
|
|||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// returns true if policyResourceName is a regexp
|
||||
func parseRegexPolicyResourceName(policyResourceName string) (string, bool) {
|
||||
regex := strings.Split(policyResourceName, "regex:")
|
||||
if len(regex) == 1 {
|
||||
return regex[0], false
|
||||
}
|
||||
return strings.Trim(regex[1], " "), true
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue