mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-10-31 02:08:13 +00:00 
			
		
		
		
	Include pod namespace in PSP 'use' authorization check
This commit is contained in:
		| @@ -52,7 +52,7 @@ func init() { | |||||||
| } | } | ||||||
|  |  | ||||||
| // PSPMatchFn allows plugging in how PSPs are matched against user information. | // PSPMatchFn allows plugging in how PSPs are matched against user information. | ||||||
| type PSPMatchFn func(lister extensionslisters.PodSecurityPolicyLister, user user.Info, sa user.Info, authz authorizer.Authorizer) ([]*extensions.PodSecurityPolicy, error) | type PSPMatchFn func(lister extensionslisters.PodSecurityPolicyLister, user user.Info, sa user.Info, authz authorizer.Authorizer, namespace string) ([]*extensions.PodSecurityPolicy, error) | ||||||
|  |  | ||||||
| // podSecurityPolicyPlugin holds state for and implements the admission plugin. | // podSecurityPolicyPlugin holds state for and implements the admission plugin. | ||||||
| type podSecurityPolicyPlugin struct { | type podSecurityPolicyPlugin struct { | ||||||
| @@ -130,7 +130,7 @@ func (c *podSecurityPolicyPlugin) Admit(a admission.Attributes) error { | |||||||
| 		saInfo = serviceaccount.UserInfo(a.GetNamespace(), pod.Spec.ServiceAccountName, "") | 		saInfo = serviceaccount.UserInfo(a.GetNamespace(), pod.Spec.ServiceAccountName, "") | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	matchedPolicies, err := c.pspMatcher(c.lister, a.GetUserInfo(), saInfo, c.authz) | 	matchedPolicies, err := c.pspMatcher(c.lister, a.GetUserInfo(), saInfo, c.authz, a.GetNamespace()) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return admission.NewForbidden(a, err) | 		return admission.NewForbidden(a, err) | ||||||
| 	} | 	} | ||||||
| @@ -279,7 +279,7 @@ func (c *podSecurityPolicyPlugin) createProvidersFromPolicies(psps []*extensions | |||||||
| // TODO: this will likely need optimization since the initial implementation will | // TODO: this will likely need optimization since the initial implementation will | ||||||
| // always query for authorization.  Needs scale testing and possibly checking against | // always query for authorization.  Needs scale testing and possibly checking against | ||||||
| // a cache. | // a cache. | ||||||
| func getMatchingPolicies(lister extensionslisters.PodSecurityPolicyLister, user user.Info, sa user.Info, authz authorizer.Authorizer) ([]*extensions.PodSecurityPolicy, error) { | func getMatchingPolicies(lister extensionslisters.PodSecurityPolicyLister, user user.Info, sa user.Info, authz authorizer.Authorizer, namespace string) ([]*extensions.PodSecurityPolicy, error) { | ||||||
| 	matchedPolicies := make([]*extensions.PodSecurityPolicy, 0) | 	matchedPolicies := make([]*extensions.PodSecurityPolicy, 0) | ||||||
|  |  | ||||||
| 	list, err := lister.List(labels.Everything()) | 	list, err := lister.List(labels.Everything()) | ||||||
| @@ -289,7 +289,7 @@ func getMatchingPolicies(lister extensionslisters.PodSecurityPolicyLister, user | |||||||
|  |  | ||||||
| 	for _, constraint := range list { | 	for _, constraint := range list { | ||||||
| 		// if no user info exists then the API is being hit via the unsecured port. In this case authorize the request. | 		// if no user info exists then the API is being hit via the unsecured port. In this case authorize the request. | ||||||
| 		if user == nil || authorizedForPolicy(user, constraint, authz) || authorizedForPolicy(sa, constraint, authz) { | 		if user == nil || authorizedForPolicy(user, namespace, constraint, authz) || authorizedForPolicy(sa, namespace, constraint, authz) { | ||||||
| 			matchedPolicies = append(matchedPolicies, constraint) | 			matchedPolicies = append(matchedPolicies, constraint) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -297,26 +297,26 @@ func getMatchingPolicies(lister extensionslisters.PodSecurityPolicyLister, user | |||||||
| 	return matchedPolicies, nil | 	return matchedPolicies, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| // authorizedForPolicy returns true if info is authorized to perform a "get" on policy. | // authorizedForPolicy returns true if info is authorized to perform the "use" verb on the policy resource. | ||||||
| func authorizedForPolicy(info user.Info, policy *extensions.PodSecurityPolicy, authz authorizer.Authorizer) bool { | func authorizedForPolicy(info user.Info, namespace string, policy *extensions.PodSecurityPolicy, authz authorizer.Authorizer) bool { | ||||||
| 	if info == nil { | 	if info == nil { | ||||||
| 		return false | 		return false | ||||||
| 	} | 	} | ||||||
| 	attr := buildAttributes(info, policy) | 	attr := buildAttributes(info, namespace, policy) | ||||||
| 	allowed, reason, err := authz.Authorize(attr) | 	allowed, reason, err := authz.Authorize(attr) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		glog.V(5).Infof("cannot authorized for policy: %v,%v", reason, err) | 		glog.V(5).Infof("cannot authorize for policy: %v,%v", reason, err) | ||||||
| 	} | 	} | ||||||
| 	return allowed | 	return allowed | ||||||
| } | } | ||||||
|  |  | ||||||
| // buildAttributes builds an attributes record for a SAR based on the user info and policy. | // buildAttributes builds an attributes record for a SAR based on the user info and policy. | ||||||
| func buildAttributes(info user.Info, policy *extensions.PodSecurityPolicy) authorizer.Attributes { | func buildAttributes(info user.Info, namespace string, policy *extensions.PodSecurityPolicy) authorizer.Attributes { | ||||||
| 	// TODO consider checking against the namespace that the pod is being | 	// check against the namespace that the pod is being created in to allow per-namespace PSP grants. | ||||||
| 	// created in to allow per-namespace PSP definitions. |  | ||||||
| 	attr := authorizer.AttributesRecord{ | 	attr := authorizer.AttributesRecord{ | ||||||
| 		User:            info, | 		User:            info, | ||||||
| 		Verb:            "use", | 		Verb:            "use", | ||||||
|  | 		Namespace:       namespace, | ||||||
| 		Name:            policy.Name, | 		Name:            policy.Name, | ||||||
| 		APIGroup:        extensions.GroupName, | 		APIGroup:        extensions.GroupName, | ||||||
| 		Resource:        "podsecuritypolicies", | 		Resource:        "podsecuritypolicies", | ||||||
|   | |||||||
| @@ -57,18 +57,18 @@ func NewTestAdmission(lister extensionslisters.PodSecurityPolicyLister) kadmissi | |||||||
|  |  | ||||||
| // TestAlwaysAllowedAuthorizer is a testing struct for testing that fulfills the authorizer interface. | // TestAlwaysAllowedAuthorizer is a testing struct for testing that fulfills the authorizer interface. | ||||||
| type TestAuthorizer struct { | type TestAuthorizer struct { | ||||||
| 	// disallowed contains names of disallowed policies.  Map is keyed by user.Info.GetName() | 	// usernameToNamespaceToAllowedPSPs contains the map of allowed PSPs. | ||||||
| 	disallowed map[string][]string | 	// if nil, all PSPs are allowed. | ||||||
|  | 	usernameToNamespaceToAllowedPSPs map[string]map[string]map[string]bool | ||||||
| } | } | ||||||
|  |  | ||||||
| func (t *TestAuthorizer) Authorize(a authorizer.Attributes) (authorized bool, reason string, err error) { | func (t *TestAuthorizer) Authorize(a authorizer.Attributes) (authorized bool, reason string, err error) { | ||||||
| 	disallowedForUser, _ := t.disallowed[a.GetUser().GetName()] | 	if t.usernameToNamespaceToAllowedPSPs == nil { | ||||||
| 	for _, name := range disallowedForUser { | 		return true, "", nil | ||||||
| 		if a.GetName() == name { |  | ||||||
| 			return false, "", nil |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 	return true, "", nil | 	allowedInNamespace := t.usernameToNamespaceToAllowedPSPs[a.GetUser().GetName()][a.GetNamespace()][a.GetName()] | ||||||
|  | 	allowedClusterWide := t.usernameToNamespaceToAllowedPSPs[a.GetUser().GetName()][""][a.GetName()] | ||||||
|  | 	return (allowedInNamespace || allowedClusterWide), "", nil | ||||||
| } | } | ||||||
|  |  | ||||||
| var _ authorizer.Authorizer = &TestAuthorizer{} | var _ authorizer.Authorizer = &TestAuthorizer{} | ||||||
| @@ -1546,17 +1546,21 @@ func TestGetMatchingPolicies(t *testing.T) { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	tests := map[string]struct { | 	tests := map[string]struct { | ||||||
| 		user               user.Info | 		user             user.Info | ||||||
| 		sa                 user.Info | 		sa               user.Info | ||||||
| 		expectedPolicies   sets.String | 		ns               string | ||||||
| 		inPolicies         []*extensions.PodSecurityPolicy | 		expectedPolicies sets.String | ||||||
| 		disallowedPolicies map[string][]string | 		inPolicies       []*extensions.PodSecurityPolicy | ||||||
|  | 		allowed          map[string]map[string]map[string]bool | ||||||
| 	}{ | 	}{ | ||||||
| 		"policy allowed by user": { | 		"policy allowed by user": { | ||||||
| 			user: &user.DefaultInfo{Name: "user"}, | 			user: &user.DefaultInfo{Name: "user"}, | ||||||
| 			sa:   &user.DefaultInfo{Name: "sa"}, | 			sa:   &user.DefaultInfo{Name: "sa"}, | ||||||
| 			disallowedPolicies: map[string][]string{ | 			ns:   "test", | ||||||
| 				"sa": {"policy"}, | 			allowed: map[string]map[string]map[string]bool{ | ||||||
|  | 				"user": { | ||||||
|  | 					"test": {"policy": true}, | ||||||
|  | 				}, | ||||||
| 			}, | 			}, | ||||||
| 			inPolicies:       []*extensions.PodSecurityPolicy{policyWithName("policy")}, | 			inPolicies:       []*extensions.PodSecurityPolicy{policyWithName("policy")}, | ||||||
| 			expectedPolicies: sets.NewString("policy"), | 			expectedPolicies: sets.NewString("policy"), | ||||||
| @@ -1564,43 +1568,55 @@ func TestGetMatchingPolicies(t *testing.T) { | |||||||
| 		"policy allowed by sa": { | 		"policy allowed by sa": { | ||||||
| 			user: &user.DefaultInfo{Name: "user"}, | 			user: &user.DefaultInfo{Name: "user"}, | ||||||
| 			sa:   &user.DefaultInfo{Name: "sa"}, | 			sa:   &user.DefaultInfo{Name: "sa"}, | ||||||
| 			disallowedPolicies: map[string][]string{ | 			ns:   "test", | ||||||
| 				"user": {"policy"}, | 			allowed: map[string]map[string]map[string]bool{ | ||||||
|  | 				"sa": { | ||||||
|  | 					"test": {"policy": true}, | ||||||
|  | 				}, | ||||||
| 			}, | 			}, | ||||||
| 			inPolicies:       []*extensions.PodSecurityPolicy{policyWithName("policy")}, | 			inPolicies:       []*extensions.PodSecurityPolicy{policyWithName("policy")}, | ||||||
| 			expectedPolicies: sets.NewString("policy"), | 			expectedPolicies: sets.NewString("policy"), | ||||||
| 		}, | 		}, | ||||||
| 		"no policies allowed": { | 		"no policies allowed": { | ||||||
| 			user: &user.DefaultInfo{Name: "user"}, | 			user:             &user.DefaultInfo{Name: "user"}, | ||||||
| 			sa:   &user.DefaultInfo{Name: "sa"}, | 			sa:               &user.DefaultInfo{Name: "sa"}, | ||||||
| 			disallowedPolicies: map[string][]string{ | 			ns:               "test", | ||||||
| 				"user": {"policy"}, | 			allowed:          map[string]map[string]map[string]bool{}, | ||||||
| 				"sa":   {"policy"}, |  | ||||||
| 			}, |  | ||||||
| 			inPolicies:       []*extensions.PodSecurityPolicy{policyWithName("policy")}, | 			inPolicies:       []*extensions.PodSecurityPolicy{policyWithName("policy")}, | ||||||
| 			expectedPolicies: sets.NewString(), | 			expectedPolicies: sets.NewString(), | ||||||
| 		}, | 		}, | ||||||
| 		"multiple policies allowed": { | 		"multiple policies allowed": { | ||||||
| 			user: &user.DefaultInfo{Name: "user"}, | 			user: &user.DefaultInfo{Name: "user"}, | ||||||
| 			sa:   &user.DefaultInfo{Name: "sa"}, | 			sa:   &user.DefaultInfo{Name: "sa"}, | ||||||
| 			disallowedPolicies: map[string][]string{ | 			ns:   "test", | ||||||
| 				"user": {"policy1", "policy3"}, | 			allowed: map[string]map[string]map[string]bool{ | ||||||
| 				"sa":   {"policy2", "policy3"}, | 				"sa": { | ||||||
|  | 					"test":  {"policy1": true}, | ||||||
|  | 					"":      {"policy4": true}, | ||||||
|  | 					"other": {"policy6": true}, | ||||||
|  | 				}, | ||||||
|  | 				"user": { | ||||||
|  | 					"test":  {"policy2": true}, | ||||||
|  | 					"":      {"policy5": true}, | ||||||
|  | 					"other": {"policy7": true}, | ||||||
|  | 				}, | ||||||
| 			}, | 			}, | ||||||
| 			inPolicies: []*extensions.PodSecurityPolicy{ | 			inPolicies: []*extensions.PodSecurityPolicy{ | ||||||
| 				policyWithName("policy1"), // allowed by sa | 				policyWithName("policy1"), // allowed by sa | ||||||
| 				policyWithName("policy2"), // allowed by user | 				policyWithName("policy2"), // allowed by user | ||||||
| 				policyWithName("policy3"), // not allowed | 				policyWithName("policy3"), // not allowed | ||||||
|  | 				policyWithName("policy4"), // allowed by sa at cluster level | ||||||
|  | 				policyWithName("policy5"), // allowed by user at cluster level | ||||||
|  | 				policyWithName("policy6"), // not allowed in this namespace | ||||||
|  | 				policyWithName("policy7"), // not allowed in this namespace | ||||||
| 			}, | 			}, | ||||||
| 			expectedPolicies: sets.NewString("policy1", "policy2"), | 			expectedPolicies: sets.NewString("policy1", "policy2", "policy4", "policy5"), | ||||||
| 		}, | 		}, | ||||||
| 		"policies are allowed for nil user info": { | 		"policies are allowed for nil user info": { | ||||||
| 			user: nil, | 			user:    nil, | ||||||
| 			sa:   &user.DefaultInfo{Name: "sa"}, | 			sa:      &user.DefaultInfo{Name: "sa"}, | ||||||
| 			disallowedPolicies: map[string][]string{ | 			ns:      "test", | ||||||
| 				"user": {"policy1", "policy3"}, | 			allowed: map[string]map[string]map[string]bool{}, // authorizer not consulted | ||||||
| 				"sa":   {"policy2", "policy3"}, |  | ||||||
| 			}, |  | ||||||
| 			inPolicies: []*extensions.PodSecurityPolicy{ | 			inPolicies: []*extensions.PodSecurityPolicy{ | ||||||
| 				policyWithName("policy1"), | 				policyWithName("policy1"), | ||||||
| 				policyWithName("policy2"), | 				policyWithName("policy2"), | ||||||
| @@ -1613,9 +1629,11 @@ func TestGetMatchingPolicies(t *testing.T) { | |||||||
| 		"policies are not allowed for nil sa info": { | 		"policies are not allowed for nil sa info": { | ||||||
| 			user: &user.DefaultInfo{Name: "user"}, | 			user: &user.DefaultInfo{Name: "user"}, | ||||||
| 			sa:   nil, | 			sa:   nil, | ||||||
| 			disallowedPolicies: map[string][]string{ | 			ns:   "test", | ||||||
| 				"user": {"policy1", "policy3"}, | 			allowed: map[string]map[string]map[string]bool{ | ||||||
| 				"sa":   {"policy2", "policy3"}, | 				"user": { | ||||||
|  | 					"test": {"policy2": true}, | ||||||
|  | 				}, | ||||||
| 			}, | 			}, | ||||||
| 			inPolicies: []*extensions.PodSecurityPolicy{ | 			inPolicies: []*extensions.PodSecurityPolicy{ | ||||||
| 				policyWithName("policy1"), | 				policyWithName("policy1"), | ||||||
| @@ -1634,8 +1652,8 @@ func TestGetMatchingPolicies(t *testing.T) { | |||||||
| 			store.Add(psp) | 			store.Add(psp) | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		authz := &TestAuthorizer{disallowed: v.disallowedPolicies} | 		authz := &TestAuthorizer{usernameToNamespaceToAllowedPSPs: v.allowed} | ||||||
| 		allowedPolicies, err := getMatchingPolicies(pspInformer.Lister(), v.user, v.sa, authz) | 		allowedPolicies, err := getMatchingPolicies(pspInformer.Lister(), v.user, v.sa, authz, v.ns) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			t.Errorf("%s got unexpected error %#v", k, err) | 			t.Errorf("%s got unexpected error %#v", k, err) | ||||||
| 			continue | 			continue | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Jordan Liggitt
					Jordan Liggitt