Avoid nil user special-casing in unsecured endpoint

This commit is contained in:
Jordan Liggitt 2017-03-31 00:16:27 -04:00
parent d42d630d74
commit 5d839d0d0b
No known key found for this signature in database
GPG Key ID: 24E7ADF9A3B42012
5 changed files with 54 additions and 13 deletions

View File

@ -13,6 +13,7 @@ go_library(
tags = ["automanaged"], tags = ["automanaged"],
deps = [ deps = [
"//vendor:github.com/golang/glog", "//vendor:github.com/golang/glog",
"//vendor:k8s.io/apiserver/pkg/authentication/user",
"//vendor:k8s.io/apiserver/pkg/endpoints/filters", "//vendor:k8s.io/apiserver/pkg/endpoints/filters",
"//vendor:k8s.io/apiserver/pkg/endpoints/request", "//vendor:k8s.io/apiserver/pkg/endpoints/request",
"//vendor:k8s.io/apiserver/pkg/server", "//vendor:k8s.io/apiserver/pkg/server",

View File

@ -22,6 +22,7 @@ import (
"github.com/golang/glog" "github.com/golang/glog"
"k8s.io/apiserver/pkg/authentication/user"
genericapifilters "k8s.io/apiserver/pkg/endpoints/filters" genericapifilters "k8s.io/apiserver/pkg/endpoints/filters"
apirequest "k8s.io/apiserver/pkg/endpoints/request" apirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/server" "k8s.io/apiserver/pkg/server"
@ -35,6 +36,7 @@ import (
func BuildInsecureHandlerChain(apiHandler http.Handler, c *server.Config) http.Handler { func BuildInsecureHandlerChain(apiHandler http.Handler, c *server.Config) http.Handler {
handler := genericapifilters.WithAudit(apiHandler, c.RequestContextMapper, c.AuditWriter) handler := genericapifilters.WithAudit(apiHandler, c.RequestContextMapper, c.AuditWriter)
handler = genericapifilters.WithAuthentication(handler, c.RequestContextMapper, insecureSuperuser{}, nil)
handler = genericfilters.WithCORS(handler, c.CorsAllowedOriginList, nil, nil, nil, "true") handler = genericfilters.WithCORS(handler, c.CorsAllowedOriginList, nil, nil, nil, "true")
handler = genericfilters.WithPanicRecovery(handler, c.RequestContextMapper) handler = genericfilters.WithPanicRecovery(handler, c.RequestContextMapper)
handler = genericfilters.WithTimeoutForNonLongRunningRequests(handler, c.RequestContextMapper, c.LongRunningFunc) handler = genericfilters.WithTimeoutForNonLongRunningRequests(handler, c.RequestContextMapper, c.LongRunningFunc)
@ -111,3 +113,15 @@ func serveInsecurely(insecureServingInfo *InsecureServingInfo, insecureHandler h
_, err = server.RunServer(insecureServer, insecureServingInfo.BindNetwork, stopCh) _, err = server.RunServer(insecureServer, insecureServingInfo.BindNetwork, stopCh)
return err return err
} }
// insecureSuperuser implements authenticator.Request to always return a superuser.
// This is functionally equivalent to skipping authentication and authorization,
// but allows apiserver code to stop special-casing a nil user to skip authorization checks.
type insecureSuperuser struct{}
func (insecureSuperuser) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
return &user.DefaultInfo{
Name: "system:unsecured",
Groups: []string{user.SystemPrivilegedGroup, user.AllAuthenticated},
}, true, nil
}

View File

@ -29,9 +29,7 @@ import (
func EscalationAllowed(ctx genericapirequest.Context) bool { func EscalationAllowed(ctx genericapirequest.Context) bool {
u, ok := genericapirequest.UserFrom(ctx) u, ok := genericapirequest.UserFrom(ctx)
if !ok { if !ok {
// the only way to be without a user is to either have no authenticators by explicitly saying that's your preference return false
// or to be connecting via the insecure port, in which case this logically doesn't apply
return true
} }
// system:masters is special because the API server uses it for privileged loopback connections // system:masters is special because the API server uses it for privileged loopback connections

View File

@ -288,8 +288,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 authorizedForPolicy(user, namespace, constraint, authz) || authorizedForPolicy(sa, namespace, constraint, authz) {
if user == nil || authorizedForPolicy(user, namespace, constraint, authz) || authorizedForPolicy(sa, namespace, constraint, authz) {
matchedPolicies = append(matchedPolicies, constraint) matchedPolicies = append(matchedPolicies, constraint)
} }
} }

View File

@ -1612,25 +1612,34 @@ func TestGetMatchingPolicies(t *testing.T) {
}, },
expectedPolicies: sets.NewString("policy1", "policy2", "policy4", "policy5"), expectedPolicies: sets.NewString("policy1", "policy2", "policy4", "policy5"),
}, },
"policies are allowed for nil user info": { "policies are not allowed for nil user info": {
user: nil, user: nil,
sa: &user.DefaultInfo{Name: "sa"}, sa: &user.DefaultInfo{Name: "sa"},
ns: "test", ns: "test",
allowed: map[string]map[string]map[string]bool{}, // authorizer not consulted allowed: map[string]map[string]map[string]bool{
"sa": {
"test": {"policy1": true},
},
"user": {
"test": {"policy2": true},
},
},
inPolicies: []*extensions.PodSecurityPolicy{ inPolicies: []*extensions.PodSecurityPolicy{
policyWithName("policy1"), policyWithName("policy1"),
policyWithName("policy2"), policyWithName("policy2"),
policyWithName("policy3"), policyWithName("policy3"),
}, },
// all policies are allowed regardless of the permissions when user info is nil // only the policies for the sa are allowed when user info is nil
// (ie. a request hitting the unsecure port) expectedPolicies: sets.NewString("policy1"),
expectedPolicies: sets.NewString("policy1", "policy2", "policy3"),
}, },
"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,
ns: "test", ns: "test",
allowed: map[string]map[string]map[string]bool{ allowed: map[string]map[string]map[string]bool{
"sa": {
"test": {"policy1": true},
},
"user": { "user": {
"test": {"policy2": true}, "test": {"policy2": true},
}, },
@ -1643,6 +1652,26 @@ func TestGetMatchingPolicies(t *testing.T) {
// only the policies for the user are allowed when sa info is nil // only the policies for the user are allowed when sa info is nil
expectedPolicies: sets.NewString("policy2"), expectedPolicies: sets.NewString("policy2"),
}, },
"policies are not allowed for nil sa and user info": {
user: nil,
sa: nil,
ns: "test",
allowed: map[string]map[string]map[string]bool{
"sa": {
"test": {"policy1": true},
},
"user": {
"test": {"policy2": true},
},
},
inPolicies: []*extensions.PodSecurityPolicy{
policyWithName("policy1"),
policyWithName("policy2"),
policyWithName("policy3"),
},
// no policies are allowed if sa and user are both nil
expectedPolicies: sets.NewString(),
},
} }
for k, v := range tests { for k, v := range tests {
informerFactory := informers.NewSharedInformerFactory(nil, controller.NoResyncPeriodFunc()) informerFactory := informers.NewSharedInformerFactory(nil, controller.NoResyncPeriodFunc())