add delegating auth options

This commit is contained in:
deads2k 2016-11-10 07:36:02 -05:00
parent 7c0e48f544
commit 5cea15ac9f
11 changed files with 606 additions and 54 deletions

View File

@ -41,7 +41,6 @@ go_library(
"//pkg/master:go_default_library", "//pkg/master:go_default_library",
"//pkg/registry/cachesize:go_default_library", "//pkg/registry/cachesize:go_default_library",
"//pkg/runtime/schema:go_default_library", "//pkg/runtime/schema:go_default_library",
"//pkg/serviceaccount:go_default_library",
"//pkg/util/errors:go_default_library", "//pkg/util/errors:go_default_library",
"//pkg/util/net:go_default_library", "//pkg/util/net:go_default_library",
"//pkg/util/wait:go_default_library", "//pkg/util/wait:go_default_library",

View File

@ -26,10 +26,9 @@ go_library(
"//pkg/api/v1:go_default_library", "//pkg/api/v1:go_default_library",
"//pkg/apis/componentconfig:go_default_library", "//pkg/apis/componentconfig:go_default_library",
"//pkg/apis/componentconfig/v1alpha1:go_default_library", "//pkg/apis/componentconfig/v1alpha1:go_default_library",
"//pkg/apiserver/authenticator:go_default_library",
"//pkg/auth/authenticator:go_default_library", "//pkg/auth/authenticator:go_default_library",
"//pkg/auth/authenticator/bearertoken:go_default_library",
"//pkg/auth/authorizer:go_default_library", "//pkg/auth/authorizer:go_default_library",
"//pkg/auth/group:go_default_library",
"//pkg/capabilities:go_default_library", "//pkg/capabilities:go_default_library",
"//pkg/client/chaosclient:go_default_library", "//pkg/client/chaosclient:go_default_library",
"//pkg/client/clientset_generated/release_1_5:go_default_library", "//pkg/client/clientset_generated/release_1_5:go_default_library",
@ -99,10 +98,6 @@ go_library(
"//pkg/volume/rbd:go_default_library", "//pkg/volume/rbd:go_default_library",
"//pkg/volume/secret:go_default_library", "//pkg/volume/secret:go_default_library",
"//pkg/volume/vsphere_volume:go_default_library", "//pkg/volume/vsphere_volume:go_default_library",
"//plugin/pkg/auth/authenticator/request/anonymous:go_default_library",
"//plugin/pkg/auth/authenticator/request/union:go_default_library",
"//plugin/pkg/auth/authenticator/request/x509:go_default_library",
"//plugin/pkg/auth/authenticator/token/webhook:go_default_library",
"//plugin/pkg/auth/authorizer/webhook:go_default_library", "//plugin/pkg/auth/authorizer/webhook:go_default_library",
"//vendor:github.com/golang/glog", "//vendor:github.com/golang/glog",
"//vendor:github.com/spf13/cobra", "//vendor:github.com/spf13/cobra",

View File

@ -22,21 +22,15 @@ import (
"reflect" "reflect"
"k8s.io/kubernetes/pkg/apis/componentconfig" "k8s.io/kubernetes/pkg/apis/componentconfig"
apiserverauthenticator "k8s.io/kubernetes/pkg/apiserver/authenticator"
"k8s.io/kubernetes/pkg/auth/authenticator" "k8s.io/kubernetes/pkg/auth/authenticator"
"k8s.io/kubernetes/pkg/auth/authenticator/bearertoken"
"k8s.io/kubernetes/pkg/auth/authorizer" "k8s.io/kubernetes/pkg/auth/authorizer"
"k8s.io/kubernetes/pkg/auth/group"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5" clientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5"
authenticationclient "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5/typed/authentication/v1beta1" authenticationclient "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5/typed/authentication/v1beta1"
authorizationclient "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5/typed/authorization/v1beta1" authorizationclient "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5/typed/authorization/v1beta1"
alwaysallowauthorizer "k8s.io/kubernetes/pkg/genericapiserver/authorizer" alwaysallowauthorizer "k8s.io/kubernetes/pkg/genericapiserver/authorizer"
"k8s.io/kubernetes/pkg/kubelet/server" "k8s.io/kubernetes/pkg/kubelet/server"
"k8s.io/kubernetes/pkg/types" "k8s.io/kubernetes/pkg/types"
"k8s.io/kubernetes/pkg/util/cert"
"k8s.io/kubernetes/plugin/pkg/auth/authenticator/request/anonymous"
unionauth "k8s.io/kubernetes/plugin/pkg/auth/authenticator/request/union"
"k8s.io/kubernetes/plugin/pkg/auth/authenticator/request/x509"
webhooktoken "k8s.io/kubernetes/plugin/pkg/auth/authenticator/token/webhook"
webhooksar "k8s.io/kubernetes/plugin/pkg/auth/authorizer/webhook" webhooksar "k8s.io/kubernetes/plugin/pkg/auth/authorizer/webhook"
) )
@ -67,43 +61,21 @@ func buildAuth(nodeName types.NodeName, client clientset.Interface, config compo
} }
func buildAuthn(client authenticationclient.TokenReviewInterface, authn componentconfig.KubeletAuthentication) (authenticator.Request, error) { func buildAuthn(client authenticationclient.TokenReviewInterface, authn componentconfig.KubeletAuthentication) (authenticator.Request, error) {
authenticators := []authenticator.Request{} authenticatorConfig := apiserverauthenticator.DelegatingAuthenticatorConfig{
Anonymous: authn.Anonymous.Enabled,
// x509 client cert auth CacheTTL: authn.Webhook.CacheTTL.Duration,
if len(authn.X509.ClientCAFile) > 0 { ClientCAFile: authn.X509.ClientCAFile,
clientCAs, err := cert.NewPool(authn.X509.ClientCAFile)
if err != nil {
return nil, fmt.Errorf("unable to load client CA file %s: %v", authn.X509.ClientCAFile, err)
}
verifyOpts := x509.DefaultVerifyOptions()
verifyOpts.Roots = clientCAs
authenticators = append(authenticators, x509.New(verifyOpts, x509.CommonNameUserConversion))
} }
// bearer token auth that uses authentication.k8s.io TokenReview to determine userinfo
if authn.Webhook.Enabled { if authn.Webhook.Enabled {
if client == nil { if client == nil {
return nil, errors.New("no client provided, cannot use webhook authentication") return nil, errors.New("no client provided, cannot use webhook authentication")
} }
tokenAuth, err := webhooktoken.NewFromInterface(client, authn.Webhook.CacheTTL.Duration) authenticatorConfig.TokenAccessReviewClient = client
if err != nil {
return nil, err
}
authenticators = append(authenticators, bearertoken.New(tokenAuth))
} }
if len(authenticators) == 0 { authenticator, _, err := authenticatorConfig.New()
if authn.Anonymous.Enabled { return authenticator, err
return anonymous.NewAuthenticator(), nil
}
return nil, errors.New("No authentication method configured")
}
authenticator := group.NewGroupAdder(unionauth.New(authenticators...), []string{"system:authenticated"})
if authn.Anonymous.Enabled {
authenticator = unionauth.NewFailOnError(authenticator, anonymous.NewAuthenticator())
}
return authenticator, nil
} }
func buildAuthz(client authorizationclient.SubjectAccessReviewInterface, authz componentconfig.KubeletAuthorization) (authorizer.Authorizer, error) { func buildAuthz(client authorizationclient.SubjectAccessReviewInterface, authz componentconfig.KubeletAuthorization) (authorizer.Authorizer, error) {

File diff suppressed because it is too large Load Diff

View File

@ -127,7 +127,7 @@ func Run(s *options.ServerRunOptions) error {
storageFactory.SetEtcdLocation(groupResource, servers) storageFactory.SetEtcdLocation(groupResource, servers)
} }
apiAuthenticator, securityDefinitions, err := authenticator.New(s.Authentication.ToAuthenticationConfig()) apiAuthenticator, securityDefinitions, err := authenticator.New(s.Authentication.ToAuthenticationConfig(s.SecureServing.ClientCA))
if err != nil { if err != nil {
glog.Fatalf("Invalid Authentication Config: %v", err) glog.Fatalf("Invalid Authentication Config: %v", err)
} }

View File

@ -32,6 +32,7 @@ auth-provider
auth-provider auth-provider
auth-provider-arg auth-provider-arg
auth-provider-arg auth-provider-arg
authentication-kubeconfig
authentication-token-webhook authentication-token-webhook
authentication-token-webhook-cache-ttl authentication-token-webhook-cache-ttl
authentication-token-webhook-config-file authentication-token-webhook-config-file

View File

@ -12,13 +12,17 @@ load(
go_library( go_library(
name = "go_default_library", name = "go_default_library",
srcs = ["authn.go"], srcs = [
"builtin.go",
"delegating.go",
],
tags = ["automanaged"], tags = ["automanaged"],
deps = [ deps = [
"//pkg/auth/authenticator:go_default_library", "//pkg/auth/authenticator:go_default_library",
"//pkg/auth/authenticator/bearertoken:go_default_library", "//pkg/auth/authenticator/bearertoken:go_default_library",
"//pkg/auth/group:go_default_library", "//pkg/auth/group:go_default_library",
"//pkg/auth/user:go_default_library", "//pkg/auth/user:go_default_library",
"//pkg/client/clientset_generated/release_1_5/typed/authentication/v1beta1:go_default_library",
"//pkg/serviceaccount:go_default_library", "//pkg/serviceaccount:go_default_library",
"//pkg/util/cert:go_default_library", "//pkg/util/cert:go_default_library",
"//plugin/pkg/auth/authenticator/password/keystone:go_default_library", "//plugin/pkg/auth/authenticator/password/keystone:go_default_library",

View File

@ -0,0 +1,97 @@
/*
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 authenticator
import (
"errors"
"fmt"
"time"
"github.com/go-openapi/spec"
"k8s.io/kubernetes/pkg/auth/authenticator"
"k8s.io/kubernetes/pkg/auth/authenticator/bearertoken"
"k8s.io/kubernetes/pkg/auth/group"
"k8s.io/kubernetes/pkg/auth/user"
authenticationclient "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5/typed/authentication/v1beta1"
"k8s.io/kubernetes/pkg/util/cert"
"k8s.io/kubernetes/plugin/pkg/auth/authenticator/request/anonymous"
unionauth "k8s.io/kubernetes/plugin/pkg/auth/authenticator/request/union"
"k8s.io/kubernetes/plugin/pkg/auth/authenticator/request/x509"
webhooktoken "k8s.io/kubernetes/plugin/pkg/auth/authenticator/token/webhook"
)
// DelegatingAuthenticatorConfig is the minimal configuration needed to create an authenticator
// built to delegate authentication to a kube API server
type DelegatingAuthenticatorConfig struct {
Anonymous bool
TokenAccessReviewClient authenticationclient.TokenReviewInterface
// CacheTTL is the length of time that a token authentication answer will be cached.
CacheTTL time.Duration
// ClientCAFile is the CA bundle file used to authenticate client certificates
ClientCAFile string
}
func (c DelegatingAuthenticatorConfig) New() (authenticator.Request, *spec.SecurityDefinitions, error) {
authenticators := []authenticator.Request{}
securityDefinitions := spec.SecurityDefinitions{}
// x509 client cert auth
if len(c.ClientCAFile) > 0 {
clientCAs, err := cert.NewPool(c.ClientCAFile)
if err != nil {
return nil, nil, fmt.Errorf("unable to load client CA file %s: %v", c.ClientCAFile, err)
}
verifyOpts := x509.DefaultVerifyOptions()
verifyOpts.Roots = clientCAs
authenticators = append(authenticators, x509.New(verifyOpts, x509.CommonNameUserConversion))
}
if c.TokenAccessReviewClient != nil {
tokenAuth, err := webhooktoken.NewFromInterface(c.TokenAccessReviewClient, c.CacheTTL)
if err != nil {
return nil, nil, err
}
authenticators = append(authenticators, bearertoken.New(tokenAuth))
securityDefinitions["BearerToken"] = &spec.SecurityScheme{
SecuritySchemeProps: spec.SecuritySchemeProps{
Type: "apiKey",
Name: "authorization",
In: "header",
Description: "Bearer Token authentication",
},
}
}
if len(authenticators) == 0 {
if c.Anonymous {
return anonymous.NewAuthenticator(), &securityDefinitions, nil
}
return nil, nil, errors.New("No authentication method configured")
}
authenticator := group.NewGroupAdder(unionauth.New(authenticators...), []string{user.AllAuthenticated})
if c.Anonymous {
authenticator = unionauth.NewFailOnError(authenticator, anonymous.NewAuthenticator())
}
return authenticator, &securityDefinitions, nil
}

View File

@ -13,7 +13,7 @@ load(
go_library( go_library(
name = "go_default_library", name = "go_default_library",
srcs = [ srcs = [
"authenticator.go", "authentication.go",
"doc.go", "doc.go",
"etcd.go", "etcd.go",
"server_run_options.go", "server_run_options.go",
@ -25,7 +25,9 @@ go_library(
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/apimachinery/registered:go_default_library", "//pkg/apimachinery/registered:go_default_library",
"//pkg/apiserver/authenticator:go_default_library", "//pkg/apiserver/authenticator:go_default_library",
"//pkg/client/clientset_generated/release_1_5/typed/authentication/v1beta1:go_default_library",
"//pkg/client/restclient:go_default_library", "//pkg/client/restclient:go_default_library",
"//pkg/client/unversioned/clientcmd:go_default_library",
"//pkg/runtime/schema:go_default_library", "//pkg/runtime/schema:go_default_library",
"//pkg/storage/storagebackend:go_default_library", "//pkg/storage/storagebackend:go_default_library",
"//pkg/util/config:go_default_library", "//pkg/util/config:go_default_library",

View File

@ -22,6 +22,8 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
"k8s.io/kubernetes/pkg/apiserver/authenticator" "k8s.io/kubernetes/pkg/apiserver/authenticator"
authenticationclient "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5/typed/authentication/v1beta1"
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
) )
type BuiltInAuthenticationOptions struct { type BuiltInAuthenticationOptions struct {
@ -243,8 +245,10 @@ func (s *BuiltInAuthenticationOptions) AddFlags(fs *pflag.FlagSet) {
} }
} }
func (s *BuiltInAuthenticationOptions) ToAuthenticationConfig() authenticator.AuthenticatorConfig { func (s *BuiltInAuthenticationOptions) ToAuthenticationConfig(clientCAFile string) authenticator.AuthenticatorConfig {
ret := authenticator.AuthenticatorConfig{} ret := authenticator.AuthenticatorConfig{
ClientCAFile: clientCAFile,
}
if s.Anonymous != nil { if s.Anonymous != nil {
ret.Anonymous = s.Anonymous.Allow ret.Anonymous = s.Anonymous.Allow
} }
@ -305,11 +309,21 @@ func (s *RequestHeaderAuthenticationOptions) AuthenticationRequestHeaderConfig()
} }
} }
// DelegatingAuthenticationOptions provides an easy way for composing API servers to delegate their authentication to
// the root kube API server
type DelegatingAuthenticationOptions struct { type DelegatingAuthenticationOptions struct {
// RemoteKubeConfigFile is the file to use to connect to a "normal" kube API server which hosts the
// TokenAcessReview.authentication.k8s.io endpoint for checking tokens.
RemoteKubeConfigFile string
// CacheTTL is the length of time that a token authentication answer will be cached.
CacheTTL time.Duration
} }
func NewDelegatingAuthenticationOptions() *DelegatingAuthenticationOptions { func NewDelegatingAuthenticationOptions() *DelegatingAuthenticationOptions {
return &DelegatingAuthenticationOptions{} return &DelegatingAuthenticationOptions{
CacheTTL: 5 * time.Minute,
}
} }
func (s *DelegatingAuthenticationOptions) Validate() []error { func (s *DelegatingAuthenticationOptions) Validate() []error {
@ -318,4 +332,44 @@ func (s *DelegatingAuthenticationOptions) Validate() []error {
} }
func (s *DelegatingAuthenticationOptions) AddFlags(fs *pflag.FlagSet) { func (s *DelegatingAuthenticationOptions) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&s.RemoteKubeConfigFile, "authentication-kubeconfig", s.RemoteKubeConfigFile, ""+
"kubeconfig file pointing at the 'core' kubernetes server with enough rights to create "+
" tokenaccessreviews.authencation.k8s.io.")
}
func (s *DelegatingAuthenticationOptions) ToAuthenticationConfig(clientCAFile string) (authenticator.DelegatingAuthenticatorConfig, error) {
tokenClient, err := s.newTokenAccessReview()
if err != nil {
return authenticator.DelegatingAuthenticatorConfig{}, err
}
ret := authenticator.DelegatingAuthenticatorConfig{
Anonymous: true,
TokenAccessReviewClient: tokenClient,
CacheTTL: s.CacheTTL,
ClientCAFile: clientCAFile,
}
return ret, nil
}
func (s *DelegatingAuthenticationOptions) newTokenAccessReview() (authenticationclient.TokenReviewInterface, error) {
if len(s.RemoteKubeConfigFile) == 0 {
return nil, nil
}
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
loadingRules.ExplicitPath = s.RemoteKubeConfigFile
loader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{})
clientConfig, err := loader.ClientConfig()
if err != nil {
return nil, err
}
client, err := authenticationclient.NewForConfig(clientConfig)
if err != nil {
return nil, err
}
return client.TokenReviews(), nil
} }