mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 02:41:25 +00:00
pkg/master: enable certificates API and add rbac authorizer
This commit is contained in:
parent
6f312f145d
commit
ef40aa9572
@ -46,6 +46,15 @@ import (
|
||||
kubeletclient "k8s.io/kubernetes/pkg/kubelet/client"
|
||||
"k8s.io/kubernetes/pkg/master"
|
||||
"k8s.io/kubernetes/pkg/registry/cachesize"
|
||||
"k8s.io/kubernetes/pkg/registry/clusterrole"
|
||||
clusterroleetcd "k8s.io/kubernetes/pkg/registry/clusterrole/etcd"
|
||||
"k8s.io/kubernetes/pkg/registry/clusterrolebinding"
|
||||
clusterrolebindingetcd "k8s.io/kubernetes/pkg/registry/clusterrolebinding/etcd"
|
||||
"k8s.io/kubernetes/pkg/registry/generic"
|
||||
"k8s.io/kubernetes/pkg/registry/role"
|
||||
roleetcd "k8s.io/kubernetes/pkg/registry/role/etcd"
|
||||
"k8s.io/kubernetes/pkg/registry/rolebinding"
|
||||
rolebindingetcd "k8s.io/kubernetes/pkg/registry/rolebinding/etcd"
|
||||
"k8s.io/kubernetes/pkg/serviceaccount"
|
||||
)
|
||||
|
||||
@ -198,6 +207,32 @@ func Run(s *options.APIServer) error {
|
||||
}
|
||||
|
||||
authorizationModeNames := strings.Split(s.AuthorizationMode, ",")
|
||||
|
||||
modeEnabled := func(mode string) bool {
|
||||
for _, m := range authorizationModeNames {
|
||||
if m == mode {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
if modeEnabled(apiserver.ModeRBAC) {
|
||||
mustGetRESTOptions := func(resource string) generic.RESTOptions {
|
||||
s, err := storageFactory.New(api.Resource(resource))
|
||||
if err != nil {
|
||||
glog.Fatalf("Unable to get %s storage: %v", resource, err)
|
||||
}
|
||||
return generic.RESTOptions{Storage: s, Decorator: generic.UndecoratedStorage}
|
||||
}
|
||||
|
||||
// For initial bootstrapping go directly to etcd to avoid privillege escalation check.
|
||||
s.AuthorizationConfig.RBACRoleRegistry = role.NewRegistry(roleetcd.NewREST(mustGetRESTOptions("roles")))
|
||||
s.AuthorizationConfig.RBACRoleBindingRegistry = rolebinding.NewRegistry(rolebindingetcd.NewREST(mustGetRESTOptions("rolebindings")))
|
||||
s.AuthorizationConfig.RBACClusterRoleRegistry = clusterrole.NewRegistry(clusterroleetcd.NewREST(mustGetRESTOptions("clusterroles")))
|
||||
s.AuthorizationConfig.RBACClusterRoleBindingRegistry = clusterrolebinding.NewRegistry(clusterrolebindingetcd.NewREST(mustGetRESTOptions("clusterrolebindings")))
|
||||
}
|
||||
|
||||
authorizer, err := apiserver.NewAuthorizerFromAuthorizationConfig(authorizationModeNames, s.AuthorizationConfig)
|
||||
if err != nil {
|
||||
glog.Fatalf("Invalid Authorization Config: %v", err)
|
||||
@ -216,6 +251,7 @@ func Run(s *options.APIServer) error {
|
||||
genericConfig.Authenticator = authenticator
|
||||
genericConfig.SupportsBasicAuth = len(s.BasicAuthFile) > 0
|
||||
genericConfig.Authorizer = authorizer
|
||||
genericConfig.AuthorizerRBACSuperUser = s.AuthorizationConfig.RBACSuperUser
|
||||
genericConfig.AdmissionControl = admissionController
|
||||
genericConfig.APIResourceConfigSource = storageFactory.APIResourceConfigSource
|
||||
genericConfig.MasterServiceNamespace = s.MasterServiceNamespace
|
||||
|
@ -22,6 +22,7 @@ authentication-token-webhook-cache-ttl
|
||||
authentication-token-webhook-config-file
|
||||
authorization-mode
|
||||
authorization-policy-file
|
||||
authorization-rbac-super-user
|
||||
authorization-webhook-config-file
|
||||
authorization-webhook-cache-authorized-ttl
|
||||
authorization-webhook-cache-unauthorized-ttl
|
||||
|
@ -24,6 +24,11 @@ import (
|
||||
"k8s.io/kubernetes/pkg/auth/authorizer"
|
||||
"k8s.io/kubernetes/pkg/auth/authorizer/abac"
|
||||
"k8s.io/kubernetes/pkg/auth/authorizer/union"
|
||||
"k8s.io/kubernetes/pkg/registry/clusterrole"
|
||||
"k8s.io/kubernetes/pkg/registry/clusterrolebinding"
|
||||
"k8s.io/kubernetes/pkg/registry/role"
|
||||
"k8s.io/kubernetes/pkg/registry/rolebinding"
|
||||
"k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac"
|
||||
"k8s.io/kubernetes/plugin/pkg/auth/authorizer/webhook"
|
||||
)
|
||||
|
||||
@ -63,10 +68,11 @@ const (
|
||||
ModeAlwaysDeny string = "AlwaysDeny"
|
||||
ModeABAC string = "ABAC"
|
||||
ModeWebhook string = "Webhook"
|
||||
ModeRBAC string = "RBAC"
|
||||
)
|
||||
|
||||
// Keep this list in sync with constant list above.
|
||||
var AuthorizationModeChoices = []string{ModeAlwaysAllow, ModeAlwaysDeny, ModeABAC, ModeWebhook}
|
||||
var AuthorizationModeChoices = []string{ModeAlwaysAllow, ModeAlwaysDeny, ModeABAC, ModeWebhook, ModeRBAC}
|
||||
|
||||
type AuthorizationConfig struct {
|
||||
// Options for ModeABAC
|
||||
@ -82,6 +88,16 @@ type AuthorizationConfig struct {
|
||||
WebhookCacheAuthorizedTTL time.Duration
|
||||
// TTL for caching of unauthorized responses from the webhook server.
|
||||
WebhookCacheUnauthorizedTTL time.Duration
|
||||
|
||||
// Options for RBAC
|
||||
|
||||
// User which can bootstrap role policies
|
||||
RBACSuperUser string
|
||||
|
||||
RBACClusterRoleRegistry clusterrole.Registry
|
||||
RBACClusterRoleBindingRegistry clusterrolebinding.Registry
|
||||
RBACRoleRegistry role.Registry
|
||||
RBACRoleBindingRegistry rolebinding.Registry
|
||||
}
|
||||
|
||||
// NewAuthorizerFromAuthorizationConfig returns the right sort of union of multiple authorizer.Authorizer objects
|
||||
@ -126,6 +142,18 @@ func NewAuthorizerFromAuthorizationConfig(authorizationModes []string, config Au
|
||||
return nil, err
|
||||
}
|
||||
authorizers = append(authorizers, webhookAuthorizer)
|
||||
case ModeRBAC:
|
||||
rbacAuthorizer, err := rbac.New(
|
||||
config.RBACRoleRegistry,
|
||||
config.RBACRoleBindingRegistry,
|
||||
config.RBACClusterRoleRegistry,
|
||||
config.RBACClusterRoleBindingRegistry,
|
||||
config.RBACSuperUser,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authorizers = append(authorizers, rbacAuthorizer)
|
||||
default:
|
||||
return nil, fmt.Errorf("Unknown authorization mode %s specified", authorizationMode)
|
||||
}
|
||||
@ -138,6 +166,9 @@ func NewAuthorizerFromAuthorizationConfig(authorizationModes []string, config Au
|
||||
if !authorizerMap[ModeWebhook] && config.WebhookConfigFile != "" {
|
||||
return nil, errors.New("Cannot specify --authorization-webhook-config-file without mode Webhook")
|
||||
}
|
||||
if !authorizerMap[ModeRBAC] && config.RBACSuperUser != "" {
|
||||
return nil, errors.New("Cannot specify --authorization-rbac-super-user without mode RBAC")
|
||||
}
|
||||
|
||||
return union.New(authorizers...), nil
|
||||
}
|
||||
|
@ -118,6 +118,8 @@ type Config struct {
|
||||
Authorizer authorizer.Authorizer
|
||||
AdmissionControl admission.Interface
|
||||
MasterServiceNamespace string
|
||||
// TODO(ericchiang): Determine if policy escalation checks should be an admission controller.
|
||||
AuthorizerRBACSuperUser string
|
||||
|
||||
// Map requests to contexts. Exported so downstream consumers can provider their own mappers
|
||||
RequestContextMapper api.RequestContextMapper
|
||||
|
@ -227,6 +227,7 @@ func (s *ServerRunOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
fs.StringVar(&s.AuthorizationConfig.WebhookConfigFile, "authorization-webhook-config-file", s.AuthorizationConfig.WebhookConfigFile, "File with webhook configuration in kubeconfig format, used with --authorization-mode=Webhook. The API server will query the remote service to determine access on the API server's secure port.")
|
||||
fs.DurationVar(&s.AuthorizationConfig.WebhookCacheAuthorizedTTL, "authorization-webhook-cache-authorized-ttl", s.AuthorizationConfig.WebhookCacheAuthorizedTTL, "The duration to cache 'authorized' responses from the webhook authorizer. Default is 5m.")
|
||||
fs.DurationVar(&s.AuthorizationConfig.WebhookCacheUnauthorizedTTL, "authorization-webhook-cache-unauthorized-ttl", s.AuthorizationConfig.WebhookCacheUnauthorizedTTL, "The duration to cache 'unauthorized' responses from the webhook authorizer. Default is 30s.")
|
||||
fs.StringVar(&s.AuthorizationConfig.RBACSuperUser, "authorization-rbac-super-user", s.AuthorizationConfig.RBACSuperUser, "If specified, a username which avoids RBAC authorization checks and role binding privilege escalation checks, to be used with --authorization-mode=RBAC.")
|
||||
|
||||
fs.StringVar(&s.BasicAuthFile, "basic-auth-file", s.BasicAuthFile, "If set, the file that will be used to admit requests to the secure port of the API server via http basic authentication.")
|
||||
|
||||
|
@ -29,6 +29,7 @@ import (
|
||||
_ "k8s.io/kubernetes/pkg/apis/componentconfig/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/extensions/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/policy/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/rbac/install"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -43,12 +43,21 @@ import (
|
||||
extensionsapiv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||
"k8s.io/kubernetes/pkg/apis/policy"
|
||||
policyapiv1alpha1 "k8s.io/kubernetes/pkg/apis/policy/v1alpha1"
|
||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||
rbacapi "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1"
|
||||
rbacvalidation "k8s.io/kubernetes/pkg/apis/rbac/validation"
|
||||
"k8s.io/kubernetes/pkg/apiserver"
|
||||
apiservermetrics "k8s.io/kubernetes/pkg/apiserver/metrics"
|
||||
"k8s.io/kubernetes/pkg/genericapiserver"
|
||||
"k8s.io/kubernetes/pkg/healthz"
|
||||
kubeletclient "k8s.io/kubernetes/pkg/kubelet/client"
|
||||
"k8s.io/kubernetes/pkg/master/ports"
|
||||
"k8s.io/kubernetes/pkg/registry/clusterrole"
|
||||
clusterroleetcd "k8s.io/kubernetes/pkg/registry/clusterrole/etcd"
|
||||
clusterrolepolicybased "k8s.io/kubernetes/pkg/registry/clusterrole/policybased"
|
||||
"k8s.io/kubernetes/pkg/registry/clusterrolebinding"
|
||||
clusterrolebindingetcd "k8s.io/kubernetes/pkg/registry/clusterrolebinding/etcd"
|
||||
clusterrolebindingpolicybased "k8s.io/kubernetes/pkg/registry/clusterrolebinding/policybased"
|
||||
"k8s.io/kubernetes/pkg/registry/componentstatus"
|
||||
configmapetcd "k8s.io/kubernetes/pkg/registry/configmap/etcd"
|
||||
controlleretcd "k8s.io/kubernetes/pkg/registry/controller/etcd"
|
||||
@ -75,6 +84,12 @@ import (
|
||||
podtemplateetcd "k8s.io/kubernetes/pkg/registry/podtemplate/etcd"
|
||||
replicasetetcd "k8s.io/kubernetes/pkg/registry/replicaset/etcd"
|
||||
resourcequotaetcd "k8s.io/kubernetes/pkg/registry/resourcequota/etcd"
|
||||
"k8s.io/kubernetes/pkg/registry/role"
|
||||
roleetcd "k8s.io/kubernetes/pkg/registry/role/etcd"
|
||||
rolepolicybased "k8s.io/kubernetes/pkg/registry/role/policybased"
|
||||
"k8s.io/kubernetes/pkg/registry/rolebinding"
|
||||
rolebindingetcd "k8s.io/kubernetes/pkg/registry/rolebinding/etcd"
|
||||
rolebindingpolicybased "k8s.io/kubernetes/pkg/registry/rolebinding/policybased"
|
||||
secretetcd "k8s.io/kubernetes/pkg/registry/secret/etcd"
|
||||
"k8s.io/kubernetes/pkg/registry/service"
|
||||
etcdallocator "k8s.io/kubernetes/pkg/registry/service/allocator/etcd"
|
||||
@ -411,6 +426,39 @@ func (m *Master) InstallAPIs(c *Config) {
|
||||
allGroups = append(allGroups, group)
|
||||
|
||||
}
|
||||
|
||||
if c.APIResourceConfigSource.AnyResourcesForVersionEnabled(rbacapi.SchemeGroupVersion) {
|
||||
rbacResources := m.getRBACResources(c)
|
||||
rbacGroupMeta := registered.GroupOrDie(rbac.GroupName)
|
||||
|
||||
// Hard code preferred group version to rbac/v1alpha1
|
||||
rbacGroupMeta.GroupVersion = rbacapi.SchemeGroupVersion
|
||||
|
||||
apiGroupInfo := genericapiserver.APIGroupInfo{
|
||||
GroupMeta: *rbacGroupMeta,
|
||||
VersionedResourcesStorageMap: map[string]map[string]rest.Storage{
|
||||
"v1alpha1": rbacResources,
|
||||
},
|
||||
OptionsExternalVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion,
|
||||
Scheme: api.Scheme,
|
||||
ParameterCodec: api.ParameterCodec,
|
||||
NegotiatedSerializer: api.Codecs,
|
||||
}
|
||||
apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo)
|
||||
|
||||
rbacGVForDiscovery := unversioned.GroupVersionForDiscovery{
|
||||
GroupVersion: rbacGroupMeta.GroupVersion.String(),
|
||||
Version: rbacGroupMeta.GroupVersion.Version,
|
||||
}
|
||||
group := unversioned.APIGroup{
|
||||
Name: rbacGroupMeta.GroupVersion.Group,
|
||||
Versions: []unversioned.GroupVersionForDiscovery{rbacGVForDiscovery},
|
||||
PreferredVersion: rbacGVForDiscovery,
|
||||
}
|
||||
allGroups = append(allGroups, group)
|
||||
|
||||
}
|
||||
|
||||
if err := m.InstallAPIGroups(apiGroupsInfo); err != nil {
|
||||
glog.Fatalf("Error in registering group versions: %v", err)
|
||||
}
|
||||
@ -908,6 +956,43 @@ func (m *Master) getAppsResources(c *Config) map[string]rest.Storage {
|
||||
return storage
|
||||
}
|
||||
|
||||
func (m *Master) getRBACResources(c *Config) map[string]rest.Storage {
|
||||
version := rbacapi.SchemeGroupVersion
|
||||
|
||||
once := new(sync.Once)
|
||||
var authorizationRuleResolver rbacvalidation.AuthorizationRuleResolver
|
||||
newRuleValidator := func() rbacvalidation.AuthorizationRuleResolver {
|
||||
once.Do(func() {
|
||||
authorizationRuleResolver = rbacvalidation.NewDefaultRuleResolver(
|
||||
role.NewRegistry(roleetcd.NewREST(m.GetRESTOptionsOrDie(c, rbac.Resource("roles")))),
|
||||
rolebinding.NewRegistry(rolebindingetcd.NewREST(m.GetRESTOptionsOrDie(c, rbac.Resource("rolebindings")))),
|
||||
clusterrole.NewRegistry(clusterroleetcd.NewREST(m.GetRESTOptionsOrDie(c, rbac.Resource("clusterroles")))),
|
||||
clusterrolebinding.NewRegistry(clusterrolebindingetcd.NewREST(m.GetRESTOptionsOrDie(c, rbac.Resource("clusterrolebindings")))),
|
||||
)
|
||||
})
|
||||
return authorizationRuleResolver
|
||||
}
|
||||
|
||||
storage := map[string]rest.Storage{}
|
||||
if c.APIResourceConfigSource.ResourceEnabled(version.WithResource("roles")) {
|
||||
rolesStorage := roleetcd.NewREST(m.GetRESTOptionsOrDie(c, rbac.Resource("roles")))
|
||||
storage["roles"] = rolepolicybased.NewStorage(rolesStorage, newRuleValidator(), c.AuthorizerRBACSuperUser)
|
||||
}
|
||||
if c.APIResourceConfigSource.ResourceEnabled(version.WithResource("rolebindings")) {
|
||||
roleBindingsStorage := rolebindingetcd.NewREST(m.GetRESTOptionsOrDie(c, rbac.Resource("rolebindings")))
|
||||
storage["rolebindings"] = rolebindingpolicybased.NewStorage(roleBindingsStorage, newRuleValidator(), c.AuthorizerRBACSuperUser)
|
||||
}
|
||||
if c.APIResourceConfigSource.ResourceEnabled(version.WithResource("clusterroles")) {
|
||||
clusterRolesStorage := clusterroleetcd.NewREST(m.GetRESTOptionsOrDie(c, rbac.Resource("clusterroles")))
|
||||
storage["clusterroles"] = clusterrolepolicybased.NewStorage(clusterRolesStorage, newRuleValidator(), c.AuthorizerRBACSuperUser)
|
||||
}
|
||||
if c.APIResourceConfigSource.ResourceEnabled(version.WithResource("clusterrolebindings")) {
|
||||
clusterRoleBindingsStorage := clusterrolebindingetcd.NewREST(m.GetRESTOptionsOrDie(c, rbac.Resource("clusterrolebindings")))
|
||||
storage["clusterrolebindings"] = clusterrolebindingpolicybased.NewStorage(clusterRoleBindingsStorage, newRuleValidator(), c.AuthorizerRBACSuperUser)
|
||||
}
|
||||
return storage
|
||||
}
|
||||
|
||||
// findExternalAddress returns ExternalIP of provided node with fallback to LegacyHostIP.
|
||||
func findExternalAddress(node *api.Node) (string, error) {
|
||||
var fallback string
|
||||
@ -960,7 +1045,7 @@ func (m *Master) IsTunnelSyncHealthy(req *http.Request) error {
|
||||
|
||||
func DefaultAPIResourceConfigSource() *genericapiserver.ResourceConfig {
|
||||
ret := genericapiserver.NewResourceConfig()
|
||||
ret.EnableVersions(apiv1.SchemeGroupVersion, extensionsapiv1beta1.SchemeGroupVersion, batchapiv1.SchemeGroupVersion, autoscalingapiv1.SchemeGroupVersion, appsapi.SchemeGroupVersion, policyapiv1alpha1.SchemeGroupVersion)
|
||||
ret.EnableVersions(apiv1.SchemeGroupVersion, extensionsapiv1beta1.SchemeGroupVersion, batchapiv1.SchemeGroupVersion, autoscalingapiv1.SchemeGroupVersion, appsapi.SchemeGroupVersion, policyapiv1alpha1.SchemeGroupVersion, rbacapi.SchemeGroupVersion)
|
||||
|
||||
// all extensions resources except these are disabled by default
|
||||
ret.EnableResources(
|
||||
|
@ -43,6 +43,7 @@ import (
|
||||
batchapiv2alpha1 "k8s.io/kubernetes/pkg/apis/batch/v2alpha1"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
extensionsapiv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||
"k8s.io/kubernetes/pkg/apiserver"
|
||||
"k8s.io/kubernetes/pkg/genericapiserver"
|
||||
"k8s.io/kubernetes/pkg/kubelet/client"
|
||||
@ -89,6 +90,7 @@ func setUp(t *testing.T) (*Master, *etcdtesting.EtcdTestServer, Config, *assert.
|
||||
resourceEncoding.SetVersionEncoding(batch.GroupName, *testapi.Batch.GroupVersion(), unversioned.GroupVersion{Group: batch.GroupName, Version: runtime.APIVersionInternal})
|
||||
resourceEncoding.SetVersionEncoding(apps.GroupName, *testapi.Apps.GroupVersion(), unversioned.GroupVersion{Group: apps.GroupName, Version: runtime.APIVersionInternal})
|
||||
resourceEncoding.SetVersionEncoding(extensions.GroupName, *testapi.Extensions.GroupVersion(), unversioned.GroupVersion{Group: extensions.GroupName, Version: runtime.APIVersionInternal})
|
||||
resourceEncoding.SetVersionEncoding(rbac.GroupName, *testapi.Rbac.GroupVersion(), unversioned.GroupVersion{Group: rbac.GroupName, Version: runtime.APIVersionInternal})
|
||||
storageFactory := genericapiserver.NewDefaultStorageFactory(storageConfig, testapi.StorageMediaType(), api.Codecs, resourceEncoding, DefaultAPIResourceConfigSource())
|
||||
|
||||
config.StorageFactory = storageFactory
|
||||
|
79
plugin/pkg/auth/authorizer/rbac/rbac.go
Normal file
79
plugin/pkg/auth/authorizer/rbac/rbac.go
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package rbac implements the authorizer.Authorizer interface using roles base access control.
|
||||
package rbac
|
||||
|
||||
import (
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||
"k8s.io/kubernetes/pkg/apis/rbac/validation"
|
||||
"k8s.io/kubernetes/pkg/auth/authorizer"
|
||||
"k8s.io/kubernetes/pkg/auth/user"
|
||||
"k8s.io/kubernetes/pkg/registry/clusterrole"
|
||||
"k8s.io/kubernetes/pkg/registry/clusterrolebinding"
|
||||
"k8s.io/kubernetes/pkg/registry/role"
|
||||
"k8s.io/kubernetes/pkg/registry/rolebinding"
|
||||
)
|
||||
|
||||
type RBACAuthorizer struct {
|
||||
superUser string
|
||||
|
||||
authorizationRuleResolver validation.AuthorizationRuleResolver
|
||||
}
|
||||
|
||||
func (r *RBACAuthorizer) Authorize(attr authorizer.Attributes) error {
|
||||
if r.superUser != "" && attr.GetUserName() == r.superUser {
|
||||
return nil
|
||||
}
|
||||
|
||||
userInfo := &user.DefaultInfo{
|
||||
Name: attr.GetUserName(),
|
||||
Groups: attr.GetGroups(),
|
||||
}
|
||||
|
||||
ctx := api.WithNamespace(api.WithUser(api.NewContext(), userInfo), attr.GetNamespace())
|
||||
|
||||
// Frame the authorization request as a privilege escalation check.
|
||||
var requestedRule rbac.PolicyRule
|
||||
if attr.IsResourceRequest() {
|
||||
requestedRule = rbac.PolicyRule{
|
||||
Verbs: []string{attr.GetVerb()},
|
||||
APIGroups: []string{attr.GetAPIGroup()}, // TODO(ericchiang): add api version here too?
|
||||
Resources: []string{attr.GetResource()},
|
||||
ResourceNames: []string{attr.GetName()},
|
||||
}
|
||||
} else {
|
||||
requestedRule = rbac.PolicyRule{
|
||||
NonResourceURLs: []string{attr.GetPath()},
|
||||
}
|
||||
}
|
||||
|
||||
return validation.ConfirmNoEscalation(ctx, r.authorizationRuleResolver, []rbac.PolicyRule{requestedRule})
|
||||
}
|
||||
|
||||
func New(roleRegistry role.Registry, roleBindingRegistry rolebinding.Registry, clusterRoleRegistry clusterrole.Registry, clusterRoleBindingRegistry clusterrolebinding.Registry, superUser string) (*RBACAuthorizer, error) {
|
||||
authorizer := &RBACAuthorizer{
|
||||
superUser: superUser,
|
||||
authorizationRuleResolver: validation.NewDefaultRuleResolver(
|
||||
roleRegistry,
|
||||
roleBindingRegistry,
|
||||
clusterRoleRegistry,
|
||||
clusterRoleBindingRegistry,
|
||||
),
|
||||
}
|
||||
return authorizer, nil
|
||||
}
|
59
plugin/pkg/auth/authorizer/rbac/rbac_test.go
Normal file
59
plugin/pkg/auth/authorizer/rbac/rbac_test.go
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package rbac
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||
"k8s.io/kubernetes/pkg/registry/clusterrole"
|
||||
clusterroleetcd "k8s.io/kubernetes/pkg/registry/clusterrole/etcd"
|
||||
"k8s.io/kubernetes/pkg/registry/clusterrolebinding"
|
||||
clusterrolebindingetcd "k8s.io/kubernetes/pkg/registry/clusterrolebinding/etcd"
|
||||
"k8s.io/kubernetes/pkg/registry/generic"
|
||||
"k8s.io/kubernetes/pkg/registry/role"
|
||||
roleetcd "k8s.io/kubernetes/pkg/registry/role/etcd"
|
||||
"k8s.io/kubernetes/pkg/registry/rolebinding"
|
||||
rolebindingetcd "k8s.io/kubernetes/pkg/registry/rolebinding/etcd"
|
||||
"k8s.io/kubernetes/pkg/storage/etcd"
|
||||
"k8s.io/kubernetes/pkg/storage/etcd/etcdtest"
|
||||
etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing"
|
||||
)
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
// NOTE(ericchiang): Can't get this strategy to do reads. Get cryptic "client: etcd cluster is unavailable or misconfigured"
|
||||
// Writes work fine, so use to test storing initial data.
|
||||
server := etcdtesting.NewEtcdTestClientServer(t)
|
||||
defer server.Terminate(t)
|
||||
|
||||
codec := testapi.Groups[rbac.GroupName].StorageCodec()
|
||||
getRESTOptions := func(resource string) generic.RESTOptions {
|
||||
cacheSize := etcdtest.DeserializationCacheSize
|
||||
storage := etcd.NewEtcdStorage(server.Client, codec, resource, false, cacheSize)
|
||||
return generic.RESTOptions{Storage: storage, Decorator: generic.UndecoratedStorage}
|
||||
}
|
||||
|
||||
roleRegistry := role.NewRegistry(roleetcd.NewREST(getRESTOptions("roles")))
|
||||
roleBindingRegistry := rolebinding.NewRegistry(rolebindingetcd.NewREST(getRESTOptions("rolebindings")))
|
||||
clusterRoleRegistry := clusterrole.NewRegistry(clusterroleetcd.NewREST(getRESTOptions("clusterroles")))
|
||||
clusterRoleBindingRegistry := clusterrolebinding.NewRegistry(clusterrolebindingetcd.NewREST(getRESTOptions("clusterrolebindings")))
|
||||
_, err := New(roleRegistry, roleBindingRegistry, clusterRoleRegistry, clusterRoleBindingRegistry, "")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create authorizer: %v", err)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user