Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
a0df658b
Commit
a0df658b
authored
Feb 16, 2017
by
Eric Chiang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
kube-apiserver: add a bootstrap token authenticator for TLS bootstrapping
parent
7a06e41f
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
526 additions
and
10 deletions
+526
-10
BUILD
cmd/kube-apiserver/app/BUILD
+3
-0
server.go
cmd/kube-apiserver/app/server.go
+23
-5
.linted_packages
hack/.linted_packages
+1
-0
known-flags.txt
hack/verify-flags/known-flags.txt
+1
-0
types.go
pkg/bootstrap/api/types.go
+18
-4
config.go
pkg/kubeapiserver/authenticator/config.go
+10
-1
authentication.go
pkg/kubeapiserver/options/authentication.go
+21
-0
BUILD
plugin/pkg/auth/BUILD
+1
-0
BUILD
plugin/pkg/auth/authenticator/token/bootstrap/BUILD
+52
-0
bootstrap.go
plugin/pkg/auth/authenticator/token/bootstrap/bootstrap.go
+168
-0
bootstrap_test.go
.../pkg/auth/authenticator/token/bootstrap/bootstrap_test.go
+228
-0
No files found.
cmd/kube-apiserver/app/BUILD
View file @
a0df658b
...
@@ -20,6 +20,7 @@ go_library(
...
@@ -20,6 +20,7 @@ go_library(
"//pkg/apis/batch:go_default_library",
"//pkg/apis/batch:go_default_library",
"//pkg/capabilities:go_default_library",
"//pkg/capabilities:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/client/informers/informers_generated/internalversion:go_default_library",
"//pkg/cloudprovider:go_default_library",
"//pkg/cloudprovider:go_default_library",
"//pkg/cloudprovider/providers:go_default_library",
"//pkg/cloudprovider/providers:go_default_library",
"//pkg/controller/informers:go_default_library",
"//pkg/controller/informers:go_default_library",
...
@@ -51,10 +52,12 @@ go_library(
...
@@ -51,10 +52,12 @@ go_library(
"//plugin/pkg/admission/securitycontext/scdeny:go_default_library",
"//plugin/pkg/admission/securitycontext/scdeny:go_default_library",
"//plugin/pkg/admission/serviceaccount:go_default_library",
"//plugin/pkg/admission/serviceaccount:go_default_library",
"//plugin/pkg/admission/storageclass/default:go_default_library",
"//plugin/pkg/admission/storageclass/default:go_default_library",
"//plugin/pkg/auth/authenticator/token/bootstrap:go_default_library",
"//vendor:github.com/go-openapi/spec",
"//vendor:github.com/go-openapi/spec",
"//vendor:github.com/golang/glog",
"//vendor:github.com/golang/glog",
"//vendor:github.com/spf13/cobra",
"//vendor:github.com/spf13/cobra",
"//vendor:github.com/spf13/pflag",
"//vendor:github.com/spf13/pflag",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
"//vendor:k8s.io/apimachinery/pkg/openapi",
"//vendor:k8s.io/apimachinery/pkg/openapi",
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
"//vendor:k8s.io/apimachinery/pkg/util/errors",
"//vendor:k8s.io/apimachinery/pkg/util/errors",
...
...
cmd/kube-apiserver/app/server.go
View file @
a0df658b
...
@@ -35,6 +35,7 @@ import (
...
@@ -35,6 +35,7 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/spf13/pflag"
"k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/openapi"
"k8s.io/apimachinery/pkg/openapi"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/schema"
utilerrors
"k8s.io/apimachinery/pkg/util/errors"
utilerrors
"k8s.io/apimachinery/pkg/util/errors"
...
@@ -50,6 +51,7 @@ import (
...
@@ -50,6 +51,7 @@ import (
"k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/capabilities"
"k8s.io/kubernetes/pkg/capabilities"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
"k8s.io/kubernetes/pkg/cloudprovider"
"k8s.io/kubernetes/pkg/cloudprovider"
"k8s.io/kubernetes/pkg/controller/informers"
"k8s.io/kubernetes/pkg/controller/informers"
serviceaccountcontroller
"k8s.io/kubernetes/pkg/controller/serviceaccount"
serviceaccountcontroller
"k8s.io/kubernetes/pkg/controller/serviceaccount"
...
@@ -61,6 +63,7 @@ import (
...
@@ -61,6 +63,7 @@ import (
"k8s.io/kubernetes/pkg/master/tunneler"
"k8s.io/kubernetes/pkg/master/tunneler"
"k8s.io/kubernetes/pkg/registry/cachesize"
"k8s.io/kubernetes/pkg/registry/cachesize"
"k8s.io/kubernetes/pkg/version"
"k8s.io/kubernetes/pkg/version"
"k8s.io/kubernetes/plugin/pkg/auth/authenticator/token/bootstrap"
)
)
// NewAPIServerCommand creates a *cobra.Command object with default parameters
// NewAPIServerCommand creates a *cobra.Command object with default parameters
...
@@ -253,11 +256,6 @@ func Run(s *options.ServerRunOptions) error {
...
@@ -253,11 +256,6 @@ func Run(s *options.ServerRunOptions) error {
authenticatorConfig
.
ServiceAccountTokenGetter
=
serviceaccountcontroller
.
NewGetterFromStorageInterface
(
storageConfig
,
storageFactory
.
ResourcePrefix
(
api
.
Resource
(
"serviceaccounts"
)),
storageFactory
.
ResourcePrefix
(
api
.
Resource
(
"secrets"
)))
authenticatorConfig
.
ServiceAccountTokenGetter
=
serviceaccountcontroller
.
NewGetterFromStorageInterface
(
storageConfig
,
storageFactory
.
ResourcePrefix
(
api
.
Resource
(
"serviceaccounts"
)),
storageFactory
.
ResourcePrefix
(
api
.
Resource
(
"secrets"
)))
}
}
apiAuthenticator
,
securityDefinitions
,
err
:=
authenticatorConfig
.
New
()
if
err
!=
nil
{
return
fmt
.
Errorf
(
"invalid Authentication Config: %v"
,
err
)
}
client
,
err
:=
internalclientset
.
NewForConfig
(
genericConfig
.
LoopbackClientConfig
)
client
,
err
:=
internalclientset
.
NewForConfig
(
genericConfig
.
LoopbackClientConfig
)
if
err
!=
nil
{
if
err
!=
nil
{
kubeAPIVersions
:=
os
.
Getenv
(
"KUBE_API_VERSIONS"
)
kubeAPIVersions
:=
os
.
Getenv
(
"KUBE_API_VERSIONS"
)
...
@@ -267,10 +265,29 @@ func Run(s *options.ServerRunOptions) error {
...
@@ -267,10 +265,29 @@ func Run(s *options.ServerRunOptions) error {
// KUBE_API_VERSIONS is used in test-update-storage-objects.sh, disabling a number of API
// KUBE_API_VERSIONS is used in test-update-storage-objects.sh, disabling a number of API
// groups. This leads to a nil client above and undefined behaviour further down.
// groups. This leads to a nil client above and undefined behaviour further down.
//
// TODO: get rid of KUBE_API_VERSIONS or define sane behaviour if set
// TODO: get rid of KUBE_API_VERSIONS or define sane behaviour if set
glog
.
Errorf
(
"Failed to create clientset with KUBE_API_VERSIONS=%q. KUBE_API_VERSIONS is only for testing. Things will break."
,
kubeAPIVersions
)
glog
.
Errorf
(
"Failed to create clientset with KUBE_API_VERSIONS=%q. KUBE_API_VERSIONS is only for testing. Things will break."
,
kubeAPIVersions
)
}
}
// TODO: Internal informers should switch to using 'pkg/client/informers/informers_generated',
// the second informer created here. Refactor clients which take the former to accept the latter.
sharedInformers
:=
informers
.
NewSharedInformerFactory
(
nil
,
client
,
10
*
time
.
Minute
)
sharedInformers
:=
informers
.
NewSharedInformerFactory
(
nil
,
client
,
10
*
time
.
Minute
)
internalSharedInformers
:=
internalversion
.
NewSharedInformerFactory
(
client
,
10
*
time
.
Minute
)
if
client
==
nil
{
// TODO: Remove check once client can never be nil.
glog
.
Errorf
(
"Failed to setup bootstrap token authenticator because the loopback clientset was not setup properly."
)
}
else
{
authenticatorConfig
.
BootstrapTokenAuthenticator
=
bootstrap
.
NewTokenAuthenticator
(
internalSharedInformers
.
Core
()
.
InternalVersion
()
.
Secrets
()
.
Lister
()
.
Secrets
(
v1
.
NamespaceSystem
),
)
}
apiAuthenticator
,
securityDefinitions
,
err
:=
authenticatorConfig
.
New
()
if
err
!=
nil
{
return
fmt
.
Errorf
(
"invalid authentication config: %v"
,
err
)
}
authorizationConfig
:=
s
.
Authorization
.
ToAuthorizationConfig
(
sharedInformers
)
authorizationConfig
:=
s
.
Authorization
.
ToAuthorizationConfig
(
sharedInformers
)
apiAuthorizer
,
err
:=
authorizationConfig
.
New
()
apiAuthorizer
,
err
:=
authorizationConfig
.
New
()
...
@@ -350,6 +367,7 @@ func Run(s *options.ServerRunOptions) error {
...
@@ -350,6 +367,7 @@ func Run(s *options.ServerRunOptions) error {
}
}
sharedInformers
.
Start
(
wait
.
NeverStop
)
sharedInformers
.
Start
(
wait
.
NeverStop
)
internalSharedInformers
.
Start
(
wait
.
NeverStop
)
m
.
GenericAPIServer
.
PrepareRun
()
.
Run
(
wait
.
NeverStop
)
m
.
GenericAPIServer
.
PrepareRun
()
.
Run
(
wait
.
NeverStop
)
return
nil
return
nil
}
}
...
...
hack/.linted_packages
View file @
a0df658b
...
@@ -267,6 +267,7 @@ plugin/pkg/admission/resourcequota/apis/resourcequota/install
...
@@ -267,6 +267,7 @@ plugin/pkg/admission/resourcequota/apis/resourcequota/install
plugin/pkg/admission/resourcequota/apis/resourcequota/validation
plugin/pkg/admission/resourcequota/apis/resourcequota/validation
plugin/pkg/admission/securitycontext/scdeny
plugin/pkg/admission/securitycontext/scdeny
plugin/pkg/auth
plugin/pkg/auth
plugin/pkg/auth/authenticator/token/bootstrap
plugin/pkg/auth/authorizer
plugin/pkg/auth/authorizer
plugin/pkg/auth/authorizer/rbac/bootstrappolicy
plugin/pkg/auth/authorizer/rbac/bootstrappolicy
staging/src/k8s.io/apimachinery/pkg/api/equality
staging/src/k8s.io/apimachinery/pkg/api/equality
...
...
hack/verify-flags/known-flags.txt
View file @
a0df658b
...
@@ -204,6 +204,7 @@ executor-suicide-timeout
...
@@ -204,6 +204,7 @@ executor-suicide-timeout
exit-on-lock-contention
exit-on-lock-contention
experimental-allowed-unsafe-sysctls
experimental-allowed-unsafe-sysctls
experimental-bootstrap-kubeconfig
experimental-bootstrap-kubeconfig
experimental-bootstrap-token-auth
experimental-keystone-url
experimental-keystone-url
experimental-keystone-ca-file
experimental-keystone-ca-file
experimental-mounter-path
experimental-mounter-path
...
...
pkg/bootstrap/api/types.go
View file @
a0df658b
...
@@ -33,12 +33,12 @@ const (
...
@@ -33,12 +33,12 @@ const (
SecretTypeBootstrapToken
v1
.
SecretType
=
"bootstrap.kubernetes.io/token"
SecretTypeBootstrapToken
v1
.
SecretType
=
"bootstrap.kubernetes.io/token"
// BootstrapTokenIDKey is the id of this token. This can be transmitted in the
// BootstrapTokenIDKey is the id of this token. This can be transmitted in the
// clear and encoded in the name of the secret. It
should be a random 6
// clear and encoded in the name of the secret. It
must be a random 6 character
//
character string. Required
//
string that matches the regexp `^([a-z0-9]{6})$`. Required.
BootstrapTokenIDKey
=
"token-id"
BootstrapTokenIDKey
=
"token-id"
// BootstrapTokenSecretKey is the actual secret.
Typically this is a random 16
// BootstrapTokenSecretKey is the actual secret.
It must be a random 16 character
//
character string
. Required.
//
string that matches the regexp `^([a-z0-9]{16})$`
. Required.
BootstrapTokenSecretKey
=
"token-secret"
BootstrapTokenSecretKey
=
"token-secret"
// BootstrapTokenExpirationKey is when this token should be expired and no
// BootstrapTokenExpirationKey is when this token should be expired and no
...
@@ -52,6 +52,13 @@ const (
...
@@ -52,6 +52,13 @@ const (
// other value is assumed to be false. Optional.
// other value is assumed to be false. Optional.
BootstrapTokenUsageSigningKey
=
"usage-bootstrap-signing"
BootstrapTokenUsageSigningKey
=
"usage-bootstrap-signing"
// BootstrapTokenUsageAuthentication signals that this token should be used
// as a bearer token to authenticate against the Kubernetes API. The bearer
// token takes the form "<token-id>.<token-secret>" and authenticates as the
// user "system:bootstrap:<token-id>" in the group "system:bootstrappers".
// Value must be "true". Any other value is assumed to be false. Optional.
BootstrapTokenUsageAuthentication
=
"usage-bootstrap-authentication"
// ConfigMapClusterInfo defines the name for the ConfigMap where the information how to connect and trust the cluster exist
// ConfigMapClusterInfo defines the name for the ConfigMap where the information how to connect and trust the cluster exist
ConfigMapClusterInfo
=
"cluster-info"
ConfigMapClusterInfo
=
"cluster-info"
...
@@ -60,4 +67,11 @@ const (
...
@@ -60,4 +67,11 @@ const (
// JWSSignatureKeyPrefix defines what key prefix the JWS-signed tokens have
// JWSSignatureKeyPrefix defines what key prefix the JWS-signed tokens have
JWSSignatureKeyPrefix
=
"jws-kubeconfig-"
JWSSignatureKeyPrefix
=
"jws-kubeconfig-"
// BootstrapUserPrefix is the username prefix bootstrapping bearer tokens
// authenticate as. The full username given is "system:bootstrap:<token-id>".
BootstrapUserPrefix
=
"system:bootstrap:"
// BootstrapGroup is the group bootstrapping bearer tokens authenticate in.
BootstrapGroup
=
"system:bootstrappers"
)
)
pkg/kubeapiserver/authenticator/config.go
View file @
a0df658b
...
@@ -49,6 +49,7 @@ type AuthenticatorConfig struct {
...
@@ -49,6 +49,7 @@ type AuthenticatorConfig struct {
Anonymous
bool
Anonymous
bool
AnyToken
bool
AnyToken
bool
BasicAuthFile
string
BasicAuthFile
string
BootstrapToken
bool
ClientCAFile
string
ClientCAFile
string
TokenAuthFile
string
TokenAuthFile
string
OIDCIssuerURL
string
OIDCIssuerURL
string
...
@@ -66,7 +67,8 @@ type AuthenticatorConfig struct {
...
@@ -66,7 +67,8 @@ type AuthenticatorConfig struct {
RequestHeaderConfig
*
authenticatorfactory
.
RequestHeaderConfig
RequestHeaderConfig
*
authenticatorfactory
.
RequestHeaderConfig
// TODO, this is the only non-serializable part of the entire config. Factor it out into a clientconfig
// TODO, this is the only non-serializable part of the entire config. Factor it out into a clientconfig
ServiceAccountTokenGetter
serviceaccount
.
ServiceAccountTokenGetter
ServiceAccountTokenGetter
serviceaccount
.
ServiceAccountTokenGetter
BootstrapTokenAuthenticator
authenticator
.
Token
}
}
// New returns an authenticator.Request or an error that supports the standard
// New returns an authenticator.Request or an error that supports the standard
...
@@ -136,6 +138,13 @@ func (config AuthenticatorConfig) New() (authenticator.Request, *spec.SecurityDe
...
@@ -136,6 +138,13 @@ func (config AuthenticatorConfig) New() (authenticator.Request, *spec.SecurityDe
authenticators
=
append
(
authenticators
,
serviceAccountAuth
)
authenticators
=
append
(
authenticators
,
serviceAccountAuth
)
hasTokenAuth
=
true
hasTokenAuth
=
true
}
}
if
config
.
BootstrapToken
{
if
config
.
BootstrapTokenAuthenticator
!=
nil
{
// TODO: This can sometimes be nil because of
authenticators
=
append
(
authenticators
,
bearertoken
.
New
(
config
.
BootstrapTokenAuthenticator
))
hasTokenAuth
=
true
}
}
// NOTE(ericchiang): Keep the OpenID Connect after Service Accounts.
// NOTE(ericchiang): Keep the OpenID Connect after Service Accounts.
//
//
// Because both plugins verify JWTs whichever comes first in the union experiences
// Because both plugins verify JWTs whichever comes first in the union experiences
...
...
pkg/kubeapiserver/options/authentication.go
View file @
a0df658b
...
@@ -33,6 +33,7 @@ import (
...
@@ -33,6 +33,7 @@ import (
type
BuiltInAuthenticationOptions
struct
{
type
BuiltInAuthenticationOptions
struct
{
Anonymous
*
AnonymousAuthenticationOptions
Anonymous
*
AnonymousAuthenticationOptions
AnyToken
*
AnyTokenAuthenticationOptions
AnyToken
*
AnyTokenAuthenticationOptions
BootstrapToken
*
BootstrapTokenAuthenticationOptions
ClientCert
*
genericoptions
.
ClientCertAuthenticationOptions
ClientCert
*
genericoptions
.
ClientCertAuthenticationOptions
Keystone
*
KeystoneAuthenticationOptions
Keystone
*
KeystoneAuthenticationOptions
OIDC
*
OIDCAuthenticationOptions
OIDC
*
OIDCAuthenticationOptions
...
@@ -51,6 +52,10 @@ type AnonymousAuthenticationOptions struct {
...
@@ -51,6 +52,10 @@ type AnonymousAuthenticationOptions struct {
Allow
bool
Allow
bool
}
}
type
BootstrapTokenAuthenticationOptions
struct
{
Allow
bool
}
type
KeystoneAuthenticationOptions
struct
{
type
KeystoneAuthenticationOptions
struct
{
URL
string
URL
string
CAFile
string
CAFile
string
...
@@ -90,6 +95,7 @@ func (s *BuiltInAuthenticationOptions) WithAll() *BuiltInAuthenticationOptions {
...
@@ -90,6 +95,7 @@ func (s *BuiltInAuthenticationOptions) WithAll() *BuiltInAuthenticationOptions {
return
s
.
return
s
.
WithAnyonymous
()
.
WithAnyonymous
()
.
WithAnyToken
()
.
WithAnyToken
()
.
WithBootstrapToken
()
.
WithClientCert
()
.
WithClientCert
()
.
WithKeystone
()
.
WithKeystone
()
.
WithOIDC
()
.
WithOIDC
()
.
...
@@ -110,6 +116,11 @@ func (s *BuiltInAuthenticationOptions) WithAnyToken() *BuiltInAuthenticationOpti
...
@@ -110,6 +116,11 @@ func (s *BuiltInAuthenticationOptions) WithAnyToken() *BuiltInAuthenticationOpti
return
s
return
s
}
}
func
(
s
*
BuiltInAuthenticationOptions
)
WithBootstrapToken
()
*
BuiltInAuthenticationOptions
{
s
.
BootstrapToken
=
&
BootstrapTokenAuthenticationOptions
{}
return
s
}
func
(
s
*
BuiltInAuthenticationOptions
)
WithClientCert
()
*
BuiltInAuthenticationOptions
{
func
(
s
*
BuiltInAuthenticationOptions
)
WithClientCert
()
*
BuiltInAuthenticationOptions
{
s
.
ClientCert
=
&
genericoptions
.
ClientCertAuthenticationOptions
{}
s
.
ClientCert
=
&
genericoptions
.
ClientCertAuthenticationOptions
{}
return
s
return
s
...
@@ -172,6 +183,12 @@ func (s *BuiltInAuthenticationOptions) AddFlags(fs *pflag.FlagSet) {
...
@@ -172,6 +183,12 @@ func (s *BuiltInAuthenticationOptions) AddFlags(fs *pflag.FlagSet) {
}
}
if
s
.
BootstrapToken
!=
nil
{
fs
.
BoolVar
(
&
s
.
BootstrapToken
.
Allow
,
"experimental-bootstrap-token-auth"
,
s
.
BootstrapToken
.
Allow
,
""
+
"Enable to allow secrets of type 'bootstrap.kubernetes.io/token' in the 'kube-system' "
+
"namespace to be used for TLS bootstrapping authentication."
)
}
if
s
.
ClientCert
!=
nil
{
if
s
.
ClientCert
!=
nil
{
s
.
ClientCert
.
AddFlags
(
fs
)
s
.
ClientCert
.
AddFlags
(
fs
)
}
}
...
@@ -255,6 +272,10 @@ func (s *BuiltInAuthenticationOptions) ToAuthenticationConfig() authenticator.Au
...
@@ -255,6 +272,10 @@ func (s *BuiltInAuthenticationOptions) ToAuthenticationConfig() authenticator.Au
ret
.
AnyToken
=
s
.
AnyToken
.
Allow
ret
.
AnyToken
=
s
.
AnyToken
.
Allow
}
}
if
s
.
BootstrapToken
!=
nil
{
ret
.
BootstrapToken
=
s
.
BootstrapToken
.
Allow
}
if
s
.
ClientCert
!=
nil
{
if
s
.
ClientCert
!=
nil
{
ret
.
ClientCAFile
=
s
.
ClientCert
.
ClientCA
ret
.
ClientCAFile
=
s
.
ClientCert
.
ClientCA
}
}
...
...
plugin/pkg/auth/BUILD
View file @
a0df658b
...
@@ -24,6 +24,7 @@ filegroup(
...
@@ -24,6 +24,7 @@ filegroup(
name = "all-srcs",
name = "all-srcs",
srcs = [
srcs = [
":package-srcs",
":package-srcs",
"//plugin/pkg/auth/authenticator/token/bootstrap:all-srcs",
"//plugin/pkg/auth/authorizer:all-srcs",
"//plugin/pkg/auth/authorizer:all-srcs",
],
],
tags = ["automanaged"],
tags = ["automanaged"],
...
...
plugin/pkg/auth/authenticator/token/bootstrap/BUILD
0 → 100644
View file @
a0df658b
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_test(
name = "go_default_test",
srcs = ["bootstrap_test.go"],
library = ":go_default_library",
tags = ["automanaged"],
deps = [
"//pkg/api:go_default_library",
"//pkg/bootstrap/api:go_default_library",
"//vendor:k8s.io/apimachinery/pkg/api/errors",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
"//vendor:k8s.io/apimachinery/pkg/labels",
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
"//vendor:k8s.io/apiserver/pkg/authentication/user",
],
)
go_library(
name = "go_default_library",
srcs = ["bootstrap.go"],
tags = ["automanaged"],
deps = [
"//pkg/api:go_default_library",
"//pkg/bootstrap/api:go_default_library",
"//pkg/client/listers/core/internalversion:go_default_library",
"//vendor:github.com/golang/glog",
"//vendor:k8s.io/apimachinery/pkg/api/errors",
"//vendor:k8s.io/apiserver/pkg/authentication/user",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)
plugin/pkg/auth/authenticator/token/bootstrap/bootstrap.go
0 → 100644
View file @
a0df658b
/*
Copyright 2017 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 bootstrap provides a token authenticator for TLS bootstrap secrets.
*/
package
bootstrap
import
(
"fmt"
"regexp"
"time"
"github.com/golang/glog"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apiserver/pkg/authentication/user"
"k8s.io/kubernetes/pkg/api"
bootstrapapi
"k8s.io/kubernetes/pkg/bootstrap/api"
"k8s.io/kubernetes/pkg/client/listers/core/internalversion"
)
// TODO: A few methods in this package is copied from other sources. Either
// because the existing functionality isn't exported or because it is in a
// package that shouldn't be directly imported by this packages.
// NewTokenAuthenticator initializes a bootstrap token authenticator.
//
// Lister is expected to be for the "kube-system" namespace.
func
NewTokenAuthenticator
(
lister
internalversion
.
SecretNamespaceLister
)
*
TokenAuthenticator
{
return
&
TokenAuthenticator
{
lister
}
}
// TokenAuthenticator authenticates bootstrap tokens from secrets in the API server.
type
TokenAuthenticator
struct
{
lister
internalversion
.
SecretNamespaceLister
}
// AuthenticateToken tries to match the provided token to a bootstrap token secret
// in a given namespace. If found, it authenticates the token in the
// "system:bootstrappers" group and with the "system:bootstrap:(token-id)" username.
//
// All secrets must be of type "bootstrap.kubernetes.io/token". An example secret:
//
// apiVersion: v1
// kind: Secret
// metadata:
// # Name MUST be of form "bootstrap-token-( token id )".
// name: bootstrap-token-( token id )
// namespace: kube-system
// # Only secrets of this type will be evaluated.
// type: bootstrap.kubernetes.io/token
// data:
// token-secret: ( private part of token )
// token-id: ( token id )
// # Required key usage.
// usage-bootstrap-authentication: true
// # May also contain an expiry.
//
// Tokens are expected to be of the form:
//
// ( token-id ).( token-secret )
//
func
(
t
*
TokenAuthenticator
)
AuthenticateToken
(
token
string
)
(
user
.
Info
,
bool
,
error
)
{
tokenID
,
tokenSecret
,
err
:=
parseToken
(
token
)
if
err
!=
nil
{
// Token isn't of the correct form, ignore it.
return
nil
,
false
,
nil
}
secretName
:=
bootstrapapi
.
BootstrapTokenSecretPrefix
+
tokenID
secret
,
err
:=
t
.
lister
.
Get
(
secretName
)
if
err
!=
nil
{
if
errors
.
IsNotFound
(
err
)
{
return
nil
,
false
,
nil
}
return
nil
,
false
,
err
}
if
string
(
secret
.
Type
)
!=
string
(
bootstrapapi
.
SecretTypeBootstrapToken
)
||
secret
.
Data
==
nil
{
return
nil
,
false
,
nil
}
ts
:=
getSecretString
(
secret
,
bootstrapapi
.
BootstrapTokenSecretKey
)
if
ts
!=
tokenSecret
{
return
nil
,
false
,
nil
}
id
:=
getSecretString
(
secret
,
bootstrapapi
.
BootstrapTokenIDKey
)
if
id
!=
tokenID
{
return
nil
,
false
,
nil
}
if
isSecretExpired
(
secret
)
{
return
nil
,
false
,
nil
}
if
getSecretString
(
secret
,
bootstrapapi
.
BootstrapTokenUsageAuthentication
)
!=
"true"
{
glog
.
V
(
3
)
.
Infof
(
"Bearer token matching bootstrap Secret %s/%s not marked %s=true."
,
secret
.
Namespace
,
secret
.
Name
,
bootstrapapi
.
BootstrapTokenUsageAuthentication
)
return
nil
,
false
,
nil
}
return
&
user
.
DefaultInfo
{
Name
:
bootstrapapi
.
BootstrapUserPrefix
+
string
(
id
),
Groups
:
[]
string
{
bootstrapapi
.
BootstrapGroup
},
},
true
,
nil
}
// Copied from k8s.io/kubernetes/pkg/bootstrap/api
func
getSecretString
(
secret
*
api
.
Secret
,
key
string
)
string
{
if
secret
.
Data
==
nil
{
return
""
}
if
val
,
ok
:=
secret
.
Data
[
key
];
ok
{
return
string
(
val
)
}
return
""
}
// Copied from k8s.io/kubernetes/pkg/bootstrap/api
func
isSecretExpired
(
secret
*
api
.
Secret
)
bool
{
expiration
:=
getSecretString
(
secret
,
bootstrapapi
.
BootstrapTokenExpirationKey
)
if
len
(
expiration
)
>
0
{
expTime
,
err2
:=
time
.
Parse
(
time
.
RFC3339
,
expiration
)
if
err2
!=
nil
{
glog
.
V
(
3
)
.
Infof
(
"Unparseable expiration time (%s) in %s/%s Secret: %v. Treating as expired."
,
expiration
,
secret
.
Namespace
,
secret
.
Name
,
err2
)
return
true
}
if
time
.
Now
()
.
After
(
expTime
)
{
glog
.
V
(
3
)
.
Infof
(
"Expired bootstrap token in %s/%s Secret: %v"
,
secret
.
Namespace
,
secret
.
Name
,
expiration
)
return
true
}
}
return
false
}
// Copied from kubernetes/cmd/kubeadm/app/util/token
var
(
tokenRegexpString
=
"^([a-z0-9]{6})
\\
.([a-z0-9]{16})$"
tokenRegexp
=
regexp
.
MustCompile
(
tokenRegexpString
)
)
// parseToken tries and parse a valid token from a string.
// A token ID and token secret are returned in case of success, an error otherwise.
func
parseToken
(
s
string
)
(
string
,
string
,
error
)
{
split
:=
tokenRegexp
.
FindStringSubmatch
(
s
)
if
len
(
split
)
!=
3
{
return
""
,
""
,
fmt
.
Errorf
(
"token [%q] was not of form [%q]"
,
s
,
tokenRegexpString
)
}
return
split
[
1
],
split
[
2
],
nil
}
plugin/pkg/auth/authenticator/token/bootstrap/bootstrap_test.go
0 → 100644
View file @
a0df658b
/*
Copyright 2017 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
bootstrap
import
(
"reflect"
"testing"
"k8s.io/apimachinery/pkg/api/errors"
metav1
"k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apiserver/pkg/authentication/user"
"k8s.io/kubernetes/pkg/api"
bootstrapapi
"k8s.io/kubernetes/pkg/bootstrap/api"
)
type
lister
struct
{
secrets
[]
*
api
.
Secret
}
func
(
l
*
lister
)
List
(
selector
labels
.
Selector
)
(
ret
[]
*
api
.
Secret
,
err
error
)
{
return
l
.
secrets
,
nil
}
func
(
l
*
lister
)
Get
(
name
string
)
(
*
api
.
Secret
,
error
)
{
for
_
,
s
:=
range
l
.
secrets
{
if
s
.
Name
==
name
{
return
s
,
nil
}
}
return
nil
,
errors
.
NewNotFound
(
schema
.
GroupResource
{},
name
)
}
const
(
tokenID
=
"foobar"
// 6 letters
tokenSecret
=
"circumnavigation"
// 16 letters
)
func
TestTokenAuthenticator
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
name
string
secrets
[]
*
api
.
Secret
token
string
wantNotFound
bool
wantUser
*
user
.
DefaultInfo
}{
{
name
:
"valid token"
,
secrets
:
[]
*
api
.
Secret
{
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
bootstrapapi
.
BootstrapTokenSecretPrefix
+
tokenID
,
},
Data
:
map
[
string
][]
byte
{
bootstrapapi
.
BootstrapTokenIDKey
:
[]
byte
(
tokenID
),
bootstrapapi
.
BootstrapTokenSecretKey
:
[]
byte
(
tokenSecret
),
bootstrapapi
.
BootstrapTokenUsageAuthentication
:
[]
byte
(
"true"
),
},
Type
:
"bootstrap.kubernetes.io/token"
,
},
},
token
:
tokenID
+
"."
+
tokenSecret
,
wantUser
:
&
user
.
DefaultInfo
{
Name
:
"system:bootstrap:"
+
tokenID
,
Groups
:
[]
string
{
"system:bootstrappers"
},
},
},
{
name
:
"invalid secret name"
,
secrets
:
[]
*
api
.
Secret
{
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
"bad-name"
,
},
Data
:
map
[
string
][]
byte
{
bootstrapapi
.
BootstrapTokenIDKey
:
[]
byte
(
tokenID
),
bootstrapapi
.
BootstrapTokenSecretKey
:
[]
byte
(
tokenSecret
),
bootstrapapi
.
BootstrapTokenUsageAuthentication
:
[]
byte
(
"true"
),
},
Type
:
"bootstrap.kubernetes.io/token"
,
},
},
token
:
tokenID
+
"."
+
tokenSecret
,
wantNotFound
:
true
,
},
{
name
:
"no usage"
,
secrets
:
[]
*
api
.
Secret
{
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
bootstrapapi
.
BootstrapTokenSecretPrefix
+
tokenID
,
},
Data
:
map
[
string
][]
byte
{
bootstrapapi
.
BootstrapTokenIDKey
:
[]
byte
(
tokenID
),
bootstrapapi
.
BootstrapTokenSecretKey
:
[]
byte
(
tokenSecret
),
},
Type
:
"bootstrap.kubernetes.io/token"
,
},
},
token
:
tokenID
+
"."
+
tokenSecret
,
wantNotFound
:
true
,
},
{
name
:
"wrong token"
,
secrets
:
[]
*
api
.
Secret
{
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
bootstrapapi
.
BootstrapTokenSecretPrefix
+
tokenID
,
},
Data
:
map
[
string
][]
byte
{
bootstrapapi
.
BootstrapTokenIDKey
:
[]
byte
(
tokenID
),
bootstrapapi
.
BootstrapTokenSecretKey
:
[]
byte
(
tokenSecret
),
bootstrapapi
.
BootstrapTokenUsageAuthentication
:
[]
byte
(
"true"
),
},
Type
:
"bootstrap.kubernetes.io/token"
,
},
},
token
:
"barfoo"
+
"."
+
tokenSecret
,
wantNotFound
:
true
,
},
{
name
:
"expired token"
,
secrets
:
[]
*
api
.
Secret
{
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
bootstrapapi
.
BootstrapTokenSecretPrefix
+
tokenID
,
},
Data
:
map
[
string
][]
byte
{
bootstrapapi
.
BootstrapTokenIDKey
:
[]
byte
(
tokenID
),
bootstrapapi
.
BootstrapTokenSecretKey
:
[]
byte
(
tokenSecret
),
bootstrapapi
.
BootstrapTokenUsageAuthentication
:
[]
byte
(
"true"
),
bootstrapapi
.
BootstrapTokenExpirationKey
:
[]
byte
(
"2009-11-10T23:00:00Z"
),
},
Type
:
"bootstrap.kubernetes.io/token"
,
},
},
token
:
tokenID
+
"."
+
tokenSecret
,
wantNotFound
:
true
,
},
{
name
:
"not expired token"
,
secrets
:
[]
*
api
.
Secret
{
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
bootstrapapi
.
BootstrapTokenSecretPrefix
+
tokenID
,
},
Data
:
map
[
string
][]
byte
{
bootstrapapi
.
BootstrapTokenIDKey
:
[]
byte
(
tokenID
),
bootstrapapi
.
BootstrapTokenSecretKey
:
[]
byte
(
tokenSecret
),
bootstrapapi
.
BootstrapTokenUsageAuthentication
:
[]
byte
(
"true"
),
bootstrapapi
.
BootstrapTokenExpirationKey
:
[]
byte
(
"2109-11-10T23:00:00Z"
),
},
Type
:
"bootstrap.kubernetes.io/token"
,
},
},
token
:
tokenID
+
"."
+
tokenSecret
,
wantUser
:
&
user
.
DefaultInfo
{
Name
:
"system:bootstrap:"
+
tokenID
,
Groups
:
[]
string
{
"system:bootstrappers"
},
},
},
{
name
:
"token id wrong length"
,
secrets
:
[]
*
api
.
Secret
{
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
bootstrapapi
.
BootstrapTokenSecretPrefix
+
"foo"
,
},
Data
:
map
[
string
][]
byte
{
bootstrapapi
.
BootstrapTokenIDKey
:
[]
byte
(
"foo"
),
bootstrapapi
.
BootstrapTokenSecretKey
:
[]
byte
(
tokenSecret
),
bootstrapapi
.
BootstrapTokenUsageAuthentication
:
[]
byte
(
"true"
),
},
Type
:
"bootstrap.kubernetes.io/token"
,
},
},
// Token ID must be 6 characters.
token
:
"foo"
+
"."
+
tokenSecret
,
wantNotFound
:
true
,
},
}
for
_
,
test
:=
range
tests
{
func
()
{
a
:=
NewTokenAuthenticator
(
&
lister
{
test
.
secrets
})
u
,
found
,
err
:=
a
.
AuthenticateToken
(
test
.
token
)
if
err
!=
nil
{
t
.
Errorf
(
"test %q returned an error: %v"
,
test
.
name
,
err
)
return
}
if
!
found
{
if
!
test
.
wantNotFound
{
t
.
Errorf
(
"test %q expected to get user"
,
test
.
name
)
}
return
}
if
test
.
wantNotFound
{
t
.
Errorf
(
"test %q expected to not get a user"
,
test
.
name
)
return
}
gotUser
:=
u
.
(
*
user
.
DefaultInfo
)
if
!
reflect
.
DeepEqual
(
gotUser
,
test
.
wantUser
)
{
t
.
Errorf
(
"test %q want user=%#v, got=%#v"
,
test
.
name
,
test
.
wantUser
,
gotUser
)
}
}()
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment