Modify PodSecurityPolicy admission plugin to additionally allow authorizing via "use" verb in policy API group.

pull/6/head
Slava Semushin 2018-02-21 18:16:00 +01:00
parent a4222bd8c3
commit 3d4fa8a189
3 changed files with 52 additions and 9 deletions

View File

@ -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:

View File

@ -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,
}

View File

@ -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()