mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-10-31 05:40:42 +00:00 
			
		
		
		
	Modify PodSecurityPolicy admission plugin to additionally allow authorizing via "use" verb in policy API group.
This commit is contained in:
		| @@ -5,7 +5,7 @@ metadata: | ||||
|   name: restricted-psp-user | ||||
| rules: | ||||
| - apiGroups: | ||||
|   - extensions | ||||
|   - policy | ||||
|   resources: | ||||
|   - podsecuritypolicies | ||||
|   resourceNames: | ||||
| @@ -20,7 +20,7 @@ metadata: | ||||
|   name: privileged-psp-user | ||||
| rules: | ||||
| - apiGroups: | ||||
|   - extensions | ||||
|   - policy | ||||
|   resources: | ||||
|   - podsecuritypolicies | ||||
|   resourceNames: | ||||
|   | ||||
| @@ -33,6 +33,7 @@ import ( | ||||
| 	"k8s.io/apiserver/pkg/authorization/authorizer" | ||||
| 	api "k8s.io/kubernetes/pkg/apis/core" | ||||
| 	"k8s.io/kubernetes/pkg/apis/extensions" | ||||
| 	"k8s.io/kubernetes/pkg/apis/policy" | ||||
| 	informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion" | ||||
| 	extensionslisters "k8s.io/kubernetes/pkg/client/listers/extensions/internalversion" | ||||
| 	kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" | ||||
| @@ -354,11 +355,19 @@ func isAuthorizedForPolicy(user, sa user.Info, namespace, policyName string, aut | ||||
| } | ||||
|  | ||||
| // authorizedForPolicy returns true if info is authorized to perform the "use" verb on the policy resource. | ||||
| // TODO: check against only the policy group when PSP will be completely moved out of the extensions | ||||
| func authorizedForPolicy(info user.Info, namespace string, policyName string, authz authorizer.Authorizer) bool { | ||||
| 	// Check against extensions API group for backward compatibility | ||||
| 	return authorizedForPolicyInAPIGroup(info, namespace, policyName, policy.GroupName, authz) || | ||||
| 		authorizedForPolicyInAPIGroup(info, namespace, policyName, extensions.GroupName, authz) | ||||
| } | ||||
|  | ||||
| // authorizedForPolicyInAPIGroup returns true if info is authorized to perform the "use" verb on the policy resource in the specified API group. | ||||
| func authorizedForPolicyInAPIGroup(info user.Info, namespace, policyName, apiGroupName string, authz authorizer.Authorizer) bool { | ||||
| 	if info == nil { | ||||
| 		return false | ||||
| 	} | ||||
| 	attr := buildAttributes(info, namespace, policyName) | ||||
| 	attr := buildAttributes(info, namespace, policyName, apiGroupName) | ||||
| 	decision, reason, err := authz.Authorize(attr) | ||||
| 	if err != nil { | ||||
| 		glog.V(5).Infof("cannot authorize for policy: %v,%v", reason, err) | ||||
| @@ -367,14 +376,14 @@ func authorizedForPolicy(info user.Info, namespace string, policyName string, au | ||||
| } | ||||
|  | ||||
| // buildAttributes builds an attributes record for a SAR based on the user info and policy. | ||||
| func buildAttributes(info user.Info, namespace string, policyName string) authorizer.Attributes { | ||||
| func buildAttributes(info user.Info, namespace, policyName, apiGroupName string) authorizer.Attributes { | ||||
| 	// check against the namespace that the pod is being created in to allow per-namespace PSP grants. | ||||
| 	attr := authorizer.AttributesRecord{ | ||||
| 		User:            info, | ||||
| 		Verb:            "use", | ||||
| 		Namespace:       namespace, | ||||
| 		Name:            policyName, | ||||
| 		APIGroup:        extensions.GroupName, | ||||
| 		APIGroup:        apiGroupName, | ||||
| 		Resource:        "podsecuritypolicies", | ||||
| 		ResourceRequest: true, | ||||
| 	} | ||||
|   | ||||
| @@ -37,6 +37,7 @@ import ( | ||||
| 	kapi "k8s.io/kubernetes/pkg/apis/core" | ||||
| 	"k8s.io/kubernetes/pkg/apis/core/helper" | ||||
| 	"k8s.io/kubernetes/pkg/apis/extensions" | ||||
| 	"k8s.io/kubernetes/pkg/apis/policy" | ||||
| 	informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion" | ||||
| 	"k8s.io/kubernetes/pkg/controller" | ||||
| 	"k8s.io/kubernetes/pkg/security/apparmor" | ||||
| @@ -71,6 +72,11 @@ type TestAuthorizer struct { | ||||
| 	// usernameToNamespaceToAllowedPSPs contains the map of allowed PSPs. | ||||
| 	// if nil, all PSPs are allowed. | ||||
| 	usernameToNamespaceToAllowedPSPs map[string]map[string]map[string]bool | ||||
| 	// allowedAPIGroupName specifies an API Group name that contains PSP resources. | ||||
| 	// In order to be authorized, AttributesRecord must have this group name. | ||||
| 	// When empty, API Group name isn't taken into account. | ||||
| 	// TODO: remove this when PSP will be completely moved out of the extensions and we'll lookup only in "policy" group. | ||||
| 	allowedAPIGroupName string | ||||
| } | ||||
|  | ||||
| func (t *TestAuthorizer) Authorize(a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) { | ||||
| @@ -79,7 +85,8 @@ func (t *TestAuthorizer) Authorize(a authorizer.Attributes) (authorized authoriz | ||||
| 	} | ||||
| 	allowedInNamespace := t.usernameToNamespaceToAllowedPSPs[a.GetUser().GetName()][a.GetNamespace()][a.GetName()] | ||||
| 	allowedClusterWide := t.usernameToNamespaceToAllowedPSPs[a.GetUser().GetName()][""][a.GetName()] | ||||
| 	if allowedInNamespace || allowedClusterWide { | ||||
| 	allowedAPIGroup := len(t.allowedAPIGroupName) == 0 || a.GetAPIGroup() == t.allowedAPIGroupName | ||||
| 	if allowedAPIGroup && (allowedInNamespace || allowedClusterWide) { | ||||
| 		return authorizer.DecisionAllow, "", nil | ||||
| 	} | ||||
| 	return authorizer.DecisionNoOpinion, "", nil | ||||
| @@ -1996,8 +2003,9 @@ func TestPolicyAuthorization(t *testing.T) { | ||||
| 		expectedPolicy string | ||||
| 		inPolicies     []*extensions.PodSecurityPolicy | ||||
| 		allowed        map[string]map[string]map[string]bool | ||||
| 		allowedGroup   string | ||||
| 	}{ | ||||
| 		"policy allowed by user": { | ||||
| 		"policy allowed by user (extensions API Group)": { | ||||
| 			user: &user.DefaultInfo{Name: "user"}, | ||||
| 			sa:   "sa", | ||||
| 			ns:   "test", | ||||
| @@ -2009,7 +2017,7 @@ func TestPolicyAuthorization(t *testing.T) { | ||||
| 			inPolicies:     []*extensions.PodSecurityPolicy{policyWithName("policy")}, | ||||
| 			expectedPolicy: "policy", | ||||
| 		}, | ||||
| 		"policy allowed by sa": { | ||||
| 		"policy allowed by sa (extensions API Group)": { | ||||
| 			user: &user.DefaultInfo{Name: "user"}, | ||||
| 			sa:   "sa", | ||||
| 			ns:   "test", | ||||
| @@ -2021,6 +2029,32 @@ func TestPolicyAuthorization(t *testing.T) { | ||||
| 			inPolicies:     []*extensions.PodSecurityPolicy{policyWithName("policy")}, | ||||
| 			expectedPolicy: "policy", | ||||
| 		}, | ||||
| 		"policy allowed by user (policy API Group)": { | ||||
| 			user: &user.DefaultInfo{Name: "user"}, | ||||
| 			sa:   "sa", | ||||
| 			ns:   "test", | ||||
| 			allowed: map[string]map[string]map[string]bool{ | ||||
| 				"user": { | ||||
| 					"test": {"policy": true}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			inPolicies:     []*extensions.PodSecurityPolicy{policyWithName("policy")}, | ||||
| 			expectedPolicy: "policy", | ||||
| 			allowedGroup:   policy.GroupName, | ||||
| 		}, | ||||
| 		"policy allowed by sa (policy API Group)": { | ||||
| 			user: &user.DefaultInfo{Name: "user"}, | ||||
| 			sa:   "sa", | ||||
| 			ns:   "test", | ||||
| 			allowed: map[string]map[string]map[string]bool{ | ||||
| 				serviceaccount.MakeUsername("test", "sa"): { | ||||
| 					"test": {"policy": true}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			inPolicies:     []*extensions.PodSecurityPolicy{policyWithName("policy")}, | ||||
| 			expectedPolicy: "policy", | ||||
| 			allowedGroup:   policy.GroupName, | ||||
| 		}, | ||||
| 		"no policies allowed": { | ||||
| 			user:           &user.DefaultInfo{Name: "user"}, | ||||
| 			sa:             "sa", | ||||
| @@ -2122,7 +2156,7 @@ func TestPolicyAuthorization(t *testing.T) { | ||||
| 		var ( | ||||
| 			oldPod     *kapi.Pod | ||||
| 			shouldPass = v.expectedPolicy != "" | ||||
| 			authz      = &TestAuthorizer{usernameToNamespaceToAllowedPSPs: v.allowed} | ||||
| 			authz      = &TestAuthorizer{usernameToNamespaceToAllowedPSPs: v.allowed, allowedAPIGroupName: v.allowedGroup} | ||||
| 			canMutate  = true | ||||
| 		) | ||||
| 		pod := goodPod() | ||||
|   | ||||
		Reference in New Issue
	
	Block a user