mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-09 20:17:41 +00:00
make ValidatingAdmissionPolicy ignore excluded resources.
This commit is contained in:
parent
5b1fffa3e4
commit
64ee859aa8
@ -26,6 +26,7 @@ import (
|
|||||||
"k8s.io/apiserver/pkg/admission"
|
"k8s.io/apiserver/pkg/admission"
|
||||||
"k8s.io/apiserver/pkg/admission/initializer"
|
"k8s.io/apiserver/pkg/admission/initializer"
|
||||||
"k8s.io/apiserver/pkg/admission/plugin/policy/matching"
|
"k8s.io/apiserver/pkg/admission/plugin/policy/matching"
|
||||||
|
"k8s.io/apiserver/pkg/admission/resourcefilter"
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||||
"k8s.io/client-go/dynamic"
|
"k8s.io/client-go/dynamic"
|
||||||
"k8s.io/client-go/informers"
|
"k8s.io/client-go/informers"
|
||||||
@ -52,6 +53,7 @@ type Plugin[H any] struct {
|
|||||||
client kubernetes.Interface
|
client kubernetes.Interface
|
||||||
restMapper meta.RESTMapper
|
restMapper meta.RESTMapper
|
||||||
dynamicClient dynamic.Interface
|
dynamicClient dynamic.Interface
|
||||||
|
resourceFilter resourcefilter.Interface // optional
|
||||||
stopCh <-chan struct{}
|
stopCh <-chan struct{}
|
||||||
authorizer authorizer.Authorizer
|
authorizer authorizer.Authorizer
|
||||||
enabled bool
|
enabled bool
|
||||||
@ -64,6 +66,7 @@ var (
|
|||||||
_ initializer.WantsDynamicClient = &Plugin[any]{}
|
_ initializer.WantsDynamicClient = &Plugin[any]{}
|
||||||
_ initializer.WantsDrainedNotification = &Plugin[any]{}
|
_ initializer.WantsDrainedNotification = &Plugin[any]{}
|
||||||
_ initializer.WantsAuthorizer = &Plugin[any]{}
|
_ initializer.WantsAuthorizer = &Plugin[any]{}
|
||||||
|
_ initializer.WantsResourceFilter = &Plugin[any]{}
|
||||||
_ admission.InitializationValidator = &Plugin[any]{}
|
_ admission.InitializationValidator = &Plugin[any]{}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -111,6 +114,10 @@ func (c *Plugin[H]) SetEnabled(enabled bool) {
|
|||||||
c.enabled = enabled
|
c.enabled = enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Plugin[H]) SetResourceFilter(filter resourcefilter.Interface) {
|
||||||
|
c.resourceFilter = filter
|
||||||
|
}
|
||||||
|
|
||||||
// ValidateInitialization - once clientset and informer factory are provided, creates and starts the admission controller
|
// ValidateInitialization - once clientset and informer factory are provided, creates and starts the admission controller
|
||||||
func (c *Plugin[H]) ValidateInitialization() error {
|
func (c *Plugin[H]) ValidateInitialization() error {
|
||||||
// By default enabled is set to false. It is up to types which embed this
|
// By default enabled is set to false. It is up to types which embed this
|
||||||
@ -177,7 +184,7 @@ func (c *Plugin[H]) Dispatch(
|
|||||||
) (err error) {
|
) (err error) {
|
||||||
if !c.enabled {
|
if !c.enabled {
|
||||||
return nil
|
return nil
|
||||||
} else if isPolicyResource(a) {
|
} else if isPolicyResource(a) || (c.resourceFilter != nil && !c.resourceFilter.ShouldHandle(a)) {
|
||||||
return nil
|
return nil
|
||||||
} else if !c.WaitForReady() {
|
} else if !c.WaitForReady() {
|
||||||
return admission.NewForbidden(a, fmt.Errorf("not yet ready to handle request"))
|
return admission.NewForbidden(a, fmt.Errorf("not yet ready to handle request"))
|
||||||
|
@ -74,6 +74,7 @@ type Plugin struct {
|
|||||||
var _ admission.Interface = &Plugin{}
|
var _ admission.Interface = &Plugin{}
|
||||||
var _ admission.ValidationInterface = &Plugin{}
|
var _ admission.ValidationInterface = &Plugin{}
|
||||||
var _ initializer.WantsFeatures = &Plugin{}
|
var _ initializer.WantsFeatures = &Plugin{}
|
||||||
|
var _ initializer.WantsResourceFilter = &Plugin{}
|
||||||
|
|
||||||
func NewPlugin(_ io.Reader) *Plugin {
|
func NewPlugin(_ io.Reader) *Plugin {
|
||||||
handler := admission.NewHandler(admission.Connect, admission.Create, admission.Delete, admission.Update)
|
handler := admission.NewHandler(admission.Connect, admission.Create, admission.Delete, admission.Update)
|
||||||
|
@ -80,7 +80,6 @@ func (v *validator) Validate(ctx context.Context, matchedResource schema.GroupVe
|
|||||||
} else {
|
} else {
|
||||||
f = *v.failPolicy
|
f = *v.failPolicy
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.celMatcher != nil {
|
if v.celMatcher != nil {
|
||||||
matchResults := v.celMatcher.Match(ctx, versionedAttr, versionedParams, authz)
|
matchResults := v.celMatcher.Match(ctx, versionedAttr, versionedParams, authz)
|
||||||
if matchResults.Error != nil {
|
if matchResults.Error != nil {
|
||||||
|
@ -30,6 +30,7 @@ import (
|
|||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
authenticationv1 "k8s.io/api/authentication/v1"
|
||||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||||
apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
||||||
"k8s.io/apiextensions-apiserver/test/integration/fixtures"
|
"k8s.io/apiextensions-apiserver/test/integration/fixtures"
|
||||||
@ -39,6 +40,7 @@ import (
|
|||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
"k8s.io/client-go/rest"
|
"k8s.io/client-go/rest"
|
||||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||||
|
"k8s.io/utils/ptr"
|
||||||
|
|
||||||
"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
|
"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
|
||||||
apiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
|
apiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
|
||||||
@ -1701,6 +1703,71 @@ func Test_ValidatingAdmissionPolicy_MatchWithMatchPolicyExact(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_ValidatingAdmissionPolicy_MatchExcludedResource(t *testing.T) {
|
||||||
|
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, genericfeatures.ValidatingAdmissionPolicy, true)()
|
||||||
|
server, err := apiservertesting.StartTestServer(t, nil, []string{
|
||||||
|
"--enable-admission-plugins", "ValidatingAdmissionPolicy",
|
||||||
|
}, framework.SharedEtcd())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer server.TearDownFn()
|
||||||
|
|
||||||
|
config := server.ClientConfig
|
||||||
|
|
||||||
|
client, err := clientset.NewForConfig(config)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
policy := withValidations([]admissionregistrationv1beta1.Validation{
|
||||||
|
{
|
||||||
|
Expression: "false",
|
||||||
|
Message: "try to deny SelfSubjectReview",
|
||||||
|
},
|
||||||
|
}, withFailurePolicy(admissionregistrationv1beta1.Fail, makePolicy("match-excluded-resources")))
|
||||||
|
policy.Spec.MatchConstraints = &admissionregistrationv1beta1.MatchResources{
|
||||||
|
MatchPolicy: ptr.To(admissionregistrationv1beta1.Exact),
|
||||||
|
ResourceRules: []admissionregistrationv1beta1.NamedRuleWithOperations{
|
||||||
|
{
|
||||||
|
RuleWithOperations: admissionregistrationv1beta1.RuleWithOperations{
|
||||||
|
Operations: []admissionregistrationv1.OperationType{
|
||||||
|
"*",
|
||||||
|
},
|
||||||
|
Rule: admissionregistrationv1.Rule{
|
||||||
|
APIGroups: []string{
|
||||||
|
"authentication.k8s.io",
|
||||||
|
},
|
||||||
|
APIVersions: []string{
|
||||||
|
"v1",
|
||||||
|
},
|
||||||
|
Resources: []string{
|
||||||
|
"selfsubjectreviews",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
policy = withWaitReadyConstraintAndExpression(policy)
|
||||||
|
if _, err := client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(context.Background(), policy, metav1.CreateOptions{}); err != nil {
|
||||||
|
t.Fatalf("fail to create policy: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
policyBinding := makeBinding("match-by-match-policy-exact-binding", "match-excluded-resources", "")
|
||||||
|
if err := createAndWaitReady(t, client, policyBinding, nil); err != nil {
|
||||||
|
t.Fatalf("fail to create and wait for binding: %v", err)
|
||||||
|
}
|
||||||
|
r, err := client.AuthenticationV1().SelfSubjectReviews().Create(context.Background(), &authenticationv1.SelfSubjectReview{}, metav1.CreateOptions{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected denied SelfSubjectReview: %v", err)
|
||||||
|
}
|
||||||
|
// confidence check the returned user info.
|
||||||
|
if len(r.Status.UserInfo.UID) == 0 {
|
||||||
|
t.Errorf("unexpected invalid user info: %v", r.Status.UserInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Test_ValidatingAdmissionPolicy_PolicyDeletedThenRecreated validates that deleting a ValidatingAdmissionPolicy
|
// Test_ValidatingAdmissionPolicy_PolicyDeletedThenRecreated validates that deleting a ValidatingAdmissionPolicy
|
||||||
// removes the policy from the apiserver admission chain and recreating it re-enables it.
|
// removes the policy from the apiserver admission chain and recreating it re-enables it.
|
||||||
func Test_ValidatingAdmissionPolicy_PolicyDeletedThenRecreated(t *testing.T) {
|
func Test_ValidatingAdmissionPolicy_PolicyDeletedThenRecreated(t *testing.T) {
|
||||||
|
Loading…
Reference in New Issue
Block a user