Optimize PSP authorization

This commit is contained in:
Tim Allclair 2017-11-13 17:03:24 -08:00
parent 5337ff8009
commit 9673235583
No known key found for this signature in database
GPG Key ID: 434D16BCEF479EAB
3 changed files with 204 additions and 147 deletions

View File

@ -42,7 +42,6 @@ go_test(
"//pkg/apis/core/helper:go_default_library",
"//pkg/apis/extensions:go_default_library",
"//pkg/client/informers/informers_generated/internalversion:go_default_library",
"//pkg/client/listers/extensions/internalversion:go_default_library",
"//pkg/controller:go_default_library",
"//pkg/security/apparmor:go_default_library",
"//pkg/security/podsecuritypolicy:go_default_library",
@ -53,8 +52,8 @@ go_test(
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/apiserver/pkg/admission:go_default_library",
"//vendor/k8s.io/apiserver/pkg/authentication/serviceaccount:go_default_library",
"//vendor/k8s.io/apiserver/pkg/authentication/user:go_default_library",
"//vendor/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library",
],

View File

@ -49,19 +49,15 @@ const (
// Register registers a plugin
func Register(plugins *admission.Plugins) {
plugins.Register(PluginName, func(config io.Reader) (admission.Interface, error) {
plugin := NewPlugin(psp.NewSimpleStrategyFactory(), getMatchingPolicies, true)
plugin := newPlugin(psp.NewSimpleStrategyFactory(), true)
return plugin, nil
})
}
// 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, namespace string) ([]*extensions.PodSecurityPolicy, error)
// PodSecurityPolicyPlugin holds state for and implements the admission plugin.
type PodSecurityPolicyPlugin struct {
*admission.Handler
strategyFactory psp.StrategyFactory
pspMatcher PSPMatchFn
failOnNoPolicies bool
authz authorizer.Authorizer
lister extensionslisters.PodSecurityPolicyLister
@ -88,12 +84,11 @@ var _ admission.ValidationInterface = &PodSecurityPolicyPlugin{}
var _ genericadmissioninit.WantsAuthorizer = &PodSecurityPolicyPlugin{}
var _ kubeapiserveradmission.WantsInternalKubeInformerFactory = &PodSecurityPolicyPlugin{}
// NewPlugin creates a new PSP admission plugin.
func NewPlugin(strategyFactory psp.StrategyFactory, pspMatcher PSPMatchFn, failOnNoPolicies bool) *PodSecurityPolicyPlugin {
// newPlugin creates a new PSP admission plugin.
func newPlugin(strategyFactory psp.StrategyFactory, failOnNoPolicies bool) *PodSecurityPolicyPlugin {
return &PodSecurityPolicyPlugin{
Handler: admission.NewHandler(admission.Create, admission.Update),
strategyFactory: strategyFactory,
pspMatcher: pspMatcher,
failOnNoPolicies: failOnNoPolicies,
}
}
@ -207,49 +202,60 @@ func (c *PodSecurityPolicyPlugin) computeSecurityContext(a admission.Attributes,
saInfo = serviceaccount.UserInfo(a.GetNamespace(), pod.Spec.ServiceAccountName, "")
}
matchedPolicies, err := c.pspMatcher(c.lister, a.GetUserInfo(), saInfo, c.authz, a.GetNamespace())
policies, err := c.lister.List(labels.Everything())
if err != nil {
return nil, "", nil, err
}
// if we have no policies and want to succeed then return. Otherwise we'll end up with no
// providers and fail with "unable to validate against any pod security policy" below.
if len(matchedPolicies) == 0 && !c.failOnNoPolicies {
if len(policies) == 0 && !c.failOnNoPolicies {
return pod, "", nil, nil
}
// sort by name to make order deterministic
// TODO(liggitt): add priority field to allow admins to bucket differently
sort.SliceStable(matchedPolicies, func(i, j int) bool {
return strings.Compare(matchedPolicies[i].Name, matchedPolicies[j].Name) < 0
sort.SliceStable(policies, func(i, j int) bool {
return strings.Compare(policies[i].Name, policies[j].Name) < 0
})
providers, errs := c.createProvidersFromPolicies(matchedPolicies, pod.Namespace)
logProviders(a, pod, providers, errs)
providers, errs := c.createProvidersFromPolicies(policies, pod.Namespace)
for _, err := range errs {
glog.V(4).Infof("provider creation error: %v", err)
}
if len(providers) == 0 {
return nil, "", nil, fmt.Errorf("no providers available to validate pod request")
}
// all containers in a single pod must validate under a single provider or we will reject the request
validationErrs := field.ErrorList{}
var (
allowedMutatedPod *api.Pod
allowingMutatingPSP string
// Map of PSP name to associated validation errors.
validationErrs = map[string]field.ErrorList{}
)
for _, provider := range providers {
podCopy := pod.DeepCopy()
if errs := assignSecurityContext(provider, podCopy, field.NewPath(fmt.Sprintf("provider %s: ", provider.GetPSPName()))); len(errs) > 0 {
validationErrs = append(validationErrs, errs...)
validationErrs[provider.GetPSPName()] = errs
continue
}
// the entire pod validated
mutated := !apiequality.Semantic.DeepEqual(pod, podCopy)
if mutated && !specMutationAllowed {
continue
}
if !isAuthorizedForPolicy(a.GetUserInfo(), saInfo, a.GetNamespace(), provider.GetPSPName(), c.authz) {
continue
}
switch {
case apiequality.Semantic.DeepEqual(pod, podCopy):
case !mutated:
// if it validated without mutating anything, use this result
return podCopy, provider.GetPSPName(), nil, nil
@ -261,11 +267,18 @@ func (c *PodSecurityPolicyPlugin) computeSecurityContext(a admission.Attributes,
}
}
if allowedMutatedPod == nil {
return nil, "", validationErrs, nil
if allowedMutatedPod != nil {
return allowedMutatedPod, allowingMutatingPSP, nil, nil
}
return allowedMutatedPod, allowingMutatingPSP, nil, nil
// Pod is rejected. Filter the validation errors to only include errors from authorized PSPs.
aggregate := field.ErrorList{}
for psp, errs := range validationErrs {
if isAuthorizedForPolicy(a.GetUserInfo(), saInfo, a.GetNamespace(), psp, c.authz) {
aggregate = append(aggregate, errs...)
}
}
return nil, "", aggregate, nil
}
// assignSecurityContext creates a security context for each container in the pod
@ -332,35 +345,18 @@ func (c *PodSecurityPolicyPlugin) createProvidersFromPolicies(psps []*extensions
return providers, errs
}
// getMatchingPolicies returns policies from the lister. For now this returns everything
// in the future it can filter based on UserInfo and permissions.
//
// TODO: this will likely need optimization since the initial implementation will
// always query for authorization. Needs scale testing and possibly checking against
// a cache.
func getMatchingPolicies(lister extensionslisters.PodSecurityPolicyLister, user user.Info, sa user.Info, authz authorizer.Authorizer, namespace string) ([]*extensions.PodSecurityPolicy, error) {
matchedPolicies := make([]*extensions.PodSecurityPolicy, 0)
list, err := lister.List(labels.Everything())
if err != nil {
return nil, err
}
for _, constraint := range list {
if authorizedForPolicy(user, namespace, constraint, authz) || authorizedForPolicy(sa, namespace, constraint, authz) {
matchedPolicies = append(matchedPolicies, constraint)
}
}
return matchedPolicies, nil
func isAuthorizedForPolicy(user, sa user.Info, namespace, policyName string, authz authorizer.Authorizer) bool {
// Check the service account first, as that is the more common use case.
return authorizedForPolicy(sa, namespace, policyName, authz) ||
authorizedForPolicy(user, namespace, policyName, authz)
}
// authorizedForPolicy returns true if info is authorized to perform the "use" verb on the policy resource.
func authorizedForPolicy(info user.Info, namespace string, policy *extensions.PodSecurityPolicy, authz authorizer.Authorizer) bool {
func authorizedForPolicy(info user.Info, namespace string, policyName string, authz authorizer.Authorizer) bool {
if info == nil {
return false
}
attr := buildAttributes(info, namespace, policy)
attr := buildAttributes(info, namespace, policyName)
decision, reason, err := authz.Authorize(attr)
if err != nil {
glog.V(5).Infof("cannot authorize for policy: %v,%v", reason, err)
@ -369,35 +365,16 @@ func authorizedForPolicy(info user.Info, namespace string, policy *extensions.Po
}
// buildAttributes builds an attributes record for a SAR based on the user info and policy.
func buildAttributes(info user.Info, namespace string, policy *extensions.PodSecurityPolicy) authorizer.Attributes {
func buildAttributes(info user.Info, namespace string, policyName 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: policy.Name,
Name: policyName,
APIGroup: extensions.GroupName,
Resource: "podsecuritypolicies",
ResourceRequest: true,
}
return attr
}
// logProviders logs what providers were found for the pod as well as any errors that were encountered
// while creating providers.
func logProviders(a admission.Attributes, pod *api.Pod, providers []psp.Provider, providerCreationErrs []error) {
for _, err := range providerCreationErrs {
glog.V(4).Infof("provider creation error: %v", err)
}
if len(providers) == 0 {
glog.V(4).Infof("unable to validate pod %s (generate: %s) in namespace %s against any provider.", pod.Name, pod.GenerateName, a.GetNamespace())
return
}
names := make([]string, len(providers))
for i, p := range providers {
names[i] = p.GetPSPName()
}
glog.V(4).Infof("validating pod %s (generate: %s) in namespace %s against providers: %s", pod.Name, pod.GenerateName, a.GetNamespace(), strings.Join(names, ","))
}

View File

@ -28,8 +28,8 @@ import (
apiequality "k8s.io/apimachinery/pkg/api/equality"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/diff"
"k8s.io/apimachinery/pkg/util/sets"
kadmission "k8s.io/apiserver/pkg/admission"
"k8s.io/apiserver/pkg/authentication/serviceaccount"
"k8s.io/apiserver/pkg/authentication/user"
"k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/kubernetes/pkg/api/legacyscheme"
@ -37,7 +37,6 @@ import (
"k8s.io/kubernetes/pkg/apis/core/helper"
"k8s.io/kubernetes/pkg/apis/extensions"
informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
extensionslisters "k8s.io/kubernetes/pkg/client/listers/extensions/internalversion"
"k8s.io/kubernetes/pkg/controller"
"k8s.io/kubernetes/pkg/security/apparmor"
kpsp "k8s.io/kubernetes/pkg/security/podsecuritypolicy"
@ -47,14 +46,21 @@ import (
const defaultContainerName = "test-c"
// NewTestAdmission provides an admission plugin with test implementations of internal structs. It uses
// an authorizer that always returns true.
func NewTestAdmission(lister extensionslisters.PodSecurityPolicyLister) *PodSecurityPolicyPlugin {
// NewTestAdmission provides an admission plugin with test implementations of internal structs.
func NewTestAdmission(psps []*extensions.PodSecurityPolicy, authz authorizer.Authorizer) *PodSecurityPolicyPlugin {
informerFactory := informers.NewSharedInformerFactory(nil, controller.NoResyncPeriodFunc())
store := informerFactory.Extensions().InternalVersion().PodSecurityPolicies().Informer().GetStore()
for _, psp := range psps {
store.Add(psp)
}
lister := informerFactory.Extensions().InternalVersion().PodSecurityPolicies().Lister()
if authz == nil {
authz = &TestAuthorizer{}
}
return &PodSecurityPolicyPlugin{
Handler: kadmission.NewHandler(kadmission.Create, kadmission.Update),
strategyFactory: kpsp.NewSimpleStrategyFactory(),
pspMatcher: getMatchingPolicies,
authz: &TestAuthorizer{},
authz: authz,
lister: lister,
}
}
@ -434,7 +440,7 @@ func TestAdmitPreferNonmutating(t *testing.T) {
}
for k, v := range tests {
testPSPAdmitAdvanced(k, v.operation, v.psps, v.pod, v.podBeforeUpdate, v.shouldPassAdmit, v.shouldPassValidate, v.expectMutation, v.expectedPSP, t)
testPSPAdmitAdvanced(k, v.operation, v.psps, nil, &user.DefaultInfo{}, v.pod, v.podBeforeUpdate, v.shouldPassAdmit, v.shouldPassValidate, v.expectMutation, v.expectedPSP, t)
if v.shouldPassAdmit {
actualPodUser := (*int64)(nil)
@ -461,7 +467,7 @@ func TestAdmitPreferNonmutating(t *testing.T) {
}
func TestFailClosedOnInvalidPod(t *testing.T) {
plugin := NewTestAdmission(nil)
plugin := NewTestAdmission(nil, nil)
pod := &v1.Pod{}
attrs := kadmission.NewAttributesRecord(pod, nil, kapi.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, kapi.Resource("pods").WithVersion("version"), "", kadmission.Create, &user.DefaultInfo{})
@ -1785,22 +1791,14 @@ func TestAdmitSysctls(t *testing.T) {
}
func testPSPAdmit(testCaseName string, psps []*extensions.PodSecurityPolicy, pod *kapi.Pod, shouldPassAdmit, shouldPassValidate bool, expectedPSP string, t *testing.T) {
testPSPAdmitAdvanced(testCaseName, kadmission.Create, psps, pod, nil, shouldPassAdmit, shouldPassValidate, true, expectedPSP, t)
testPSPAdmitAdvanced(testCaseName, kadmission.Create, psps, nil, &user.DefaultInfo{}, pod, nil, shouldPassAdmit, shouldPassValidate, true, expectedPSP, t)
}
func testPSPAdmitAdvanced(testCaseName string, op kadmission.Operation, psps []*extensions.PodSecurityPolicy, pod, oldPod *kapi.Pod, shouldPassAdmit, shouldPassValidate bool, canMutate bool, expectedPSP string, t *testing.T) {
informerFactory := informers.NewSharedInformerFactory(nil, controller.NoResyncPeriodFunc())
store := informerFactory.Extensions().InternalVersion().PodSecurityPolicies().Informer().GetStore()
for _, psp := range psps {
store.Add(psp)
}
func testPSPAdmitAdvanced(testCaseName string, op kadmission.Operation, psps []*extensions.PodSecurityPolicy, authz authorizer.Authorizer, userInfo user.Info, pod, oldPod *kapi.Pod, shouldPassAdmit, shouldPassValidate bool, canMutate bool, expectedPSP string, t *testing.T) {
originalPod := pod.DeepCopy()
plugin := NewTestAdmission(psps, authz)
plugin := NewTestAdmission(informerFactory.Extensions().InternalVersion().PodSecurityPolicies().Lister())
attrs := kadmission.NewAttributesRecord(pod, oldPod, kapi.Kind("Pod").WithVersion("version"), "namespace", "", kapi.Resource("pods").WithVersion("version"), "", op, &user.DefaultInfo{})
attrs := kadmission.NewAttributesRecord(pod, oldPod, kapi.Kind("Pod").WithVersion("version"), pod.Namespace, "", kapi.Resource("pods").WithVersion("version"), "", op, userInfo)
err := plugin.Admit(attrs)
if shouldPassAdmit && err != nil {
@ -1987,59 +1985,59 @@ func TestCreateProvidersFromConstraints(t *testing.T) {
}
}
func TestGetMatchingPolicies(t *testing.T) {
func TestPolicyAuthorization(t *testing.T) {
policyWithName := func(name string) *extensions.PodSecurityPolicy {
p := restrictivePSP()
p := permissivePSP()
p.Name = name
return p
}
tests := map[string]struct {
user user.Info
sa user.Info
ns string
expectedPolicies sets.String
inPolicies []*extensions.PodSecurityPolicy
allowed map[string]map[string]map[string]bool
user user.Info
sa string
ns string
expectedPolicy string
inPolicies []*extensions.PodSecurityPolicy
allowed map[string]map[string]map[string]bool
}{
"policy allowed by user": {
user: &user.DefaultInfo{Name: "user"},
sa: &user.DefaultInfo{Name: "sa"},
sa: "sa",
ns: "test",
allowed: map[string]map[string]map[string]bool{
"user": {
"test": {"policy": true},
},
},
inPolicies: []*extensions.PodSecurityPolicy{policyWithName("policy")},
expectedPolicies: sets.NewString("policy"),
inPolicies: []*extensions.PodSecurityPolicy{policyWithName("policy")},
expectedPolicy: "policy",
},
"policy allowed by sa": {
user: &user.DefaultInfo{Name: "user"},
sa: &user.DefaultInfo{Name: "sa"},
sa: "sa",
ns: "test",
allowed: map[string]map[string]map[string]bool{
"sa": {
serviceaccount.MakeUsername("test", "sa"): {
"test": {"policy": true},
},
},
inPolicies: []*extensions.PodSecurityPolicy{policyWithName("policy")},
expectedPolicies: sets.NewString("policy"),
inPolicies: []*extensions.PodSecurityPolicy{policyWithName("policy")},
expectedPolicy: "policy",
},
"no policies allowed": {
user: &user.DefaultInfo{Name: "user"},
sa: &user.DefaultInfo{Name: "sa"},
ns: "test",
allowed: map[string]map[string]map[string]bool{},
inPolicies: []*extensions.PodSecurityPolicy{policyWithName("policy")},
expectedPolicies: sets.NewString(),
user: &user.DefaultInfo{Name: "user"},
sa: "sa",
ns: "test",
allowed: map[string]map[string]map[string]bool{},
inPolicies: []*extensions.PodSecurityPolicy{policyWithName("policy")},
expectedPolicy: "",
},
"multiple policies allowed": {
user: &user.DefaultInfo{Name: "user"},
sa: &user.DefaultInfo{Name: "sa"},
sa: "sa",
ns: "test",
allowed: map[string]map[string]map[string]bool{
"sa": {
serviceaccount.MakeUsername("test", "sa"): {
"test": {"policy1": true},
"": {"policy4": true},
"other": {"policy6": true},
@ -2051,22 +2049,23 @@ func TestGetMatchingPolicies(t *testing.T) {
},
},
inPolicies: []*extensions.PodSecurityPolicy{
policyWithName("policy1"), // allowed by sa
policyWithName("policy2"), // allowed by user
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
// Prefix to force checking these policies first.
policyWithName("a_policy1"), // not allowed in this namespace
policyWithName("a_policy2"), // not allowed in this namespace
policyWithName("policy2"), // allowed by sa
policyWithName("policy3"), // allowed by user
policyWithName("policy4"), // not allowed
policyWithName("policy5"), // allowed by sa at cluster level
policyWithName("policy6"), // allowed by user at cluster level
},
expectedPolicies: sets.NewString("policy1", "policy2", "policy4", "policy5"),
expectedPolicy: "policy2",
},
"policies are not allowed for nil user info": {
user: nil,
sa: &user.DefaultInfo{Name: "sa"},
sa: "sa",
ns: "test",
allowed: map[string]map[string]map[string]bool{
"sa": {
serviceaccount.MakeUsername("test", "sa"): {
"test": {"policy1": true},
},
"user": {
@ -2079,14 +2078,14 @@ func TestGetMatchingPolicies(t *testing.T) {
policyWithName("policy3"),
},
// only the policies for the sa are allowed when user info is nil
expectedPolicies: sets.NewString("policy1"),
expectedPolicy: "policy1",
},
"policies are not allowed for nil sa info": {
user: &user.DefaultInfo{Name: "user"},
sa: nil,
sa: "",
ns: "test",
allowed: map[string]map[string]map[string]bool{
"sa": {
serviceaccount.MakeUsername("test", "sa"): {
"test": {"policy1": true},
},
"user": {
@ -2099,14 +2098,14 @@ func TestGetMatchingPolicies(t *testing.T) {
policyWithName("policy3"),
},
// only the policies for the user are allowed when sa info is nil
expectedPolicies: sets.NewString("policy2"),
expectedPolicy: "policy2",
},
"policies are not allowed for nil sa and user info": {
user: nil,
sa: nil,
sa: "",
ns: "test",
allowed: map[string]map[string]map[string]bool{
"sa": {
serviceaccount.MakeUsername("test", "sa"): {
"test": {"policy1": true},
},
"user": {
@ -2119,30 +2118,110 @@ func TestGetMatchingPolicies(t *testing.T) {
policyWithName("policy3"),
},
// no policies are allowed if sa and user are both nil
expectedPolicies: sets.NewString(),
expectedPolicy: "",
},
}
for k, v := range tests {
informerFactory := informers.NewSharedInformerFactory(nil, controller.NoResyncPeriodFunc())
pspInformer := informerFactory.Extensions().InternalVersion().PodSecurityPolicies()
store := pspInformer.Informer().GetStore()
for _, psp := range v.inPolicies {
store.Add(psp)
}
var (
oldPod *kapi.Pod
shouldPass = v.expectedPolicy != ""
authz = &TestAuthorizer{usernameToNamespaceToAllowedPSPs: v.allowed}
canMutate = true
)
pod := goodPod()
pod.Namespace = v.ns
pod.Spec.ServiceAccountName = v.sa
testPSPAdmitAdvanced(k, kadmission.Create, v.inPolicies, authz, v.user,
pod, oldPod, shouldPass, shouldPass, canMutate, v.expectedPolicy, t)
}
}
authz := &TestAuthorizer{usernameToNamespaceToAllowedPSPs: v.allowed}
allowedPolicies, err := getMatchingPolicies(pspInformer.Lister(), v.user, v.sa, authz, v.ns)
if err != nil {
t.Errorf("%s got unexpected error %#v", k, err)
continue
}
allowedPolicyNames := sets.NewString()
for _, p := range allowedPolicies {
allowedPolicyNames.Insert(p.Name)
}
if !v.expectedPolicies.Equal(allowedPolicyNames) {
t.Errorf("%s received unexpected policies. Expected %#v but got %#v", k, v.expectedPolicies.List(), allowedPolicyNames.List())
}
func TestPolicyAuthorizationErrors(t *testing.T) {
policyWithName := func(name string) *extensions.PodSecurityPolicy {
p := restrictivePSP()
p.Name = name
return p
}
const (
sa = "sa"
ns = "test"
userName = "user"
)
tests := map[string]struct {
priviliged bool
inPolicies []*extensions.PodSecurityPolicy
allowed map[string]map[string]map[string]bool
expectValidationErrs int
}{
"policies not allowed": {
allowed: map[string]map[string]map[string]bool{},
inPolicies: []*extensions.PodSecurityPolicy{
policyWithName("policy1"),
policyWithName("policy2"),
},
expectValidationErrs: 0,
},
"policy allowed by user": {
allowed: map[string]map[string]map[string]bool{
"user": {
"test": {"policy1": true},
},
},
inPolicies: []*extensions.PodSecurityPolicy{
policyWithName("policy1"),
policyWithName("policy2"),
},
expectValidationErrs: 1,
},
"policy allowed by service account": {
allowed: map[string]map[string]map[string]bool{
serviceaccount.MakeUsername("test", "sa"): {
"test": {"policy2": true},
},
},
inPolicies: []*extensions.PodSecurityPolicy{
policyWithName("policy1"),
policyWithName("policy2"),
},
expectValidationErrs: 1,
},
"multiple policies allowed": {
allowed: map[string]map[string]map[string]bool{
"user": {
"test": {"policy1": true},
},
serviceaccount.MakeUsername("test", "sa"): {
"test": {"policy2": true},
},
},
inPolicies: []*extensions.PodSecurityPolicy{
policyWithName("policy1"),
policyWithName("policy2"),
},
expectValidationErrs: 2,
},
}
for desc, tc := range tests {
t.Run(desc, func(t *testing.T) {
var (
authz = &TestAuthorizer{usernameToNamespaceToAllowedPSPs: tc.allowed}
privileged = true
)
pod := goodPod()
pod.Namespace = ns
pod.Spec.ServiceAccountName = sa
pod.Spec.Containers[0].SecurityContext.Privileged = &privileged
plugin := NewTestAdmission(tc.inPolicies, authz)
attrs := kadmission.NewAttributesRecord(pod, nil, kapi.Kind("Pod").WithVersion("version"), ns, "", kapi.Resource("pods").WithVersion("version"), "", kadmission.Create, &user.DefaultInfo{Name: userName})
allowedPod, _, validationErrs, err := plugin.computeSecurityContext(attrs, pod, true)
assert.Nil(t, allowedPod)
assert.NoError(t, err)
assert.Len(t, validationErrs, tc.expectValidationErrs)
})
}
}
@ -2217,6 +2296,8 @@ func permissivePSP() *extensions.PodSecurityPolicy {
func goodPod() *kapi.Pod {
return &kapi.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "pod",
Namespace: "namespace",
Annotations: map[string]string{},
},
Spec: kapi.PodSpec{