split authorization from main options struct

pull/6/head
deads2k 2016-11-10 09:15:50 -05:00
parent 5cea15ac9f
commit ca2b5f136e
10 changed files with 147 additions and 97 deletions

View File

@ -36,6 +36,7 @@ type ServerRunOptions struct {
SecureServing *genericoptions.SecureServingOptions
InsecureServing *genericoptions.ServingOptions
Authentication *genericoptions.BuiltInAuthenticationOptions
Authorization *genericoptions.BuiltInAuthorizationOptions
AllowPrivileged bool
EventTTL time.Duration
@ -53,6 +54,7 @@ func NewServerRunOptions() *ServerRunOptions {
SecureServing: genericoptions.NewSecureServingOptions(),
InsecureServing: genericoptions.NewInsecureServingOptions(),
Authentication: genericoptions.NewBuiltInAuthenticationOptions().WithAll(),
Authorization: genericoptions.NewBuiltInAuthorizationOptions(),
EventTTL: 1 * time.Hour,
KubeletConfig: kubeletclient.KubeletClientConfig{
@ -81,6 +83,7 @@ func (s *ServerRunOptions) AddFlags(fs *pflag.FlagSet) {
s.InsecureServing.AddFlags(fs)
s.InsecureServing.AddDeprecatedFlags(fs)
s.Authentication.AddFlags(fs)
s.Authorization.AddFlags(fs)
// Note: the weird ""+ in below lines seems to be the only way to get gofmt to
// arrange these text blocks sensibly. Grrr.

View File

@ -94,6 +94,7 @@ func Run(s *options.ServerRunOptions) error {
ApplySecureServingOptions(s.SecureServing).
ApplyInsecureServingOptions(s.InsecureServing).
ApplyAuthenticationOptions(s.Authentication).
ApplyRBACSuperUser(s.Authorization.RBACSuperUser).
Complete() // set default values based on the known values
serviceIPRange, apiServerServiceIP, err := genericapiserver.DefaultServiceIPRange(s.GenericServerRunOptions.ServiceClusterIPRange)
@ -245,16 +246,8 @@ func Run(s *options.ServerRunOptions) error {
}
sharedInformers := informers.NewSharedInformerFactory(nil, client, 10*time.Minute)
authorizationConfig := authorizer.AuthorizationConfig{
PolicyFile: s.GenericServerRunOptions.AuthorizationPolicyFile,
WebhookConfigFile: s.GenericServerRunOptions.AuthorizationWebhookConfigFile,
WebhookCacheAuthorizedTTL: s.GenericServerRunOptions.AuthorizationWebhookCacheAuthorizedTTL,
WebhookCacheUnauthorizedTTL: s.GenericServerRunOptions.AuthorizationWebhookCacheUnauthorizedTTL,
RBACSuperUser: s.GenericServerRunOptions.AuthorizationRBACSuperUser,
InformerFactory: sharedInformers,
}
authorizationModeNames := strings.Split(s.GenericServerRunOptions.AuthorizationMode, ",")
apiAuthorizer, err := authorizer.NewAuthorizerFromAuthorizationConfig(authorizationModeNames, authorizationConfig)
authorizerconfig := s.Authorization.ToAuthorizationConfig(sharedInformers)
apiAuthorizer, err := authorizer.NewAuthorizerFromAuthorizationConfig(authorizerconfig)
if err != nil {
glog.Fatalf("Invalid Authorization Config: %v", err)
}

View File

@ -32,6 +32,7 @@ type ServerRunOptions struct {
SecureServing *genericoptions.SecureServingOptions
InsecureServing *genericoptions.ServingOptions
Authentication *genericoptions.BuiltInAuthenticationOptions
Authorization *genericoptions.BuiltInAuthorizationOptions
EventTTL time.Duration
}
@ -44,6 +45,7 @@ func NewServerRunOptions() *ServerRunOptions {
SecureServing: genericoptions.NewSecureServingOptions(),
InsecureServing: genericoptions.NewInsecureServingOptions(),
Authentication: genericoptions.NewBuiltInAuthenticationOptions().WithAll(),
Authorization: genericoptions.NewBuiltInAuthorizationOptions(),
EventTTL: 1 * time.Hour,
}
@ -58,6 +60,7 @@ func (s *ServerRunOptions) AddFlags(fs *pflag.FlagSet) {
s.SecureServing.AddFlags(fs)
s.InsecureServing.AddFlags(fs)
s.Authentication.AddFlags(fs)
s.Authorization.AddFlags(fs)
fs.DurationVar(&s.EventTTL, "event-ttl", s.EventTTL,
"Amount of time to retain events. Default is 1h.")

View File

@ -82,6 +82,7 @@ func Run(s *options.ServerRunOptions) error {
ApplySecureServingOptions(s.SecureServing).
ApplyInsecureServingOptions(s.InsecureServing).
ApplyAuthenticationOptions(s.Authentication).
ApplyRBACSuperUser(s.Authorization.RBACSuperUser).
Complete() // set default values based on the known values
if err := genericConfig.MaybeGenerateServingCerts(); err != nil {
@ -143,16 +144,8 @@ func Run(s *options.ServerRunOptions) error {
}
sharedInformers := informers.NewSharedInformerFactory(nil, client, 10*time.Minute)
authorizationConfig := authorizer.AuthorizationConfig{
PolicyFile: s.GenericServerRunOptions.AuthorizationPolicyFile,
WebhookConfigFile: s.GenericServerRunOptions.AuthorizationWebhookConfigFile,
WebhookCacheAuthorizedTTL: s.GenericServerRunOptions.AuthorizationWebhookCacheAuthorizedTTL,
WebhookCacheUnauthorizedTTL: s.GenericServerRunOptions.AuthorizationWebhookCacheUnauthorizedTTL,
RBACSuperUser: s.GenericServerRunOptions.AuthorizationRBACSuperUser,
InformerFactory: sharedInformers,
}
authorizationModeNames := strings.Split(s.GenericServerRunOptions.AuthorizationMode, ",")
apiAuthorizer, err := authorizer.NewAuthorizerFromAuthorizationConfig(authorizationModeNames, authorizationConfig)
authorizerconfig := s.Authorization.ToAuthorizationConfig(sharedInformers)
apiAuthorizer, err := authorizer.NewAuthorizerFromAuthorizationConfig(authorizerconfig)
if err != nil {
glog.Fatalf("Invalid Authorization Config: %v", err)
}

View File

@ -19,7 +19,6 @@ go_library(
"//pkg/auth/authorizer/abac:go_default_library",
"//pkg/auth/authorizer/union:go_default_library",
"//pkg/controller/informers:go_default_library",
"//pkg/genericapiserver/options:go_default_library",
"//plugin/pkg/auth/authorizer/rbac:go_default_library",
"//plugin/pkg/auth/authorizer/webhook:go_default_library",
],

View File

@ -25,11 +25,18 @@ import (
"k8s.io/kubernetes/pkg/auth/authorizer/abac"
"k8s.io/kubernetes/pkg/auth/authorizer/union"
"k8s.io/kubernetes/pkg/controller/informers"
"k8s.io/kubernetes/pkg/genericapiserver/options"
"k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac"
"k8s.io/kubernetes/plugin/pkg/auth/authorizer/webhook"
)
const (
ModeAlwaysAllow string = "AlwaysAllow"
ModeAlwaysDeny string = "AlwaysDeny"
ModeABAC string = "ABAC"
ModeWebhook string = "Webhook"
ModeRBAC string = "RBAC"
)
// alwaysAllowAuthorizer is an implementation of authorizer.Attributes
// which always says yes to an authorization request.
// It is useful in tests and when using kubernetes in an open manner.
@ -95,6 +102,8 @@ func NewPrivilegedGroups(groups ...string) *privilegedGroupAuthorizer {
}
type AuthorizationConfig struct {
AuthorizationModes []string
// Options for ModeABAC
// Path to an ABAC policy file.
@ -118,28 +127,27 @@ type AuthorizationConfig struct {
}
// NewAuthorizerFromAuthorizationConfig returns the right sort of union of multiple authorizer.Authorizer objects
// based on the authorizationMode or an error. authorizationMode should be a comma separated values
// of options.AuthorizationModeChoices.
func NewAuthorizerFromAuthorizationConfig(authorizationModes []string, config AuthorizationConfig) (authorizer.Authorizer, error) {
// based on the authorizationMode or an error.
func NewAuthorizerFromAuthorizationConfig(config AuthorizationConfig) (authorizer.Authorizer, error) {
if len(authorizationModes) == 0 {
if len(config.AuthorizationModes) == 0 {
return nil, errors.New("At least one authorization mode should be passed")
}
var authorizers []authorizer.Authorizer
authorizerMap := make(map[string]bool)
for _, authorizationMode := range authorizationModes {
for _, authorizationMode := range config.AuthorizationModes {
if authorizerMap[authorizationMode] {
return nil, fmt.Errorf("Authorization mode %s specified more than once", authorizationMode)
}
// Keep cases in sync with constant list above.
switch authorizationMode {
case options.ModeAlwaysAllow:
case ModeAlwaysAllow:
authorizers = append(authorizers, NewAlwaysAllowAuthorizer())
case options.ModeAlwaysDeny:
case ModeAlwaysDeny:
authorizers = append(authorizers, NewAlwaysDenyAuthorizer())
case options.ModeABAC:
case ModeABAC:
if config.PolicyFile == "" {
return nil, errors.New("ABAC's authorization policy file not passed")
}
@ -148,7 +156,7 @@ func NewAuthorizerFromAuthorizationConfig(authorizationModes []string, config Au
return nil, err
}
authorizers = append(authorizers, abacAuthorizer)
case options.ModeWebhook:
case ModeWebhook:
if config.WebhookConfigFile == "" {
return nil, errors.New("Webhook's configuration file not passed")
}
@ -159,7 +167,7 @@ func NewAuthorizerFromAuthorizationConfig(authorizationModes []string, config Au
return nil, err
}
authorizers = append(authorizers, webhookAuthorizer)
case options.ModeRBAC:
case ModeRBAC:
rbacAuthorizer := rbac.New(
config.InformerFactory.Roles().Lister(),
config.InformerFactory.RoleBindings().Lister(),
@ -174,13 +182,13 @@ func NewAuthorizerFromAuthorizationConfig(authorizationModes []string, config Au
authorizerMap[authorizationMode] = true
}
if !authorizerMap[options.ModeABAC] && config.PolicyFile != "" {
if !authorizerMap[ModeABAC] && config.PolicyFile != "" {
return nil, errors.New("Cannot specify --authorization-policy-file without mode ABAC")
}
if !authorizerMap[options.ModeWebhook] && config.WebhookConfigFile != "" {
if !authorizerMap[ModeWebhook] && config.WebhookConfigFile != "" {
return nil, errors.New("Cannot specify --authorization-webhook-config-file without mode Webhook")
}
if !authorizerMap[options.ModeRBAC] && config.RBACSuperUser != "" {
if !authorizerMap[ModeRBAC] && config.RBACSuperUser != "" {
return nil, errors.New("Cannot specify --authorization-rbac-super-user without mode RBAC")
}

View File

@ -291,6 +291,11 @@ func (c *Config) ApplyAuthenticationOptions(o *options.BuiltInAuthenticationOpti
return c
}
func (c *Config) ApplyRBACSuperUser(rbacSuperUser string) *Config {
c.AuthorizerRBACSuperUser = rbacSuperUser
return c
}
// ApplyOptions applies the run options to the method receiver and returns self
func (c *Config) ApplyOptions(options *options.ServerRunOptions) *Config {
if len(options.AuditLogPath) != 0 {
@ -302,7 +307,6 @@ func (c *Config) ApplyOptions(options *options.ServerRunOptions) *Config {
}
}
c.AuthorizerRBACSuperUser = options.AuthorizationRBACSuperUser
c.CorsAllowedOriginList = options.CorsAllowedOriginList
c.EnableGarbageCollection = options.EnableGarbageCollection
c.EnableProfiling = options.EnableProfiling

View File

@ -14,6 +14,7 @@ go_library(
name = "go_default_library",
srcs = [
"authentication.go",
"authorization.go",
"doc.go",
"etcd.go",
"server_run_options.go",
@ -28,6 +29,8 @@ go_library(
"//pkg/client/clientset_generated/release_1_5/typed/authentication/v1beta1:go_default_library",
"//pkg/client/restclient:go_default_library",
"//pkg/client/unversioned/clientcmd:go_default_library",
"//pkg/controller/informers:go_default_library",
"//pkg/genericapiserver/authorizer:go_default_library",
"//pkg/runtime/schema:go_default_library",
"//pkg/storage/storagebackend:go_default_library",
"//pkg/util/config:go_default_library",

View File

@ -0,0 +1,89 @@
/*
Copyright 2016 The Kubernetes Authors.
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 options
import (
"strings"
"time"
"github.com/spf13/pflag"
"k8s.io/kubernetes/pkg/controller/informers"
"k8s.io/kubernetes/pkg/genericapiserver/authorizer"
)
var AuthorizationModeChoices = []string{authorizer.ModeAlwaysAllow, authorizer.ModeAlwaysDeny, authorizer.ModeABAC, authorizer.ModeWebhook, authorizer.ModeRBAC}
type BuiltInAuthorizationOptions struct {
Mode string
PolicyFile string
WebhookConfigFile string
WebhookCacheAuthorizedTTL time.Duration
WebhookCacheUnauthorizedTTL time.Duration
RBACSuperUser string
}
func NewBuiltInAuthorizationOptions() *BuiltInAuthorizationOptions {
return &BuiltInAuthorizationOptions{
Mode: "AlwaysAllow",
WebhookCacheAuthorizedTTL: 5 * time.Minute,
WebhookCacheUnauthorizedTTL: 30 * time.Second,
}
}
func (s *BuiltInAuthorizationOptions) Validate() []error {
allErrors := []error{}
return allErrors
}
func (s *BuiltInAuthorizationOptions) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&s.Mode, "authorization-mode", s.Mode, ""+
"Ordered list of plug-ins to do authorization on secure port. Comma-delimited list of: "+
strings.Join(AuthorizationModeChoices, ",")+".")
fs.StringVar(&s.PolicyFile, "authorization-policy-file", s.PolicyFile, ""+
"File with authorization policy in csv format, used with --authorization-mode=ABAC, on the secure port.")
fs.StringVar(&s.WebhookConfigFile, "authorization-webhook-config-file", s.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.WebhookCacheAuthorizedTTL, "authorization-webhook-cache-authorized-ttl",
s.WebhookCacheAuthorizedTTL,
"The duration to cache 'authorized' responses from the webhook authorizer. Default is 5m.")
fs.DurationVar(&s.WebhookCacheUnauthorizedTTL,
"authorization-webhook-cache-unauthorized-ttl", s.WebhookCacheUnauthorizedTTL,
"The duration to cache 'unauthorized' responses from the webhook authorizer. Default is 30s.")
fs.StringVar(&s.RBACSuperUser, "authorization-rbac-super-user", s.RBACSuperUser, ""+
"If specified, a username which avoids RBAC authorization checks and role binding "+
"privilege escalation checks, to be used with --authorization-mode=RBAC.")
}
func (s *BuiltInAuthorizationOptions) ToAuthorizationConfig(informerFactory informers.SharedInformerFactory) authorizer.AuthorizationConfig {
return authorizer.AuthorizationConfig{
AuthorizationModes: strings.Split(s.Mode, ","),
PolicyFile: s.PolicyFile,
WebhookConfigFile: s.WebhookConfigFile,
WebhookCacheAuthorizedTTL: s.WebhookCacheAuthorizedTTL,
WebhookCacheUnauthorizedTTL: s.WebhookCacheUnauthorizedTTL,
RBACSuperUser: s.RBACSuperUser,
InformerFactory: informerFactory,
}
}

View File

@ -20,7 +20,6 @@ import (
"fmt"
"net"
"strings"
"time"
"k8s.io/kubernetes/pkg/admission"
"k8s.io/kubernetes/pkg/api"
@ -39,30 +38,12 @@ const (
var DefaultServiceNodePortRange = utilnet.PortRange{Base: 30000, Size: 2768}
const (
ModeAlwaysAllow string = "AlwaysAllow"
ModeAlwaysDeny string = "AlwaysDeny"
ModeABAC string = "ABAC"
ModeWebhook string = "Webhook"
ModeRBAC string = "RBAC"
)
var AuthorizationModeChoices = []string{ModeAlwaysAllow, ModeAlwaysDeny, ModeABAC, ModeWebhook, ModeRBAC}
// ServerRunOptions contains the options while running a generic api server.
type ServerRunOptions struct {
AdmissionControl string
AdmissionControlConfigFile string
AdvertiseAddress net.IP
// Authorization mode and associated flags.
AuthorizationMode string
AuthorizationPolicyFile string
AuthorizationWebhookConfigFile string
AuthorizationWebhookCacheAuthorizedTTL time.Duration
AuthorizationWebhookCacheUnauthorizedTTL time.Duration
AuthorizationRBACSuperUser string
CloudConfigFile string
CloudProvider string
CorsAllowedOriginList []string
@ -99,25 +80,22 @@ type ServerRunOptions struct {
func NewServerRunOptions() *ServerRunOptions {
return &ServerRunOptions{
AdmissionControl: "AlwaysAdmit",
AuthorizationMode: "AlwaysAllow",
AuthorizationWebhookCacheAuthorizedTTL: 5 * time.Minute,
AuthorizationWebhookCacheUnauthorizedTTL: 30 * time.Second,
DefaultStorageMediaType: "application/json",
DefaultStorageVersions: registered.AllPreferredGroupVersions(),
DeleteCollectionWorkers: 1,
EnableGarbageCollection: true,
EnableProfiling: true,
EnableContentionProfiling: false,
EnableWatchCache: true,
LongRunningRequestRE: DefaultLongRunningRequestRE,
MasterCount: 1,
MasterServiceNamespace: api.NamespaceDefault,
MaxRequestsInFlight: 400,
MinRequestTimeout: 1800,
RuntimeConfig: make(config.ConfigurationMap),
ServiceNodePortRange: DefaultServiceNodePortRange,
StorageVersions: registered.AllPreferredGroupVersions(),
AdmissionControl: "AlwaysAdmit",
DefaultStorageMediaType: "application/json",
DefaultStorageVersions: registered.AllPreferredGroupVersions(),
DeleteCollectionWorkers: 1,
EnableGarbageCollection: true,
EnableProfiling: true,
EnableContentionProfiling: false,
EnableWatchCache: true,
LongRunningRequestRE: DefaultLongRunningRequestRE,
MasterCount: 1,
MasterServiceNamespace: api.NamespaceDefault,
MaxRequestsInFlight: 400,
MinRequestTimeout: 1800,
RuntimeConfig: make(config.ConfigurationMap),
ServiceNodePortRange: DefaultServiceNodePortRange,
StorageVersions: registered.AllPreferredGroupVersions(),
}
}
@ -209,29 +187,6 @@ func (s *ServerRunOptions) AddUniversalFlags(fs *pflag.FlagSet) {
"will be used. If --bind-address is unspecified, the host's default interface will "+
"be used.")
fs.StringVar(&s.AuthorizationMode, "authorization-mode", s.AuthorizationMode, ""+
"Ordered list of plug-ins to do authorization on secure port. Comma-delimited list of: "+
strings.Join(AuthorizationModeChoices, ",")+".")
fs.StringVar(&s.AuthorizationPolicyFile, "authorization-policy-file", s.AuthorizationPolicyFile, ""+
"File with authorization policy in csv format, used with --authorization-mode=ABAC, on the secure port.")
fs.StringVar(&s.AuthorizationWebhookConfigFile, "authorization-webhook-config-file", s.AuthorizationWebhookConfigFile, ""+
"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.AuthorizationWebhookCacheAuthorizedTTL, "authorization-webhook-cache-authorized-ttl",
s.AuthorizationWebhookCacheAuthorizedTTL,
"The duration to cache 'authorized' responses from the webhook authorizer. Default is 5m.")
fs.DurationVar(&s.AuthorizationWebhookCacheUnauthorizedTTL,
"authorization-webhook-cache-unauthorized-ttl", s.AuthorizationWebhookCacheUnauthorizedTTL,
"The duration to cache 'unauthorized' responses from the webhook authorizer. Default is 30s.")
fs.StringVar(&s.AuthorizationRBACSuperUser, "authorization-rbac-super-user", s.AuthorizationRBACSuperUser, ""+
"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.CloudProvider, "cloud-provider", s.CloudProvider,
"The provider for cloud services. Empty string for no provider.")