mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 11:50:44 +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"
|
kubeletclient "k8s.io/kubernetes/pkg/kubelet/client"
|
||||||
"k8s.io/kubernetes/pkg/master"
|
"k8s.io/kubernetes/pkg/master"
|
||||||
"k8s.io/kubernetes/pkg/registry/cachesize"
|
"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"
|
"k8s.io/kubernetes/pkg/serviceaccount"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -198,6 +207,32 @@ func Run(s *options.APIServer) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
authorizationModeNames := strings.Split(s.AuthorizationMode, ",")
|
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)
|
authorizer, err := apiserver.NewAuthorizerFromAuthorizationConfig(authorizationModeNames, s.AuthorizationConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("Invalid Authorization Config: %v", err)
|
glog.Fatalf("Invalid Authorization Config: %v", err)
|
||||||
@ -216,6 +251,7 @@ func Run(s *options.APIServer) error {
|
|||||||
genericConfig.Authenticator = authenticator
|
genericConfig.Authenticator = authenticator
|
||||||
genericConfig.SupportsBasicAuth = len(s.BasicAuthFile) > 0
|
genericConfig.SupportsBasicAuth = len(s.BasicAuthFile) > 0
|
||||||
genericConfig.Authorizer = authorizer
|
genericConfig.Authorizer = authorizer
|
||||||
|
genericConfig.AuthorizerRBACSuperUser = s.AuthorizationConfig.RBACSuperUser
|
||||||
genericConfig.AdmissionControl = admissionController
|
genericConfig.AdmissionControl = admissionController
|
||||||
genericConfig.APIResourceConfigSource = storageFactory.APIResourceConfigSource
|
genericConfig.APIResourceConfigSource = storageFactory.APIResourceConfigSource
|
||||||
genericConfig.MasterServiceNamespace = s.MasterServiceNamespace
|
genericConfig.MasterServiceNamespace = s.MasterServiceNamespace
|
||||||
|
@ -22,6 +22,7 @@ authentication-token-webhook-cache-ttl
|
|||||||
authentication-token-webhook-config-file
|
authentication-token-webhook-config-file
|
||||||
authorization-mode
|
authorization-mode
|
||||||
authorization-policy-file
|
authorization-policy-file
|
||||||
|
authorization-rbac-super-user
|
||||||
authorization-webhook-config-file
|
authorization-webhook-config-file
|
||||||
authorization-webhook-cache-authorized-ttl
|
authorization-webhook-cache-authorized-ttl
|
||||||
authorization-webhook-cache-unauthorized-ttl
|
authorization-webhook-cache-unauthorized-ttl
|
||||||
|
@ -24,6 +24,11 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/auth/authorizer"
|
"k8s.io/kubernetes/pkg/auth/authorizer"
|
||||||
"k8s.io/kubernetes/pkg/auth/authorizer/abac"
|
"k8s.io/kubernetes/pkg/auth/authorizer/abac"
|
||||||
"k8s.io/kubernetes/pkg/auth/authorizer/union"
|
"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"
|
"k8s.io/kubernetes/plugin/pkg/auth/authorizer/webhook"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -63,10 +68,11 @@ const (
|
|||||||
ModeAlwaysDeny string = "AlwaysDeny"
|
ModeAlwaysDeny string = "AlwaysDeny"
|
||||||
ModeABAC string = "ABAC"
|
ModeABAC string = "ABAC"
|
||||||
ModeWebhook string = "Webhook"
|
ModeWebhook string = "Webhook"
|
||||||
|
ModeRBAC string = "RBAC"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Keep this list in sync with constant list above.
|
// 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 {
|
type AuthorizationConfig struct {
|
||||||
// Options for ModeABAC
|
// Options for ModeABAC
|
||||||
@ -82,6 +88,16 @@ type AuthorizationConfig struct {
|
|||||||
WebhookCacheAuthorizedTTL time.Duration
|
WebhookCacheAuthorizedTTL time.Duration
|
||||||
// TTL for caching of unauthorized responses from the webhook server.
|
// TTL for caching of unauthorized responses from the webhook server.
|
||||||
WebhookCacheUnauthorizedTTL time.Duration
|
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
|
// 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
|
return nil, err
|
||||||
}
|
}
|
||||||
authorizers = append(authorizers, webhookAuthorizer)
|
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:
|
default:
|
||||||
return nil, fmt.Errorf("Unknown authorization mode %s specified", authorizationMode)
|
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 != "" {
|
if !authorizerMap[ModeWebhook] && config.WebhookConfigFile != "" {
|
||||||
return nil, errors.New("Cannot specify --authorization-webhook-config-file without mode Webhook")
|
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
|
return union.New(authorizers...), nil
|
||||||
}
|
}
|
||||||
|
@ -118,6 +118,8 @@ type Config struct {
|
|||||||
Authorizer authorizer.Authorizer
|
Authorizer authorizer.Authorizer
|
||||||
AdmissionControl admission.Interface
|
AdmissionControl admission.Interface
|
||||||
MasterServiceNamespace string
|
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
|
// Map requests to contexts. Exported so downstream consumers can provider their own mappers
|
||||||
RequestContextMapper api.RequestContextMapper
|
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.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.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.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.")
|
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/componentconfig/install"
|
||||||
_ "k8s.io/kubernetes/pkg/apis/extensions/install"
|
_ "k8s.io/kubernetes/pkg/apis/extensions/install"
|
||||||
_ "k8s.io/kubernetes/pkg/apis/policy/install"
|
_ "k8s.io/kubernetes/pkg/apis/policy/install"
|
||||||
|
_ "k8s.io/kubernetes/pkg/apis/rbac/install"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -43,12 +43,21 @@ import (
|
|||||||
extensionsapiv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
extensionsapiv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||||
"k8s.io/kubernetes/pkg/apis/policy"
|
"k8s.io/kubernetes/pkg/apis/policy"
|
||||||
policyapiv1alpha1 "k8s.io/kubernetes/pkg/apis/policy/v1alpha1"
|
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"
|
"k8s.io/kubernetes/pkg/apiserver"
|
||||||
apiservermetrics "k8s.io/kubernetes/pkg/apiserver/metrics"
|
apiservermetrics "k8s.io/kubernetes/pkg/apiserver/metrics"
|
||||||
"k8s.io/kubernetes/pkg/genericapiserver"
|
"k8s.io/kubernetes/pkg/genericapiserver"
|
||||||
"k8s.io/kubernetes/pkg/healthz"
|
"k8s.io/kubernetes/pkg/healthz"
|
||||||
kubeletclient "k8s.io/kubernetes/pkg/kubelet/client"
|
kubeletclient "k8s.io/kubernetes/pkg/kubelet/client"
|
||||||
"k8s.io/kubernetes/pkg/master/ports"
|
"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"
|
"k8s.io/kubernetes/pkg/registry/componentstatus"
|
||||||
configmapetcd "k8s.io/kubernetes/pkg/registry/configmap/etcd"
|
configmapetcd "k8s.io/kubernetes/pkg/registry/configmap/etcd"
|
||||||
controlleretcd "k8s.io/kubernetes/pkg/registry/controller/etcd"
|
controlleretcd "k8s.io/kubernetes/pkg/registry/controller/etcd"
|
||||||
@ -75,6 +84,12 @@ import (
|
|||||||
podtemplateetcd "k8s.io/kubernetes/pkg/registry/podtemplate/etcd"
|
podtemplateetcd "k8s.io/kubernetes/pkg/registry/podtemplate/etcd"
|
||||||
replicasetetcd "k8s.io/kubernetes/pkg/registry/replicaset/etcd"
|
replicasetetcd "k8s.io/kubernetes/pkg/registry/replicaset/etcd"
|
||||||
resourcequotaetcd "k8s.io/kubernetes/pkg/registry/resourcequota/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"
|
secretetcd "k8s.io/kubernetes/pkg/registry/secret/etcd"
|
||||||
"k8s.io/kubernetes/pkg/registry/service"
|
"k8s.io/kubernetes/pkg/registry/service"
|
||||||
etcdallocator "k8s.io/kubernetes/pkg/registry/service/allocator/etcd"
|
etcdallocator "k8s.io/kubernetes/pkg/registry/service/allocator/etcd"
|
||||||
@ -411,6 +426,39 @@ func (m *Master) InstallAPIs(c *Config) {
|
|||||||
allGroups = append(allGroups, group)
|
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 {
|
if err := m.InstallAPIGroups(apiGroupsInfo); err != nil {
|
||||||
glog.Fatalf("Error in registering group versions: %v", err)
|
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
|
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.
|
// findExternalAddress returns ExternalIP of provided node with fallback to LegacyHostIP.
|
||||||
func findExternalAddress(node *api.Node) (string, error) {
|
func findExternalAddress(node *api.Node) (string, error) {
|
||||||
var fallback string
|
var fallback string
|
||||||
@ -960,7 +1045,7 @@ func (m *Master) IsTunnelSyncHealthy(req *http.Request) error {
|
|||||||
|
|
||||||
func DefaultAPIResourceConfigSource() *genericapiserver.ResourceConfig {
|
func DefaultAPIResourceConfigSource() *genericapiserver.ResourceConfig {
|
||||||
ret := genericapiserver.NewResourceConfig()
|
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
|
// all extensions resources except these are disabled by default
|
||||||
ret.EnableResources(
|
ret.EnableResources(
|
||||||
|
@ -43,6 +43,7 @@ import (
|
|||||||
batchapiv2alpha1 "k8s.io/kubernetes/pkg/apis/batch/v2alpha1"
|
batchapiv2alpha1 "k8s.io/kubernetes/pkg/apis/batch/v2alpha1"
|
||||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
extensionsapiv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
extensionsapiv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||||
|
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||||
"k8s.io/kubernetes/pkg/apiserver"
|
"k8s.io/kubernetes/pkg/apiserver"
|
||||||
"k8s.io/kubernetes/pkg/genericapiserver"
|
"k8s.io/kubernetes/pkg/genericapiserver"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/client"
|
"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(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(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(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())
|
storageFactory := genericapiserver.NewDefaultStorageFactory(storageConfig, testapi.StorageMediaType(), api.Codecs, resourceEncoding, DefaultAPIResourceConfigSource())
|
||||||
|
|
||||||
config.StorageFactory = storageFactory
|
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