mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-05 18:24:07 +00:00
bugfix: use matched resource for AdmissionRequest.resource, not the resource it was converted from
use existing admission request for audit annotation eval populate matchResource in empty rules case
This commit is contained in:
parent
5e2e8c8064
commit
e1b0bc3d0a
@ -23,6 +23,7 @@ import (
|
|||||||
|
|
||||||
"github.com/google/cel-go/cel"
|
"github.com/google/cel-go/cel"
|
||||||
|
|
||||||
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apiserver/pkg/admission"
|
"k8s.io/apiserver/pkg/admission"
|
||||||
celconfig "k8s.io/apiserver/pkg/apis/cel"
|
celconfig "k8s.io/apiserver/pkg/apis/cel"
|
||||||
"k8s.io/apiserver/pkg/cel/environment"
|
"k8s.io/apiserver/pkg/cel/environment"
|
||||||
@ -141,7 +142,7 @@ func TestCompositedPolicies(t *testing.T) {
|
|||||||
if costBudget == 0 {
|
if costBudget == 0 {
|
||||||
costBudget = celconfig.RuntimeCELCostBudget
|
costBudget = celconfig.RuntimeCELCostBudget
|
||||||
}
|
}
|
||||||
result, _, err := f.ForInput(context.Background(), versionedAttr, CreateAdmissionRequest(versionedAttr.Attributes), optionalVars, nil, costBudget)
|
result, _, err := f.ForInput(context.Background(), versionedAttr, CreateAdmissionRequest(versionedAttr.Attributes, v1.GroupVersionResource(tc.attributes.GetResource()), v1.GroupVersionKind(versionedAttr.VersionedKind)), optionalVars, nil, costBudget)
|
||||||
if !tc.expectErr && err != nil {
|
if !tc.expectErr && err != nil {
|
||||||
t.Fatalf("failed evaluation: %v", err)
|
t.Fatalf("failed evaluation: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -253,10 +253,13 @@ func (f *filter) ForInput(ctx context.Context, versionedAttr *admission.Versione
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: to reuse https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/request/admissionreview.go#L154
|
// TODO: to reuse https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/request/admissionreview.go#L154
|
||||||
func CreateAdmissionRequest(attr admission.Attributes) *admissionv1.AdmissionRequest {
|
func CreateAdmissionRequest(attr admission.Attributes, equivalentGVR metav1.GroupVersionResource, equivalentKind metav1.GroupVersionKind) *admissionv1.AdmissionRequest {
|
||||||
// FIXME: how to get resource GVK, GVR and subresource?
|
// Attempting to use same logic as webhook for constructing resource
|
||||||
gvk := attr.GetKind()
|
// GVK, GVR, subresource
|
||||||
gvr := attr.GetResource()
|
// Use the GVK, GVR that the matcher decided was equivalent to that of the request
|
||||||
|
// https://github.com/kubernetes/kubernetes/blob/90c362b3430bcbbf8f245fadbcd521dab39f1d7c/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/generic/webhook.go#L182-L210
|
||||||
|
gvk := equivalentKind
|
||||||
|
gvr := equivalentGVR
|
||||||
subresource := attr.GetSubresource()
|
subresource := attr.GetSubresource()
|
||||||
|
|
||||||
requestGVK := attr.GetKind()
|
requestGVK := attr.GetKind()
|
||||||
|
@ -787,7 +787,7 @@ func TestFilter(t *testing.T) {
|
|||||||
|
|
||||||
optionalVars := OptionalVariableBindings{VersionedParams: tc.params, Authorizer: tc.authorizer}
|
optionalVars := OptionalVariableBindings{VersionedParams: tc.params, Authorizer: tc.authorizer}
|
||||||
ctx := context.TODO()
|
ctx := context.TODO()
|
||||||
evalResults, _, err := f.ForInput(ctx, versionedAttr, CreateAdmissionRequest(versionedAttr.Attributes), optionalVars, CreateNamespaceObject(tc.namespaceObject), celconfig.RuntimeCELCostBudget)
|
evalResults, _, err := f.ForInput(ctx, versionedAttr, CreateAdmissionRequest(versionedAttr.Attributes, metav1.GroupVersionResource(versionedAttr.GetResource()), metav1.GroupVersionKind(versionedAttr.VersionedKind)), optionalVars, CreateNamespaceObject(tc.namespaceObject), celconfig.RuntimeCELCostBudget)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@ -933,7 +933,7 @@ func TestRuntimeCELCostBudget(t *testing.T) {
|
|||||||
}
|
}
|
||||||
optionalVars := OptionalVariableBindings{VersionedParams: tc.params, Authorizer: tc.authorizer}
|
optionalVars := OptionalVariableBindings{VersionedParams: tc.params, Authorizer: tc.authorizer}
|
||||||
ctx := context.TODO()
|
ctx := context.TODO()
|
||||||
evalResults, remaining, err := f.ForInput(ctx, versionedAttr, CreateAdmissionRequest(versionedAttr.Attributes), optionalVars, nil, tc.testRuntimeCELCostBudget)
|
evalResults, remaining, err := f.ForInput(ctx, versionedAttr, CreateAdmissionRequest(versionedAttr.Attributes, metav1.GroupVersionResource(versionedAttr.GetResource()), metav1.GroupVersionKind(versionedAttr.VersionedKind)), optionalVars, nil, tc.testRuntimeCELCostBudget)
|
||||||
if tc.exceedBudget && err == nil {
|
if tc.exceedBudget && err == nil {
|
||||||
t.Errorf("Expected RuntimeCELCostBudge to be exceeded but got nil")
|
t.Errorf("Expected RuntimeCELCostBudge to be exceeded but got nil")
|
||||||
}
|
}
|
||||||
|
@ -318,10 +318,10 @@ var _ Validator = &fakeValidator{}
|
|||||||
|
|
||||||
type fakeValidator struct {
|
type fakeValidator struct {
|
||||||
validationFilter, auditAnnotationFilter, messageFilter *fakeFilter
|
validationFilter, auditAnnotationFilter, messageFilter *fakeFilter
|
||||||
ValidateFunc func(ctx context.Context, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult
|
ValidateFunc func(ctx context.Context, matchResource schema.GroupVersionResource, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fakeValidator) RegisterDefinition(definition *v1beta1.ValidatingAdmissionPolicy, validateFunc func(ctx context.Context, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult) {
|
func (f *fakeValidator) RegisterDefinition(definition *v1beta1.ValidatingAdmissionPolicy, validateFunc func(ctx context.Context, matchResource schema.GroupVersionResource, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult) {
|
||||||
//Key must be something that we can decipher from the inputs to Validate so using message which will be on the validationCondition object of evalResult
|
//Key must be something that we can decipher from the inputs to Validate so using message which will be on the validationCondition object of evalResult
|
||||||
var key string
|
var key string
|
||||||
if len(definition.Spec.Validations) > 0 {
|
if len(definition.Spec.Validations) > 0 {
|
||||||
@ -338,8 +338,8 @@ func (f *fakeValidator) RegisterDefinition(definition *v1beta1.ValidatingAdmissi
|
|||||||
validatorMap[key] = f
|
validatorMap[key] = f
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fakeValidator) Validate(ctx context.Context, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
func (f *fakeValidator) Validate(ctx context.Context, matchResource schema.GroupVersionResource, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
||||||
return f.ValidateFunc(ctx, versionedAttr, versionedParams, namespace, runtimeCELCostBudget, authz)
|
return f.ValidateFunc(ctx, matchResource, versionedAttr, versionedParams, namespace, runtimeCELCostBudget, authz)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Matcher = &fakeMatcher{}
|
var _ Matcher = &fakeMatcher{}
|
||||||
@ -390,18 +390,18 @@ func (f *fakeMatcher) RegisterBinding(binding *v1beta1.ValidatingAdmissionPolicy
|
|||||||
|
|
||||||
// Matches says whether this policy definition matches the provided admission
|
// Matches says whether this policy definition matches the provided admission
|
||||||
// resource request
|
// resource request
|
||||||
func (f *fakeMatcher) DefinitionMatches(a admission.Attributes, o admission.ObjectInterfaces, definition *v1beta1.ValidatingAdmissionPolicy) (bool, schema.GroupVersionKind, error) {
|
func (f *fakeMatcher) DefinitionMatches(a admission.Attributes, o admission.ObjectInterfaces, definition *v1beta1.ValidatingAdmissionPolicy) (bool, schema.GroupVersionResource, schema.GroupVersionKind, error) {
|
||||||
namespace, name := definition.Namespace, definition.Name
|
namespace, name := definition.Namespace, definition.Name
|
||||||
key := namespacedName{
|
key := namespacedName{
|
||||||
name: name,
|
name: name,
|
||||||
namespace: namespace,
|
namespace: namespace,
|
||||||
}
|
}
|
||||||
if fun, ok := f.DefinitionMatchFuncs[key]; ok {
|
if fun, ok := f.DefinitionMatchFuncs[key]; ok {
|
||||||
return fun(definition, a), a.GetKind(), nil
|
return fun(definition, a), a.GetResource(), a.GetKind(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default is match everything
|
// Default is match everything
|
||||||
return f.DefaultMatch, a.GetKind(), nil
|
return f.DefaultMatch, a.GetResource(), a.GetKind(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Matches says whether this policy definition matches the provided admission
|
// Matches says whether this policy definition matches the provided admission
|
||||||
@ -834,7 +834,7 @@ func TestBasicPolicyDefinitionFailure(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
validator.RegisterDefinition(denyPolicy, func(ctx context.Context, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
validator.RegisterDefinition(denyPolicy, func(ctx context.Context, matchedResource schema.GroupVersionResource, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
||||||
return ValidateResult{
|
return ValidateResult{
|
||||||
Decisions: []PolicyDecision{
|
Decisions: []PolicyDecision{
|
||||||
{
|
{
|
||||||
@ -904,7 +904,7 @@ func TestDefinitionDoesntMatch(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
validator.RegisterDefinition(denyPolicy, func(ctx context.Context, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
validator.RegisterDefinition(denyPolicy, func(ctx context.Context, matchedResource schema.GroupVersionResource, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
||||||
return ValidateResult{
|
return ValidateResult{
|
||||||
Decisions: []PolicyDecision{
|
Decisions: []PolicyDecision{
|
||||||
{
|
{
|
||||||
@ -1019,7 +1019,7 @@ func TestReconfigureBinding(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
validator.RegisterDefinition(denyPolicy, func(ctx context.Context, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
validator.RegisterDefinition(denyPolicy, func(ctx context.Context, matchedResource schema.GroupVersionResource, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
||||||
return ValidateResult{
|
return ValidateResult{
|
||||||
Decisions: []PolicyDecision{
|
Decisions: []PolicyDecision{
|
||||||
{
|
{
|
||||||
@ -1130,7 +1130,7 @@ func TestRemoveDefinition(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
validator.RegisterDefinition(denyPolicy, func(ctx context.Context, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
validator.RegisterDefinition(denyPolicy, func(ctx context.Context, matchedResource schema.GroupVersionResource, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
||||||
return ValidateResult{
|
return ValidateResult{
|
||||||
Decisions: []PolicyDecision{
|
Decisions: []PolicyDecision{
|
||||||
{
|
{
|
||||||
@ -1199,7 +1199,7 @@ func TestRemoveBinding(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
validator.RegisterDefinition(denyPolicy, func(ctx context.Context, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
validator.RegisterDefinition(denyPolicy, func(ctx context.Context, matchedResource schema.GroupVersionResource, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
||||||
return ValidateResult{
|
return ValidateResult{
|
||||||
Decisions: []PolicyDecision{
|
Decisions: []PolicyDecision{
|
||||||
{
|
{
|
||||||
@ -1309,7 +1309,7 @@ func TestInvalidParamSourceInstanceName(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
validator.RegisterDefinition(denyPolicy, func(ctx context.Context, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
validator.RegisterDefinition(denyPolicy, func(ctx context.Context, matchedResource schema.GroupVersionResource, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
||||||
return ValidateResult{
|
return ValidateResult{
|
||||||
Decisions: []PolicyDecision{
|
Decisions: []PolicyDecision{
|
||||||
{
|
{
|
||||||
@ -1370,7 +1370,7 @@ func TestEmptyParamRef(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
validator.RegisterDefinition(denyPolicy, func(ctx context.Context, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
validator.RegisterDefinition(denyPolicy, func(ctx context.Context, matchedResource schema.GroupVersionResource, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
||||||
// Versioned params must be nil to pass the test
|
// Versioned params must be nil to pass the test
|
||||||
if versionedParams != nil {
|
if versionedParams != nil {
|
||||||
return ValidateResult{
|
return ValidateResult{
|
||||||
@ -1447,7 +1447,7 @@ func TestEmptyParamSource(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
validator.RegisterDefinition(denyPolicy, func(ctx context.Context, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
validator.RegisterDefinition(denyPolicy, func(ctx context.Context, matchedResource schema.GroupVersionResource, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
||||||
return ValidateResult{
|
return ValidateResult{
|
||||||
Decisions: []PolicyDecision{
|
Decisions: []PolicyDecision{
|
||||||
{
|
{
|
||||||
@ -1549,7 +1549,7 @@ func TestMultiplePoliciesSharedParamType(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
validator1.RegisterDefinition(&policy1, func(ctx context.Context, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
validator1.RegisterDefinition(&policy1, func(ctx context.Context, matchedResource schema.GroupVersionResource, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
||||||
evaluations1.Add(1)
|
evaluations1.Add(1)
|
||||||
return ValidateResult{
|
return ValidateResult{
|
||||||
Decisions: []PolicyDecision{
|
Decisions: []PolicyDecision{
|
||||||
@ -1568,7 +1568,7 @@ func TestMultiplePoliciesSharedParamType(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
validator2.RegisterDefinition(&policy2, func(ctx context.Context, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
validator2.RegisterDefinition(&policy2, func(ctx context.Context, matchedResource schema.GroupVersionResource, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
||||||
evaluations2.Add(1)
|
evaluations2.Add(1)
|
||||||
return ValidateResult{
|
return ValidateResult{
|
||||||
Decisions: []PolicyDecision{
|
Decisions: []PolicyDecision{
|
||||||
@ -1678,7 +1678,7 @@ func TestNativeTypeParam(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
validator.RegisterDefinition(&nativeTypeParamPolicy, func(ctx context.Context, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
validator.RegisterDefinition(&nativeTypeParamPolicy, func(ctx context.Context, matchedResource schema.GroupVersionResource, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
||||||
evaluations.Add(1)
|
evaluations.Add(1)
|
||||||
if _, ok := versionedParams.(*v1.ConfigMap); ok {
|
if _, ok := versionedParams.(*v1.ConfigMap); ok {
|
||||||
return ValidateResult{
|
return ValidateResult{
|
||||||
@ -1760,7 +1760,7 @@ func TestAuditValidationAction(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
validator.RegisterDefinition(denyPolicy, func(ctx context.Context, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
validator.RegisterDefinition(denyPolicy, func(ctx context.Context, matchedResource schema.GroupVersionResource, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
||||||
return ValidateResult{
|
return ValidateResult{
|
||||||
Decisions: []PolicyDecision{
|
Decisions: []PolicyDecision{
|
||||||
{
|
{
|
||||||
@ -1831,7 +1831,7 @@ func TestWarnValidationAction(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
validator.RegisterDefinition(denyPolicy, func(ctx context.Context, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
validator.RegisterDefinition(denyPolicy, func(ctx context.Context, matchedResource schema.GroupVersionResource, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
||||||
return ValidateResult{
|
return ValidateResult{
|
||||||
Decisions: []PolicyDecision{
|
Decisions: []PolicyDecision{
|
||||||
{
|
{
|
||||||
@ -1890,7 +1890,7 @@ func TestAllValidationActions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
validator.RegisterDefinition(denyPolicy, func(ctx context.Context, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
validator.RegisterDefinition(denyPolicy, func(ctx context.Context, matchedResource schema.GroupVersionResource, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
||||||
return ValidateResult{
|
return ValidateResult{
|
||||||
Decisions: []PolicyDecision{
|
Decisions: []PolicyDecision{
|
||||||
{
|
{
|
||||||
@ -1977,7 +1977,7 @@ func TestNamespaceParamRefName(t *testing.T) {
|
|||||||
|
|
||||||
lock := sync.Mutex{}
|
lock := sync.Mutex{}
|
||||||
observedParamNamespaces := []string{}
|
observedParamNamespaces := []string{}
|
||||||
validator.RegisterDefinition(&nativeTypeParamPolicy, func(ctx context.Context, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
validator.RegisterDefinition(&nativeTypeParamPolicy, func(ctx context.Context, matchedResource schema.GroupVersionResource, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
||||||
lock.Lock()
|
lock.Lock()
|
||||||
defer lock.Unlock()
|
defer lock.Unlock()
|
||||||
|
|
||||||
@ -2264,7 +2264,7 @@ func testParamRefCase(t *testing.T, paramIsClusterScoped, nameIsSet, namespaceIs
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
validator.RegisterDefinition(&policy, func(ctx context.Context, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
validator.RegisterDefinition(&policy, func(ctx context.Context, matchedResource schema.GroupVersionResource, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
||||||
observeParam(versionedParams)
|
observeParam(versionedParams)
|
||||||
return ValidateResult{
|
return ValidateResult{
|
||||||
Decisions: []PolicyDecision{
|
Decisions: []PolicyDecision{
|
||||||
@ -2505,7 +2505,7 @@ func TestNamespaceParamRefClusterScopedParamError(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
validator.RegisterDefinition(&nativeTypeParamPolicy, func(ctx context.Context, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
validator.RegisterDefinition(&nativeTypeParamPolicy, func(ctx context.Context, matchedResource schema.GroupVersionResource, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
||||||
evaluations.Add(1)
|
evaluations.Add(1)
|
||||||
if _, ok := versionedParams.(*v1beta1.ValidatingAdmissionPolicy); ok {
|
if _, ok := versionedParams.(*v1beta1.ValidatingAdmissionPolicy); ok {
|
||||||
return ValidateResult{
|
return ValidateResult{
|
||||||
@ -2570,7 +2570,7 @@ func TestAuditAnnotations(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
validator.RegisterDefinition(denyPolicy, func(ctx context.Context, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
validator.RegisterDefinition(denyPolicy, func(ctx context.Context, matchedResource schema.GroupVersionResource, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
||||||
o, err := meta.Accessor(versionedParams)
|
o, err := meta.Accessor(versionedParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
@ -244,7 +244,7 @@ func (c *celAdmissionController) Validate(
|
|||||||
var versionedAttr *admission.VersionedAttributes
|
var versionedAttr *admission.VersionedAttributes
|
||||||
|
|
||||||
definition := definitionInfo.lastReconciledValue
|
definition := definitionInfo.lastReconciledValue
|
||||||
matches, matchKind, err := c.policyController.matcher.DefinitionMatches(a, o, definition)
|
matches, matchResource, matchKind, err := c.policyController.matcher.DefinitionMatches(a, o, definition)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Configuration error.
|
// Configuration error.
|
||||||
addConfigError(err, definition, nil)
|
addConfigError(err, definition, nil)
|
||||||
@ -323,7 +323,7 @@ func (c *celAdmissionController) Validate(
|
|||||||
nested: param,
|
nested: param,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
validationResults = append(validationResults, bindingInfo.validator.Validate(ctx, versionedAttr, p, namespace, celconfig.RuntimeCELCostBudget, authz))
|
validationResults = append(validationResults, bindingInfo.validator.Validate(ctx, matchResource, versionedAttr, p, namespace, celconfig.RuntimeCELCostBudget, authz))
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, validationResult := range validationResults {
|
for _, validationResult := range validationResults {
|
||||||
|
@ -86,7 +86,7 @@ type Matcher interface {
|
|||||||
|
|
||||||
// DefinitionMatches says whether this policy definition matches the provided admission
|
// DefinitionMatches says whether this policy definition matches the provided admission
|
||||||
// resource request
|
// resource request
|
||||||
DefinitionMatches(a admission.Attributes, o admission.ObjectInterfaces, definition *v1beta1.ValidatingAdmissionPolicy) (bool, schema.GroupVersionKind, error)
|
DefinitionMatches(a admission.Attributes, o admission.ObjectInterfaces, definition *v1beta1.ValidatingAdmissionPolicy) (bool, schema.GroupVersionResource, schema.GroupVersionKind, error)
|
||||||
|
|
||||||
// BindingMatches says whether this policy definition matches the provided admission
|
// BindingMatches says whether this policy definition matches the provided admission
|
||||||
// resource request
|
// resource request
|
||||||
@ -109,5 +109,5 @@ type ValidateResult struct {
|
|||||||
type Validator interface {
|
type Validator interface {
|
||||||
// Validate is used to take cel evaluations and convert into decisions
|
// Validate is used to take cel evaluations and convert into decisions
|
||||||
// runtimeCELCostBudget was added for testing purpose only. Callers should always use const RuntimeCELCostBudget from k8s.io/apiserver/pkg/apis/cel/config.go as input.
|
// runtimeCELCostBudget was added for testing purpose only. Callers should always use const RuntimeCELCostBudget from k8s.io/apiserver/pkg/apis/cel/config.go as input.
|
||||||
Validate(ctx context.Context, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *corev1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult
|
Validate(ctx context.Context, matchedResource schema.GroupVersionResource, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *corev1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ func (c *matcher) ValidateInitialization() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DefinitionMatches returns whether this ValidatingAdmissionPolicy matches the provided admission resource request
|
// DefinitionMatches returns whether this ValidatingAdmissionPolicy matches the provided admission resource request
|
||||||
func (c *matcher) DefinitionMatches(a admission.Attributes, o admission.ObjectInterfaces, definition *v1beta1.ValidatingAdmissionPolicy) (bool, schema.GroupVersionKind, error) {
|
func (c *matcher) DefinitionMatches(a admission.Attributes, o admission.ObjectInterfaces, definition *v1beta1.ValidatingAdmissionPolicy) (bool, schema.GroupVersionResource, schema.GroupVersionKind, error) {
|
||||||
criteria := matchCriteria{constraints: definition.Spec.MatchConstraints}
|
criteria := matchCriteria{constraints: definition.Spec.MatchConstraints}
|
||||||
return c.Matcher.Matches(a, o, &criteria)
|
return c.Matcher.Matches(a, o, &criteria)
|
||||||
}
|
}
|
||||||
@ -74,7 +74,7 @@ func (c *matcher) BindingMatches(a admission.Attributes, o admission.ObjectInter
|
|||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
criteria := matchCriteria{constraints: binding.Spec.MatchResources}
|
criteria := matchCriteria{constraints: binding.Spec.MatchResources}
|
||||||
isMatch, _, err := c.Matcher.Matches(a, o, &criteria)
|
isMatch, _, _, err := c.Matcher.Matches(a, o, &criteria)
|
||||||
return isMatch, err
|
return isMatch, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,56 +71,60 @@ func (m *Matcher) ValidateInitialization() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Matcher) Matches(attr admission.Attributes, o admission.ObjectInterfaces, criteria MatchCriteria) (bool, schema.GroupVersionKind, error) {
|
func (m *Matcher) Matches(attr admission.Attributes, o admission.ObjectInterfaces, criteria MatchCriteria) (bool, schema.GroupVersionResource, schema.GroupVersionKind, error) {
|
||||||
matches, matchNsErr := m.namespaceMatcher.MatchNamespaceSelector(criteria, attr)
|
matches, matchNsErr := m.namespaceMatcher.MatchNamespaceSelector(criteria, attr)
|
||||||
// Should not return an error here for policy which do not apply to the request, even if err is an unexpected scenario.
|
// Should not return an error here for policy which do not apply to the request, even if err is an unexpected scenario.
|
||||||
if !matches && matchNsErr == nil {
|
if !matches && matchNsErr == nil {
|
||||||
return false, schema.GroupVersionKind{}, nil
|
return false, schema.GroupVersionResource{}, schema.GroupVersionKind{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
matches, matchObjErr := m.objectMatcher.MatchObjectSelector(criteria, attr)
|
matches, matchObjErr := m.objectMatcher.MatchObjectSelector(criteria, attr)
|
||||||
// Should not return an error here for policy which do not apply to the request, even if err is an unexpected scenario.
|
// Should not return an error here for policy which do not apply to the request, even if err is an unexpected scenario.
|
||||||
if !matches && matchObjErr == nil {
|
if !matches && matchObjErr == nil {
|
||||||
return false, schema.GroupVersionKind{}, nil
|
return false, schema.GroupVersionResource{}, schema.GroupVersionKind{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
matchResources := criteria.GetMatchResources()
|
matchResources := criteria.GetMatchResources()
|
||||||
matchPolicy := matchResources.MatchPolicy
|
matchPolicy := matchResources.MatchPolicy
|
||||||
if isExcluded, _, err := matchesResourceRules(matchResources.ExcludeResourceRules, matchPolicy, attr, o); isExcluded || err != nil {
|
if isExcluded, _, _, err := matchesResourceRules(matchResources.ExcludeResourceRules, matchPolicy, attr, o); isExcluded || err != nil {
|
||||||
return false, schema.GroupVersionKind{}, err
|
return false, schema.GroupVersionResource{}, schema.GroupVersionKind{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
isMatch bool
|
isMatch bool
|
||||||
matchKind schema.GroupVersionKind
|
matchResource schema.GroupVersionResource
|
||||||
matchErr error
|
matchKind schema.GroupVersionKind
|
||||||
|
matchErr error
|
||||||
)
|
)
|
||||||
if len(matchResources.ResourceRules) == 0 {
|
if len(matchResources.ResourceRules) == 0 {
|
||||||
isMatch = true
|
isMatch = true
|
||||||
matchKind = attr.GetKind()
|
matchKind = attr.GetKind()
|
||||||
|
matchResource = attr.GetResource()
|
||||||
} else {
|
} else {
|
||||||
isMatch, matchKind, matchErr = matchesResourceRules(matchResources.ResourceRules, matchPolicy, attr, o)
|
isMatch, matchResource, matchKind, matchErr = matchesResourceRules(matchResources.ResourceRules, matchPolicy, attr, o)
|
||||||
}
|
}
|
||||||
if matchErr != nil {
|
if matchErr != nil {
|
||||||
return false, schema.GroupVersionKind{}, matchErr
|
return false, schema.GroupVersionResource{}, schema.GroupVersionKind{}, matchErr
|
||||||
}
|
}
|
||||||
if !isMatch {
|
if !isMatch {
|
||||||
return false, schema.GroupVersionKind{}, nil
|
return false, schema.GroupVersionResource{}, schema.GroupVersionKind{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// now that we know this applies to this request otherwise, if there were selector errors, return them
|
// now that we know this applies to this request otherwise, if there were selector errors, return them
|
||||||
if matchNsErr != nil {
|
if matchNsErr != nil {
|
||||||
return false, schema.GroupVersionKind{}, matchNsErr
|
return false, schema.GroupVersionResource{}, schema.GroupVersionKind{}, matchNsErr
|
||||||
}
|
}
|
||||||
if matchObjErr != nil {
|
if matchObjErr != nil {
|
||||||
return false, schema.GroupVersionKind{}, matchObjErr
|
return false, schema.GroupVersionResource{}, schema.GroupVersionKind{}, matchObjErr
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, matchKind, nil
|
return true, matchResource, matchKind, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func matchesResourceRules(namedRules []v1beta1.NamedRuleWithOperations, matchPolicy *v1beta1.MatchPolicyType, attr admission.Attributes, o admission.ObjectInterfaces) (bool, schema.GroupVersionKind, error) {
|
func matchesResourceRules(namedRules []v1beta1.NamedRuleWithOperations, matchPolicy *v1beta1.MatchPolicyType, attr admission.Attributes, o admission.ObjectInterfaces) (bool, schema.GroupVersionResource, schema.GroupVersionKind, error) {
|
||||||
matchKind := attr.GetKind()
|
matchKind := attr.GetKind()
|
||||||
|
matchResource := attr.GetResource()
|
||||||
|
|
||||||
for _, namedRule := range namedRules {
|
for _, namedRule := range namedRules {
|
||||||
rule := v1.RuleWithOperations(namedRule.RuleWithOperations)
|
rule := v1.RuleWithOperations(namedRule.RuleWithOperations)
|
||||||
ruleMatcher := rules.Matcher{
|
ruleMatcher := rules.Matcher{
|
||||||
@ -132,14 +136,14 @@ func matchesResourceRules(namedRules []v1beta1.NamedRuleWithOperations, matchPol
|
|||||||
}
|
}
|
||||||
// an empty name list always matches
|
// an empty name list always matches
|
||||||
if len(namedRule.ResourceNames) == 0 {
|
if len(namedRule.ResourceNames) == 0 {
|
||||||
return true, matchKind, nil
|
return true, matchResource, matchKind, nil
|
||||||
}
|
}
|
||||||
// TODO: GetName() can return an empty string if the user is relying on
|
// TODO: GetName() can return an empty string if the user is relying on
|
||||||
// the API server to generate the name... figure out what to do for this edge case
|
// the API server to generate the name... figure out what to do for this edge case
|
||||||
name := attr.GetName()
|
name := attr.GetName()
|
||||||
for _, matchedName := range namedRule.ResourceNames {
|
for _, matchedName := range namedRule.ResourceNames {
|
||||||
if name == matchedName {
|
if name == matchedName {
|
||||||
return true, matchKind, nil
|
return true, matchResource, matchKind, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -147,7 +151,7 @@ func matchesResourceRules(namedRules []v1beta1.NamedRuleWithOperations, matchPol
|
|||||||
// if match policy is undefined or exact, don't perform fuzzy matching
|
// if match policy is undefined or exact, don't perform fuzzy matching
|
||||||
// note that defaulting to fuzzy matching is set by the API
|
// note that defaulting to fuzzy matching is set by the API
|
||||||
if matchPolicy == nil || *matchPolicy == v1beta1.Exact {
|
if matchPolicy == nil || *matchPolicy == v1beta1.Exact {
|
||||||
return false, schema.GroupVersionKind{}, nil
|
return false, schema.GroupVersionResource{}, schema.GroupVersionKind{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
attrWithOverride := &attrWithResourceOverride{Attributes: attr}
|
attrWithOverride := &attrWithResourceOverride{Attributes: attr}
|
||||||
@ -169,11 +173,11 @@ func matchesResourceRules(namedRules []v1beta1.NamedRuleWithOperations, matchPol
|
|||||||
}
|
}
|
||||||
matchKind = o.GetEquivalentResourceMapper().KindFor(equivalent, attr.GetSubresource())
|
matchKind = o.GetEquivalentResourceMapper().KindFor(equivalent, attr.GetSubresource())
|
||||||
if matchKind.Empty() {
|
if matchKind.Empty() {
|
||||||
return false, schema.GroupVersionKind{}, fmt.Errorf("unable to convert to %v: unknown kind", equivalent)
|
return false, schema.GroupVersionResource{}, schema.GroupVersionKind{}, fmt.Errorf("unable to convert to %v: unknown kind", equivalent)
|
||||||
}
|
}
|
||||||
// an empty name list always matches
|
// an empty name list always matches
|
||||||
if len(namedRule.ResourceNames) == 0 {
|
if len(namedRule.ResourceNames) == 0 {
|
||||||
return true, matchKind, nil
|
return true, equivalent, matchKind, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: GetName() can return an empty string if the user is relying on
|
// TODO: GetName() can return an empty string if the user is relying on
|
||||||
@ -181,12 +185,12 @@ func matchesResourceRules(namedRules []v1beta1.NamedRuleWithOperations, matchPol
|
|||||||
name := attr.GetName()
|
name := attr.GetName()
|
||||||
for _, matchedName := range namedRule.ResourceNames {
|
for _, matchedName := range namedRule.ResourceNames {
|
||||||
if name == matchedName {
|
if name == matchedName {
|
||||||
return true, matchKind, nil
|
return true, equivalent, matchKind, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false, schema.GroupVersionKind{}, nil
|
return false, schema.GroupVersionResource{}, schema.GroupVersionKind{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type attrWithResourceOverride struct {
|
type attrWithResourceOverride struct {
|
||||||
|
@ -98,9 +98,10 @@ func TestMatcher(t *testing.T) {
|
|||||||
criteria *v1beta1.MatchResources
|
criteria *v1beta1.MatchResources
|
||||||
attrs admission.Attributes
|
attrs admission.Attributes
|
||||||
|
|
||||||
expectMatches bool
|
expectMatches bool
|
||||||
expectMatchKind schema.GroupVersionKind
|
expectMatchKind schema.GroupVersionKind
|
||||||
expectErr string
|
expectMatchResource schema.GroupVersionResource
|
||||||
|
expectErr string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "no rules (just write)",
|
name: "no rules (just write)",
|
||||||
@ -204,9 +205,10 @@ func TestMatcher(t *testing.T) {
|
|||||||
Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes},
|
Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes},
|
||||||
},
|
},
|
||||||
}}},
|
}}},
|
||||||
attrs: admission.NewAttributesRecord(nil, nil, gvk("apps", "v1", "Deployment"), "ns", "name", gvr("apps", "v1", "deployments"), "", admission.Create, &metav1.CreateOptions{}, false, nil),
|
attrs: admission.NewAttributesRecord(nil, nil, gvk("apps", "v1", "Deployment"), "ns", "name", gvr("apps", "v1", "deployments"), "", admission.Create, &metav1.CreateOptions{}, false, nil),
|
||||||
expectMatches: true,
|
expectMatches: true,
|
||||||
expectMatchKind: gvk("extensions", "v1beta1", "Deployment"),
|
expectMatchResource: gvr("extensions", "v1beta1", "deployments"),
|
||||||
|
expectMatchKind: gvk("extensions", "v1beta1", "Deployment"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "specific rules, equivalent match, prefer apps",
|
name: "specific rules, equivalent match, prefer apps",
|
||||||
@ -225,9 +227,10 @@ func TestMatcher(t *testing.T) {
|
|||||||
Rule: v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes},
|
Rule: v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes},
|
||||||
},
|
},
|
||||||
}}},
|
}}},
|
||||||
attrs: admission.NewAttributesRecord(nil, nil, gvk("apps", "v1", "Deployment"), "ns", "name", gvr("apps", "v1", "deployments"), "", admission.Create, &metav1.CreateOptions{}, false, nil),
|
attrs: admission.NewAttributesRecord(nil, nil, gvk("apps", "v1", "Deployment"), "ns", "name", gvr("apps", "v1", "deployments"), "", admission.Create, &metav1.CreateOptions{}, false, nil),
|
||||||
expectMatches: true,
|
expectMatches: true,
|
||||||
expectMatchKind: gvk("apps", "v1beta1", "Deployment"),
|
expectMatchResource: gvr("apps", "v1beta1", "deployments"),
|
||||||
|
expectMatchKind: gvk("apps", "v1beta1", "Deployment"),
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -311,9 +314,10 @@ func TestMatcher(t *testing.T) {
|
|||||||
Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes},
|
Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes},
|
||||||
},
|
},
|
||||||
}}},
|
}}},
|
||||||
attrs: admission.NewAttributesRecord(nil, nil, gvk("autoscaling", "v1", "Scale"), "ns", "name", gvr("apps", "v1", "deployments"), "scale", admission.Create, &metav1.CreateOptions{}, false, nil),
|
attrs: admission.NewAttributesRecord(nil, nil, gvk("autoscaling", "v1", "Scale"), "ns", "name", gvr("apps", "v1", "deployments"), "scale", admission.Create, &metav1.CreateOptions{}, false, nil),
|
||||||
expectMatches: true,
|
expectMatches: true,
|
||||||
expectMatchKind: gvk("extensions", "v1beta1", "Scale"),
|
expectMatchResource: gvr("extensions", "v1beta1", "deployments"),
|
||||||
|
expectMatchKind: gvk("extensions", "v1beta1", "Scale"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "specific rules, subresource equivalent match, prefer apps",
|
name: "specific rules, subresource equivalent match, prefer apps",
|
||||||
@ -332,9 +336,10 @@ func TestMatcher(t *testing.T) {
|
|||||||
Rule: v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes},
|
Rule: v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes},
|
||||||
},
|
},
|
||||||
}}},
|
}}},
|
||||||
attrs: admission.NewAttributesRecord(nil, nil, gvk("autoscaling", "v1", "Scale"), "ns", "name", gvr("apps", "v1", "deployments"), "scale", admission.Create, &metav1.CreateOptions{}, false, nil),
|
attrs: admission.NewAttributesRecord(nil, nil, gvk("autoscaling", "v1", "Scale"), "ns", "name", gvr("apps", "v1", "deployments"), "scale", admission.Create, &metav1.CreateOptions{}, false, nil),
|
||||||
expectMatches: true,
|
expectMatches: true,
|
||||||
expectMatchKind: gvk("apps", "v1beta1", "Scale"),
|
expectMatchResource: gvr("apps", "v1beta1", "deployments"),
|
||||||
|
expectMatchKind: gvk("apps", "v1beta1", "Scale"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "specific rules, prefer exact match and name match",
|
name: "specific rules, prefer exact match and name match",
|
||||||
@ -380,9 +385,10 @@ func TestMatcher(t *testing.T) {
|
|||||||
Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes},
|
Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes},
|
||||||
},
|
},
|
||||||
}}},
|
}}},
|
||||||
attrs: admission.NewAttributesRecord(nil, nil, gvk("autoscaling", "v1", "Scale"), "ns", "name", gvr("extensions", "v1beta1", "deployments"), "scale", admission.Create, &metav1.CreateOptions{}, false, nil),
|
attrs: admission.NewAttributesRecord(nil, nil, gvk("autoscaling", "v1", "Scale"), "ns", "name", gvr("extensions", "v1beta1", "deployments"), "scale", admission.Create, &metav1.CreateOptions{}, false, nil),
|
||||||
expectMatches: true,
|
expectMatches: true,
|
||||||
expectMatchKind: gvk("autoscaling", "v1", "Scale"),
|
expectMatchResource: gvr("apps", "v1", "deployments"),
|
||||||
|
expectMatchKind: gvk("autoscaling", "v1", "Scale"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "specific rules, subresource equivalent match, prefer extensions and name match miss",
|
name: "specific rules, subresource equivalent match, prefer extensions and name match miss",
|
||||||
@ -536,7 +542,7 @@ func TestMatcher(t *testing.T) {
|
|||||||
|
|
||||||
for _, testcase := range testcases {
|
for _, testcase := range testcases {
|
||||||
t.Run(testcase.name, func(t *testing.T) {
|
t.Run(testcase.name, func(t *testing.T) {
|
||||||
matches, matchKind, err := a.Matches(testcase.attrs, interfaces, &fakeCriteria{matchResources: *testcase.criteria})
|
matches, matchResource, matchKind, err := a.Matches(testcase.attrs, interfaces, &fakeCriteria{matchResources: *testcase.criteria})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if len(testcase.expectErr) == 0 {
|
if len(testcase.expectErr) == 0 {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -558,6 +564,22 @@ func TestMatcher(t *testing.T) {
|
|||||||
if matches != testcase.expectMatches {
|
if matches != testcase.expectMatches {
|
||||||
t.Fatalf("expected matches = %v; got %v", testcase.expectMatches, matches)
|
t.Fatalf("expected matches = %v; got %v", testcase.expectMatches, matches)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expectResource := testcase.expectMatchResource
|
||||||
|
if !expectResource.Empty() && !matches {
|
||||||
|
t.Fatalf("expectResource is non-empty, but did not match")
|
||||||
|
} else if expectResource.Empty() {
|
||||||
|
// Test for exact match by default. Tests that expect an equivalent
|
||||||
|
// resource to match should explicitly state so by supplying
|
||||||
|
// expectMatchResource
|
||||||
|
expectResource = testcase.attrs.GetResource()
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches {
|
||||||
|
if matchResource != expectResource {
|
||||||
|
t.Fatalf("expected matchResource %v, got %v", expectResource, matchResource)
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ import (
|
|||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/apiserver/pkg/admission"
|
"k8s.io/apiserver/pkg/admission"
|
||||||
"k8s.io/apiserver/pkg/admission/plugin/cel"
|
"k8s.io/apiserver/pkg/admission/plugin/cel"
|
||||||
"k8s.io/apiserver/pkg/admission/plugin/webhook/matchconditions"
|
"k8s.io/apiserver/pkg/admission/plugin/webhook/matchconditions"
|
||||||
@ -72,7 +73,7 @@ func auditAnnotationEvaluationForError(f v1.FailurePolicyType) PolicyAuditAnnota
|
|||||||
// Validate takes a list of Evaluation and a failure policy and converts them into actionable PolicyDecisions
|
// Validate takes a list of Evaluation and a failure policy and converts them into actionable PolicyDecisions
|
||||||
// runtimeCELCostBudget was added for testing purpose only. Callers should always use const RuntimeCELCostBudget from k8s.io/apiserver/pkg/apis/cel/config.go as input.
|
// runtimeCELCostBudget was added for testing purpose only. Callers should always use const RuntimeCELCostBudget from k8s.io/apiserver/pkg/apis/cel/config.go as input.
|
||||||
|
|
||||||
func (v *validator) Validate(ctx context.Context, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *corev1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
func (v *validator) Validate(ctx context.Context, matchedResource schema.GroupVersionResource, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *corev1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) ValidateResult {
|
||||||
var f v1.FailurePolicyType
|
var f v1.FailurePolicyType
|
||||||
if v.failPolicy == nil {
|
if v.failPolicy == nil {
|
||||||
f = v1.Fail
|
f = v1.Fail
|
||||||
@ -102,7 +103,7 @@ func (v *validator) Validate(ctx context.Context, versionedAttr *admission.Versi
|
|||||||
|
|
||||||
optionalVars := cel.OptionalVariableBindings{VersionedParams: versionedParams, Authorizer: authz}
|
optionalVars := cel.OptionalVariableBindings{VersionedParams: versionedParams, Authorizer: authz}
|
||||||
expressionOptionalVars := cel.OptionalVariableBindings{VersionedParams: versionedParams}
|
expressionOptionalVars := cel.OptionalVariableBindings{VersionedParams: versionedParams}
|
||||||
admissionRequest := cel.CreateAdmissionRequest(versionedAttr.Attributes)
|
admissionRequest := cel.CreateAdmissionRequest(versionedAttr.Attributes, metav1.GroupVersionResource(matchedResource), metav1.GroupVersionKind(versionedAttr.VersionedKind))
|
||||||
// Decide which fields are exposed
|
// Decide which fields are exposed
|
||||||
ns := cel.CreateNamespaceObject(namespace)
|
ns := cel.CreateNamespaceObject(namespace)
|
||||||
evalResults, remainingBudget, err := v.validationFilter.ForInput(ctx, versionedAttr, admissionRequest, optionalVars, ns, runtimeCELCostBudget)
|
evalResults, remainingBudget, err := v.validationFilter.ForInput(ctx, versionedAttr, admissionRequest, optionalVars, ns, runtimeCELCostBudget)
|
||||||
@ -195,7 +196,7 @@ func (v *validator) Validate(ctx context.Context, versionedAttr *admission.Versi
|
|||||||
}
|
}
|
||||||
|
|
||||||
options := cel.OptionalVariableBindings{VersionedParams: versionedParams}
|
options := cel.OptionalVariableBindings{VersionedParams: versionedParams}
|
||||||
auditAnnotationEvalResults, _, err := v.auditAnnotationFilter.ForInput(ctx, versionedAttr, cel.CreateAdmissionRequest(versionedAttr.Attributes), options, namespace, runtimeCELCostBudget)
|
auditAnnotationEvalResults, _, err := v.auditAnnotationFilter.ForInput(ctx, versionedAttr, admissionRequest, options, namespace, runtimeCELCostBudget)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ValidateResult{
|
return ValidateResult{
|
||||||
Decisions: []PolicyDecision{
|
Decisions: []PolicyDecision{
|
||||||
|
@ -893,7 +893,7 @@ func TestValidate(t *testing.T) {
|
|||||||
if tc.costBudget != 0 {
|
if tc.costBudget != 0 {
|
||||||
budget = tc.costBudget
|
budget = tc.costBudget
|
||||||
}
|
}
|
||||||
validateResult := v.Validate(ctx, fakeVersionedAttr, nil, nil, budget, nil)
|
validateResult := v.Validate(ctx, fakeVersionedAttr.GetResource(), fakeVersionedAttr, nil, nil, budget, nil)
|
||||||
|
|
||||||
require.Equal(t, len(validateResult.Decisions), len(tc.policyDecision))
|
require.Equal(t, len(validateResult.Decisions), len(tc.policyDecision))
|
||||||
|
|
||||||
@ -945,7 +945,7 @@ func TestContextCanceled(t *testing.T) {
|
|||||||
}
|
}
|
||||||
ctx, cancel := context.WithCancel(context.TODO())
|
ctx, cancel := context.WithCancel(context.TODO())
|
||||||
cancel()
|
cancel()
|
||||||
validationResult := v.Validate(ctx, fakeVersionedAttr, nil, nil, celconfig.RuntimeCELCostBudget, nil)
|
validationResult := v.Validate(ctx, fakeVersionedAttr.GetResource(), fakeVersionedAttr, nil, nil, celconfig.RuntimeCELCostBudget, nil)
|
||||||
if len(validationResult.Decisions) != 1 || !strings.Contains(validationResult.Decisions[0].Message, "operation interrupted") {
|
if len(validationResult.Decisions) != 1 || !strings.Contains(validationResult.Decisions[0].Message, "operation interrupted") {
|
||||||
t.Errorf("Expected 'operation interrupted' but got %v", validationResult.Decisions)
|
t.Errorf("Expected 'operation interrupted' but got %v", validationResult.Decisions)
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ import (
|
|||||||
celtypes "github.com/google/cel-go/common/types"
|
celtypes "github.com/google/cel-go/common/types"
|
||||||
|
|
||||||
v1 "k8s.io/api/admissionregistration/v1"
|
v1 "k8s.io/api/admissionregistration/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||||
"k8s.io/apiserver/pkg/admission"
|
"k8s.io/apiserver/pkg/admission"
|
||||||
@ -78,7 +79,7 @@ func NewMatcher(filter celplugin.Filter, failPolicy *v1.FailurePolicyType, match
|
|||||||
|
|
||||||
func (m *matcher) Match(ctx context.Context, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, authz authorizer.Authorizer) MatchResult {
|
func (m *matcher) Match(ctx context.Context, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, authz authorizer.Authorizer) MatchResult {
|
||||||
t := time.Now()
|
t := time.Now()
|
||||||
evalResults, _, err := m.filter.ForInput(ctx, versionedAttr, celplugin.CreateAdmissionRequest(versionedAttr.Attributes), celplugin.OptionalVariableBindings{
|
evalResults, _, err := m.filter.ForInput(ctx, versionedAttr, celplugin.CreateAdmissionRequest(versionedAttr.Attributes, metav1.GroupVersionResource(versionedAttr.GetResource()), metav1.GroupVersionKind(versionedAttr.VersionedKind)), celplugin.OptionalVariableBindings{
|
||||||
VersionedParams: versionedParams,
|
VersionedParams: versionedParams,
|
||||||
Authorizer: authz,
|
Authorizer: authz,
|
||||||
}, nil, celconfig.RuntimeCELCostBudgetMatchConditions)
|
}, nil, celconfig.RuntimeCELCostBudgetMatchConditions)
|
||||||
|
Loading…
Reference in New Issue
Block a user