1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-31 03:45:17 +00:00

change engine interface to take policyContext struct

This commit is contained in:
Shuting Zhao 2019-11-08 18:57:27 -08:00
parent 0e9a952d64
commit 6048d59949
7 changed files with 85 additions and 28 deletions

View file

@ -5,13 +5,15 @@ import (
"time" "time"
"github.com/golang/glog" "github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1alpha1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
) )
// Mutate performs mutation. Overlay first and then mutation patches // Mutate performs mutation. Overlay first and then mutation patches
func Mutate(policy kyverno.ClusterPolicy, resource unstructured.Unstructured) (response EngineResponse) { func Mutate(policyContext PolicyContext) (response EngineResponse) {
startTime := time.Now() startTime := time.Now()
policy := policyContext.Policy
resource := policyContext.Resource
// policy information // policy information
func() { func() {
// set policy information // set policy information
@ -40,6 +42,13 @@ func Mutate(policy kyverno.ClusterPolicy, resource unstructured.Unstructured) (r
if !rule.HasMutate() { if !rule.HasMutate() {
continue continue
} }
if !matchAdmissionInfo(rule, policyContext.AdmissionInfo) {
glog.Infof("rule '%s' cannot be applied on %s/%s/%s, admission permission: %v",
rule.Name, resource.GetKind(), resource.GetNamespace(), resource.GetName(), policyContext.AdmissionInfo)
continue
}
// check if the resource satisfies the filter conditions defined in the rule // 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 //TODO: this needs to be extracted, to filter the resource so that we can avoid passing resources that
// dont statisfy a policy rule resource description // dont statisfy a policy rule resource description

View file

@ -0,0 +1,26 @@
package engine
import (
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1alpha1"
authenticationv1 "k8s.io/api/authentication/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
// PolicyContext contains the contexts for engine to process
type PolicyContext struct {
// policy to be processed
Policy kyverno.ClusterPolicy
// resource to be processed
Resource unstructured.Unstructured
AdmissionInfo RequestInfo
}
// RequestInfo contains permission info carried in an admission request
type RequestInfo struct {
// Roles is a list of possible role send the request
Roles []string
// ClusterRoles is a list of possible clusterRoles send the request
ClusterRoles []string
// UserInfo is the userInfo carried in the admission request
AdmissionUserInfo authenticationv1.UserInfo
}

View file

@ -16,8 +16,11 @@ import (
) )
//Validate applies validation rules from policy on the resource //Validate applies validation rules from policy on the resource
func Validate(policy kyverno.ClusterPolicy, resource unstructured.Unstructured) (response EngineResponse) { func Validate(policyContext PolicyContext) (response EngineResponse) {
startTime := time.Now() startTime := time.Now()
policy := policyContext.Policy
resource := policyContext.Resource
// policy information // policy information
func() { func() {
// set policy information // set policy information

View file

@ -1628,7 +1628,8 @@ func TestValidate_ServiceTest(t *testing.T) {
resourceUnstructured, err := ConvertToUnstructured(rawResource) resourceUnstructured, err := ConvertToUnstructured(rawResource)
assert.NilError(t, err) assert.NilError(t, err)
er := Validate(policy, *resourceUnstructured)
er := Validate(PolicyContext{Policy: policy, Resource: *resourceUnstructured})
assert.Assert(t, len(er.PolicyResponse.Rules) == 0) assert.Assert(t, len(er.PolicyResponse.Rules) == 0)
} }
@ -1725,7 +1726,7 @@ func TestValidate_MapHasFloats(t *testing.T) {
resourceUnstructured, err := ConvertToUnstructured(rawResource) resourceUnstructured, err := ConvertToUnstructured(rawResource)
assert.NilError(t, err) assert.NilError(t, err)
er := Validate(policy, *resourceUnstructured) er := Validate(PolicyContext{Policy: policy, Resource: *resourceUnstructured})
assert.Assert(t, len(er.PolicyResponse.Rules) == 0) assert.Assert(t, len(er.PolicyResponse.Rules) == 0)
} }
@ -1820,7 +1821,7 @@ func TestValidate_image_tag_fail(t *testing.T) {
"Validation rule 'validate-tag' succesfully validated", "Validation rule 'validate-tag' succesfully validated",
"Validation rule 'validate-latest' failed at '/spec/containers/0/imagePullPolicy/' for resource Pod//myapp-pod. imagePullPolicy 'Always' required with tag 'latest'.", "Validation rule 'validate-latest' failed at '/spec/containers/0/imagePullPolicy/' for resource Pod//myapp-pod. imagePullPolicy 'Always' required with tag 'latest'.",
} }
er := Validate(policy, *resourceUnstructured) er := Validate(PolicyContext{Policy: policy, Resource: *resourceUnstructured})
for index, r := range er.PolicyResponse.Rules { for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index]) assert.Equal(t, r.Message, msgs[index])
} }
@ -1918,7 +1919,7 @@ func TestValidate_image_tag_pass(t *testing.T) {
"Validation rule 'validate-tag' succesfully validated", "Validation rule 'validate-tag' succesfully validated",
"Validation rule 'validate-latest' succesfully validated", "Validation rule 'validate-latest' succesfully validated",
} }
er := Validate(policy, *resourceUnstructured) er := Validate(PolicyContext{Policy: policy, Resource: *resourceUnstructured})
for index, r := range er.PolicyResponse.Rules { for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index]) assert.Equal(t, r.Message, msgs[index])
} }
@ -1991,7 +1992,7 @@ func TestValidate_Fail_anyPattern(t *testing.T) {
resourceUnstructured, err := ConvertToUnstructured(rawResource) resourceUnstructured, err := ConvertToUnstructured(rawResource)
assert.NilError(t, err) assert.NilError(t, err)
er := Validate(policy, *resourceUnstructured) er := Validate(PolicyContext{Policy: policy, Resource: *resourceUnstructured})
msgs := []string{"Validation rule 'check-default-namespace' failed to validate patterns defined in anyPattern. A namespace is required.; anyPattern[0] failed at path /metadata/namespace/; anyPattern[1] failed at path /metadata/namespace/"} msgs := []string{"Validation rule 'check-default-namespace' failed to validate patterns defined in anyPattern. A namespace is required.; anyPattern[0] failed at path /metadata/namespace/; anyPattern[1] failed at path /metadata/namespace/"}
for index, r := range er.PolicyResponse.Rules { for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index]) assert.Equal(t, r.Message, msgs[index])
@ -2072,7 +2073,7 @@ func TestValidate_host_network_port(t *testing.T) {
resourceUnstructured, err := ConvertToUnstructured(rawResource) resourceUnstructured, err := ConvertToUnstructured(rawResource)
assert.NilError(t, err) assert.NilError(t, err)
er := Validate(policy, *resourceUnstructured) er := Validate(PolicyContext{Policy: policy, Resource: *resourceUnstructured})
msgs := []string{"Validation rule 'validate-host-network-port' failed at '/spec/containers/0/ports/0/hostPort/' for resource Pod//nginx-host-network. Host network and port are not allowed."} msgs := []string{"Validation rule 'validate-host-network-port' failed at '/spec/containers/0/ports/0/hostPort/' for resource Pod//nginx-host-network. Host network and port are not allowed."}
for index, r := range er.PolicyResponse.Rules { for index, r := range er.PolicyResponse.Rules {
@ -2161,7 +2162,7 @@ func TestValidate_anchor_arraymap_pass(t *testing.T) {
resourceUnstructured, err := ConvertToUnstructured(rawResource) resourceUnstructured, err := ConvertToUnstructured(rawResource)
assert.NilError(t, err) assert.NilError(t, err)
er := Validate(policy, *resourceUnstructured) er := Validate(PolicyContext{Policy: policy, Resource: *resourceUnstructured})
msgs := []string{"Validation rule 'validate-host-path' succesfully validated"} msgs := []string{"Validation rule 'validate-host-path' succesfully validated"}
for index, r := range er.PolicyResponse.Rules { for index, r := range er.PolicyResponse.Rules {
@ -2249,7 +2250,7 @@ func TestValidate_anchor_arraymap_fail(t *testing.T) {
resourceUnstructured, err := ConvertToUnstructured(rawResource) resourceUnstructured, err := ConvertToUnstructured(rawResource)
assert.NilError(t, err) assert.NilError(t, err)
er := Validate(policy, *resourceUnstructured) er := Validate(PolicyContext{Policy: policy, Resource: *resourceUnstructured})
msgs := []string{"Validation rule 'validate-host-path' failed at '/spec/volumes/0/hostPath/path/' for resource Pod//image-with-hostpath. Host path '/var/lib/' is not allowed."} msgs := []string{"Validation rule 'validate-host-path' failed at '/spec/volumes/0/hostPath/path/' for resource Pod//image-with-hostpath. Host path '/var/lib/' is not allowed."}
for index, r := range er.PolicyResponse.Rules { for index, r := range er.PolicyResponse.Rules {
@ -2318,7 +2319,7 @@ func TestValidate_anchor_map_notfound(t *testing.T) {
resourceUnstructured, err := ConvertToUnstructured(rawResource) resourceUnstructured, err := ConvertToUnstructured(rawResource)
assert.NilError(t, err) assert.NilError(t, err)
er := Validate(policy, *resourceUnstructured) er := Validate(PolicyContext{Policy: policy, Resource: *resourceUnstructured})
msgs := []string{"Validation rule 'pod rule 2' succesfully validated"} msgs := []string{"Validation rule 'pod rule 2' succesfully validated"}
for index, r := range er.PolicyResponse.Rules { for index, r := range er.PolicyResponse.Rules {
@ -2390,7 +2391,7 @@ func TestValidate_anchor_map_found_valid(t *testing.T) {
resourceUnstructured, err := ConvertToUnstructured(rawResource) resourceUnstructured, err := ConvertToUnstructured(rawResource)
assert.NilError(t, err) assert.NilError(t, err)
er := Validate(policy, *resourceUnstructured) er := Validate(PolicyContext{Policy: policy, Resource: *resourceUnstructured})
msgs := []string{"Validation rule 'pod rule 2' succesfully validated"} msgs := []string{"Validation rule 'pod rule 2' succesfully validated"}
for index, r := range er.PolicyResponse.Rules { for index, r := range er.PolicyResponse.Rules {
@ -2462,7 +2463,7 @@ func TestValidate_anchor_map_found_invalid(t *testing.T) {
resourceUnstructured, err := ConvertToUnstructured(rawResource) resourceUnstructured, err := ConvertToUnstructured(rawResource)
assert.NilError(t, err) assert.NilError(t, err)
er := Validate(policy, *resourceUnstructured) er := Validate(PolicyContext{Policy: policy, Resource: *resourceUnstructured})
msgs := []string{"Validation rule 'pod rule 2' failed at '/spec/securityContext/runAsNonRoot/' for resource Pod//myapp-pod. pod: validate run as non root user."} msgs := []string{"Validation rule 'pod rule 2' failed at '/spec/securityContext/runAsNonRoot/' for resource Pod//myapp-pod. pod: validate run as non root user."}
for index, r := range er.PolicyResponse.Rules { for index, r := range er.PolicyResponse.Rules {
@ -2536,7 +2537,7 @@ func TestValidate_AnchorList_pass(t *testing.T) {
resourceUnstructured, err := ConvertToUnstructured(rawResource) resourceUnstructured, err := ConvertToUnstructured(rawResource)
assert.NilError(t, err) assert.NilError(t, err)
er := Validate(policy, *resourceUnstructured) er := Validate(PolicyContext{Policy: policy, Resource: *resourceUnstructured})
msgs := []string{"Validation rule 'pod image rule' succesfully validated"} msgs := []string{"Validation rule 'pod image rule' succesfully validated"}
for index, r := range er.PolicyResponse.Rules { for index, r := range er.PolicyResponse.Rules {
@ -2610,7 +2611,7 @@ func TestValidate_AnchorList_fail(t *testing.T) {
resourceUnstructured, err := ConvertToUnstructured(rawResource) resourceUnstructured, err := ConvertToUnstructured(rawResource)
assert.NilError(t, err) assert.NilError(t, err)
er := Validate(policy, *resourceUnstructured) er := Validate(PolicyContext{Policy: policy, Resource: *resourceUnstructured})
// msgs := []string{"Validation rule 'pod image rule' failed at '/spec/containers/1/name/' for resource Pod//myapp-pod."} // msgs := []string{"Validation rule 'pod image rule' failed at '/spec/containers/1/name/' for resource Pod//myapp-pod."}
// for index, r := range er.PolicyResponse.Rules { // for index, r := range er.PolicyResponse.Rules {
// // t.Log(r.Message) // // t.Log(r.Message)
@ -2684,7 +2685,7 @@ func TestValidate_existenceAnchor_fail(t *testing.T) {
resourceUnstructured, err := ConvertToUnstructured(rawResource) resourceUnstructured, err := ConvertToUnstructured(rawResource)
assert.NilError(t, err) assert.NilError(t, err)
er := Validate(policy, *resourceUnstructured) er := Validate(PolicyContext{Policy: policy, Resource: *resourceUnstructured})
// msgs := []string{"Validation rule 'pod image rule' failed at '/spec/containers/' for resource Pod//myapp-pod."} // msgs := []string{"Validation rule 'pod image rule' failed at '/spec/containers/' for resource Pod//myapp-pod."}
// for index, r := range er.PolicyResponse.Rules { // for index, r := range er.PolicyResponse.Rules {
@ -2759,7 +2760,7 @@ func TestValidate_existenceAnchor_pass(t *testing.T) {
resourceUnstructured, err := ConvertToUnstructured(rawResource) resourceUnstructured, err := ConvertToUnstructured(rawResource)
assert.NilError(t, err) assert.NilError(t, err)
er := Validate(policy, *resourceUnstructured) er := Validate(PolicyContext{Policy: policy, Resource: *resourceUnstructured})
msgs := []string{"Validation rule 'pod image rule' succesfully validated"} msgs := []string{"Validation rule 'pod image rule' succesfully validated"}
for index, r := range er.PolicyResponse.Rules { for index, r := range er.PolicyResponse.Rules {
@ -2846,7 +2847,7 @@ func TestValidate_negationAnchor_deny(t *testing.T) {
resourceUnstructured, err := ConvertToUnstructured(rawResource) resourceUnstructured, err := ConvertToUnstructured(rawResource)
assert.NilError(t, err) assert.NilError(t, err)
er := Validate(policy, *resourceUnstructured) er := Validate(PolicyContext{Policy: policy, Resource: *resourceUnstructured})
msgs := []string{"Validation rule 'validate-host-path' failed at '/spec/volumes/0/hostPath/' for resource Pod//image-with-hostpath. Host path is not allowed."} msgs := []string{"Validation rule 'validate-host-path' failed at '/spec/volumes/0/hostPath/' for resource Pod//image-with-hostpath. Host path is not allowed."}
for index, r := range er.PolicyResponse.Rules { for index, r := range er.PolicyResponse.Rules {
@ -2932,7 +2933,7 @@ func TestValidate_negationAnchor_pass(t *testing.T) {
resourceUnstructured, err := ConvertToUnstructured(rawResource) resourceUnstructured, err := ConvertToUnstructured(rawResource)
assert.NilError(t, err) assert.NilError(t, err)
er := Validate(policy, *resourceUnstructured) er := Validate(PolicyContext{Policy: policy, Resource: *resourceUnstructured})
msgs := []string{"Validation rule 'validate-host-path' succesfully validated"} msgs := []string{"Validation rule 'validate-host-path' succesfully validated"}
for index, r := range er.PolicyResponse.Rules { for index, r := range er.PolicyResponse.Rules {

View file

@ -69,7 +69,7 @@ func applyPolicy(policy kyverno.ClusterPolicy, resource unstructured.Unstructure
sendStat(false) sendStat(false)
//VALIDATION //VALIDATION
engineResponse = engine.Validate(policy, resource) engineResponse = engine.Validate(engine.PolicyContext{Policy: policy, Resource: resource})
engineResponses = append(engineResponses, engineResponse) engineResponses = append(engineResponses, engineResponse)
// gather stats // gather stats
gatherStat(policy.Name, engineResponse.PolicyResponse) gatherStat(policy.Name, engineResponse.PolicyResponse)
@ -80,7 +80,7 @@ func applyPolicy(policy kyverno.ClusterPolicy, resource unstructured.Unstructure
return engineResponses return engineResponses
} }
func mutation(policy kyverno.ClusterPolicy, resource unstructured.Unstructured, policyStatus PolicyStatusInterface) (engine.EngineResponse, error) { func mutation(policy kyverno.ClusterPolicy, resource unstructured.Unstructured, policyStatus PolicyStatusInterface) (engine.EngineResponse, error) {
engineResponse := engine.Mutate(policy, resource) engineResponse := engine.Mutate(engine.PolicyContext{Policy: policy, Resource: resource})
if !engineResponse.IsSuccesful() { if !engineResponse.IsSuccesful() {
glog.V(4).Infof("mutation had errors reporting them") glog.V(4).Infof("mutation had errors reporting them")
return engineResponse, nil return engineResponse, nil

View file

@ -11,7 +11,8 @@ import (
) )
// HandleMutation handles mutating webhook admission request // HandleMutation handles mutating webhook admission request
func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest, policies []*v1alpha1.ClusterPolicy) (bool, []byte, string) { func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest,
policies []*v1alpha1.ClusterPolicy, roles, clusterRoles []string) (bool, []byte, string) {
glog.V(4).Infof("Receive request in mutating webhook: Kind=%s, Namespace=%s Name=%s UID=%s patchOperation=%s", glog.V(4).Infof("Receive request in mutating webhook: Kind=%s, Namespace=%s Name=%s UID=%s patchOperation=%s",
request.Kind.Kind, request.Namespace, request.Name, request.UID, request.Operation) request.Kind.Kind, request.Namespace, request.Name, request.UID, request.Operation)
@ -63,8 +64,16 @@ func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest, polic
resource.SetGroupVersionKind(schema.GroupVersionKind{Group: request.Kind.Group, Version: request.Kind.Version, Kind: request.Kind.Kind}) resource.SetGroupVersionKind(schema.GroupVersionKind{Group: request.Kind.Group, Version: request.Kind.Version, Kind: request.Kind.Kind})
var engineResponses []engine.EngineResponse var engineResponses []engine.EngineResponse
for _, policy := range policies { policyContext := engine.PolicyContext{
Resource: *resource,
AdmissionInfo: engine.RequestInfo{
Roles: roles,
ClusterRoles: clusterRoles,
AdmissionUserInfo: request.UserInfo},
}
for _, policy := range policies {
policyContext.Policy = *policy
// check if policy has a rule for the admission request kind // check if policy has a rule for the admission request kind
if !utils.ContainsString(getApplicableKindsForPolicy(policy), request.Kind.Kind) { if !utils.ContainsString(getApplicableKindsForPolicy(policy), request.Kind.Kind) {
continue continue
@ -73,7 +82,7 @@ func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest, polic
glog.V(2).Infof("Handling mutation for Kind=%s, Namespace=%s Name=%s UID=%s patchOperation=%s", glog.V(2).Infof("Handling mutation for Kind=%s, Namespace=%s Name=%s UID=%s patchOperation=%s",
resource.GetKind(), resource.GetNamespace(), resource.GetName(), request.UID, request.Operation) resource.GetKind(), resource.GetNamespace(), resource.GetName(), request.UID, request.Operation)
// TODO: this can be // TODO: this can be
engineResponse := engine.Mutate(*policy, *resource) engineResponse := engine.Mutate(policyContext)
engineResponses = append(engineResponses, engineResponse) engineResponses = append(engineResponses, engineResponse)
// Gather policy application statistics // Gather policy application statistics
gatherStat(policy.Name, engineResponse.PolicyResponse) gatherStat(policy.Name, engineResponse.PolicyResponse)

View file

@ -14,7 +14,8 @@ import (
// HandleValidation handles validating webhook admission request // HandleValidation handles validating webhook admission request
// If there are no errors in validating rule we apply generation rules // If there are no errors in validating rule we apply generation rules
// patchedResource is the (resource + patches) after applying mutation rules // patchedResource is the (resource + patches) after applying mutation rules
func (ws *WebhookServer) HandleValidation(request *v1beta1.AdmissionRequest, policies []*v1alpha1.ClusterPolicy, patchedResource []byte) (bool, string) { func (ws *WebhookServer) HandleValidation(request *v1beta1.AdmissionRequest,
policies []*v1alpha1.ClusterPolicy, patchedResource []byte, roles, clusterRoles []string) (bool, string) {
glog.V(4).Infof("Receive request in validating webhook: Kind=%s, Namespace=%s Name=%s UID=%s patchOperation=%s", glog.V(4).Infof("Receive request in validating webhook: Kind=%s, Namespace=%s Name=%s UID=%s patchOperation=%s",
request.Kind.Kind, request.Namespace, request.Name, request.UID, request.Operation) request.Kind.Kind, request.Namespace, request.Name, request.UID, request.Operation)
@ -71,9 +72,17 @@ func (ws *WebhookServer) HandleValidation(request *v1beta1.AdmissionRequest, pol
// resource namespace is empty for the first CREATE operation // resource namespace is empty for the first CREATE operation
resource.SetNamespace(request.Namespace) resource.SetNamespace(request.Namespace)
policyContext := engine.PolicyContext{
Resource: *resource,
AdmissionInfo: engine.RequestInfo{
Roles: roles,
ClusterRoles: clusterRoles,
AdmissionUserInfo: request.UserInfo},
}
var engineResponses []engine.EngineResponse var engineResponses []engine.EngineResponse
for _, policy := range policies { for _, policy := range policies {
policyContext.Policy = *policy
if !utils.ContainsString(getApplicableKindsForPolicy(policy), request.Kind.Kind) { if !utils.ContainsString(getApplicableKindsForPolicy(policy), request.Kind.Kind) {
continue continue
} }
@ -81,7 +90,7 @@ func (ws *WebhookServer) HandleValidation(request *v1beta1.AdmissionRequest, pol
glog.V(2).Infof("Handling validation for Kind=%s, Namespace=%s Name=%s UID=%s patchOperation=%s", glog.V(2).Infof("Handling validation for Kind=%s, Namespace=%s Name=%s UID=%s patchOperation=%s",
resource.GetKind(), resource.GetNamespace(), resource.GetName(), request.UID, request.Operation) resource.GetKind(), resource.GetNamespace(), resource.GetName(), request.UID, request.Operation)
engineResponse := engine.Validate(*policy, *resource) engineResponse := engine.Validate(policyContext)
engineResponses = append(engineResponses, engineResponse) engineResponses = append(engineResponses, engineResponse)
// Gather policy application statistics // Gather policy application statistics
gatherStat(policy.Name, engineResponse.PolicyResponse) gatherStat(policy.Name, engineResponse.PolicyResponse)