mirror of https://github.com/k3s-io/k3s
274 lines
9.6 KiB
Go
274 lines
9.6 KiB
Go
/*
|
|
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 (
|
|
"fmt"
|
|
"net/url"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/spf13/pflag"
|
|
"k8s.io/klog"
|
|
|
|
"k8s.io/apiserver/pkg/authentication/authenticator"
|
|
genericapiserver "k8s.io/apiserver/pkg/server"
|
|
genericoptions "k8s.io/apiserver/pkg/server/options"
|
|
kubeauthenticator "k8s.io/kubernetes/pkg/kubeapiserver/authenticator"
|
|
)
|
|
|
|
type BuiltInAuthenticationOptions struct {
|
|
APIAudiences []string
|
|
ClientCert *genericoptions.ClientCertAuthenticationOptions
|
|
PasswordFile *PasswordFileAuthenticationOptions
|
|
RequestHeader *genericoptions.RequestHeaderAuthenticationOptions
|
|
ServiceAccounts *ServiceAccountAuthenticationOptions
|
|
TokenFile *TokenFileAuthenticationOptions
|
|
WebHook *WebHookAuthenticationOptions
|
|
|
|
TokenSuccessCacheTTL time.Duration
|
|
TokenFailureCacheTTL time.Duration
|
|
}
|
|
|
|
type PasswordFileAuthenticationOptions struct {
|
|
BasicAuthFile string
|
|
}
|
|
|
|
type ServiceAccountAuthenticationOptions struct {
|
|
KeyFiles []string
|
|
Lookup bool
|
|
Issuer string
|
|
MaxExpiration time.Duration
|
|
}
|
|
|
|
type TokenFileAuthenticationOptions struct {
|
|
TokenFile string
|
|
}
|
|
|
|
type WebHookAuthenticationOptions struct {
|
|
ConfigFile string
|
|
CacheTTL time.Duration
|
|
}
|
|
|
|
func NewBuiltInAuthenticationOptions() *BuiltInAuthenticationOptions {
|
|
return &BuiltInAuthenticationOptions{
|
|
TokenSuccessCacheTTL: 10 * time.Second,
|
|
TokenFailureCacheTTL: 0 * time.Second,
|
|
}
|
|
}
|
|
|
|
func (s *BuiltInAuthenticationOptions) WithAll() *BuiltInAuthenticationOptions {
|
|
return s.
|
|
WithClientCert().
|
|
WithPasswordFile().
|
|
WithRequestHeader().
|
|
WithServiceAccounts().
|
|
WithTokenFile().
|
|
WithWebHook()
|
|
}
|
|
|
|
func (s *BuiltInAuthenticationOptions) WithClientCert() *BuiltInAuthenticationOptions {
|
|
s.ClientCert = &genericoptions.ClientCertAuthenticationOptions{}
|
|
return s
|
|
}
|
|
|
|
func (s *BuiltInAuthenticationOptions) WithPasswordFile() *BuiltInAuthenticationOptions {
|
|
s.PasswordFile = &PasswordFileAuthenticationOptions{}
|
|
return s
|
|
}
|
|
|
|
func (s *BuiltInAuthenticationOptions) WithRequestHeader() *BuiltInAuthenticationOptions {
|
|
s.RequestHeader = &genericoptions.RequestHeaderAuthenticationOptions{}
|
|
return s
|
|
}
|
|
|
|
func (s *BuiltInAuthenticationOptions) WithServiceAccounts() *BuiltInAuthenticationOptions {
|
|
s.ServiceAccounts = &ServiceAccountAuthenticationOptions{Lookup: true}
|
|
return s
|
|
}
|
|
|
|
func (s *BuiltInAuthenticationOptions) WithTokenFile() *BuiltInAuthenticationOptions {
|
|
s.TokenFile = &TokenFileAuthenticationOptions{}
|
|
return s
|
|
}
|
|
|
|
func (s *BuiltInAuthenticationOptions) WithWebHook() *BuiltInAuthenticationOptions {
|
|
s.WebHook = &WebHookAuthenticationOptions{
|
|
CacheTTL: 2 * time.Minute,
|
|
}
|
|
return s
|
|
}
|
|
|
|
// Validate checks invalid config combination
|
|
func (s *BuiltInAuthenticationOptions) Validate() []error {
|
|
allErrors := []error{}
|
|
|
|
if s.ServiceAccounts != nil && len(s.ServiceAccounts.Issuer) > 0 && strings.Contains(s.ServiceAccounts.Issuer, ":") {
|
|
if _, err := url.Parse(s.ServiceAccounts.Issuer); err != nil {
|
|
allErrors = append(allErrors, fmt.Errorf("service-account-issuer contained a ':' but was not a valid URL: %v", err))
|
|
}
|
|
}
|
|
|
|
return allErrors
|
|
}
|
|
|
|
func (s *BuiltInAuthenticationOptions) AddFlags(fs *pflag.FlagSet) {
|
|
fs.StringSliceVar(&s.APIAudiences, "api-audiences", s.APIAudiences, ""+
|
|
"Identifiers of the API. The service account token authenticator will validate that "+
|
|
"tokens used against the API are bound to at least one of these audiences. If the "+
|
|
"--service-account-issuer flag is configured and this flag is not, this field "+
|
|
"defaults to a single element list containing the issuer URL .")
|
|
|
|
if s.ClientCert != nil {
|
|
s.ClientCert.AddFlags(fs)
|
|
}
|
|
|
|
if s.PasswordFile != nil {
|
|
fs.StringVar(&s.PasswordFile.BasicAuthFile, "basic-auth-file", s.PasswordFile.BasicAuthFile, ""+
|
|
"If set, the file that will be used to admit requests to the secure port of the API server "+
|
|
"via http basic authentication.")
|
|
}
|
|
|
|
if s.RequestHeader != nil {
|
|
s.RequestHeader.AddFlags(fs)
|
|
}
|
|
|
|
if s.ServiceAccounts != nil {
|
|
fs.StringArrayVar(&s.ServiceAccounts.KeyFiles, "service-account-key-file", s.ServiceAccounts.KeyFiles, ""+
|
|
"File containing PEM-encoded x509 RSA or ECDSA private or public keys, used to verify "+
|
|
"ServiceAccount tokens. The specified file can contain multiple keys, and the flag can "+
|
|
"be specified multiple times with different files. If unspecified, "+
|
|
"--tls-private-key-file is used. Must be specified when "+
|
|
"--service-account-signing-key is provided")
|
|
|
|
fs.BoolVar(&s.ServiceAccounts.Lookup, "service-account-lookup", s.ServiceAccounts.Lookup,
|
|
"If true, validate ServiceAccount tokens exist in etcd as part of authentication.")
|
|
|
|
fs.StringVar(&s.ServiceAccounts.Issuer, "service-account-issuer", s.ServiceAccounts.Issuer, ""+
|
|
"Identifier of the service account token issuer. The issuer will assert this identifier "+
|
|
"in \"iss\" claim of issued tokens. This value is a string or URI.")
|
|
|
|
// Deprecated in 1.13
|
|
fs.StringSliceVar(&s.APIAudiences, "service-account-api-audiences", s.APIAudiences, ""+
|
|
"Identifiers of the API. The service account token authenticator will validate that "+
|
|
"tokens used against the API are bound to at least one of these audiences.")
|
|
fs.MarkDeprecated("service-account-api-audiences", "Use --api-audiences")
|
|
|
|
fs.DurationVar(&s.ServiceAccounts.MaxExpiration, "service-account-max-token-expiration", s.ServiceAccounts.MaxExpiration, ""+
|
|
"The maximum validity duration of a token created by the service account token issuer. If an otherwise valid "+
|
|
"TokenRequest with a validity duration larger than this value is requested, a token will be issued with a validity duration of this value.")
|
|
}
|
|
|
|
if s.TokenFile != nil {
|
|
fs.StringVar(&s.TokenFile.TokenFile, "token-auth-file", s.TokenFile.TokenFile, ""+
|
|
"If set, the file that will be used to secure the secure port of the API server "+
|
|
"via token authentication.")
|
|
}
|
|
|
|
if s.WebHook != nil {
|
|
fs.StringVar(&s.WebHook.ConfigFile, "authentication-token-webhook-config-file", s.WebHook.ConfigFile, ""+
|
|
"File with webhook configuration for token authentication in kubeconfig format. "+
|
|
"The API server will query the remote service to determine authentication for bearer tokens.")
|
|
|
|
fs.DurationVar(&s.WebHook.CacheTTL, "authentication-token-webhook-cache-ttl", s.WebHook.CacheTTL,
|
|
"The duration to cache responses from the webhook token authenticator.")
|
|
}
|
|
}
|
|
|
|
func (s *BuiltInAuthenticationOptions) ToAuthenticationConfig() kubeauthenticator.Config {
|
|
ret := kubeauthenticator.Config{
|
|
TokenSuccessCacheTTL: s.TokenSuccessCacheTTL,
|
|
TokenFailureCacheTTL: s.TokenFailureCacheTTL,
|
|
}
|
|
|
|
if s.ClientCert != nil {
|
|
ret.ClientCAFile = s.ClientCert.ClientCA
|
|
}
|
|
|
|
if s.PasswordFile != nil {
|
|
ret.BasicAuthFile = s.PasswordFile.BasicAuthFile
|
|
}
|
|
|
|
if s.RequestHeader != nil {
|
|
ret.RequestHeaderConfig = s.RequestHeader.ToAuthenticationRequestHeaderConfig()
|
|
}
|
|
|
|
ret.APIAudiences = s.APIAudiences
|
|
if s.ServiceAccounts != nil {
|
|
if s.ServiceAccounts.Issuer != "" && len(s.APIAudiences) == 0 {
|
|
ret.APIAudiences = authenticator.Audiences{s.ServiceAccounts.Issuer}
|
|
}
|
|
ret.ServiceAccountKeyFiles = s.ServiceAccounts.KeyFiles
|
|
ret.ServiceAccountIssuer = s.ServiceAccounts.Issuer
|
|
ret.ServiceAccountLookup = s.ServiceAccounts.Lookup
|
|
}
|
|
|
|
if s.TokenFile != nil {
|
|
ret.TokenAuthFile = s.TokenFile.TokenFile
|
|
}
|
|
|
|
if s.WebHook != nil {
|
|
ret.WebhookTokenAuthnConfigFile = s.WebHook.ConfigFile
|
|
ret.WebhookTokenAuthnCacheTTL = s.WebHook.CacheTTL
|
|
|
|
if len(s.WebHook.ConfigFile) > 0 && s.WebHook.CacheTTL > 0 {
|
|
if s.TokenSuccessCacheTTL > 0 && s.WebHook.CacheTTL < s.TokenSuccessCacheTTL {
|
|
klog.Warningf("the webhook cache ttl of %s is shorter than the overall cache ttl of %s for successful token authentication attempts.", s.WebHook.CacheTTL, s.TokenSuccessCacheTTL)
|
|
}
|
|
if s.TokenFailureCacheTTL > 0 && s.WebHook.CacheTTL < s.TokenFailureCacheTTL {
|
|
klog.Warningf("the webhook cache ttl of %s is shorter than the overall cache ttl of %s for failed token authentication attempts.", s.WebHook.CacheTTL, s.TokenFailureCacheTTL)
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret
|
|
}
|
|
|
|
func (o *BuiltInAuthenticationOptions) ApplyTo(c *genericapiserver.Config) error {
|
|
if o == nil {
|
|
return nil
|
|
}
|
|
|
|
var err error
|
|
if o.ClientCert != nil {
|
|
if err = c.Authentication.ApplyClientCert(o.ClientCert.ClientCA, c.SecureServing); err != nil {
|
|
return fmt.Errorf("unable to load client CA file: %v", err)
|
|
}
|
|
}
|
|
if o.RequestHeader != nil {
|
|
if err = c.Authentication.ApplyClientCert(o.RequestHeader.ClientCAFile, c.SecureServing); err != nil {
|
|
return fmt.Errorf("unable to load client CA file: %v", err)
|
|
}
|
|
}
|
|
|
|
c.Authentication.SupportsBasicAuth = o.PasswordFile != nil && len(o.PasswordFile.BasicAuthFile) > 0
|
|
|
|
c.Authentication.APIAudiences = o.APIAudiences
|
|
if o.ServiceAccounts != nil && o.ServiceAccounts.Issuer != "" && len(o.APIAudiences) == 0 {
|
|
c.Authentication.APIAudiences = authenticator.Audiences{o.ServiceAccounts.Issuer}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ApplyAuthorization will conditionally modify the authentication options based on the authorization options
|
|
func (o *BuiltInAuthenticationOptions) ApplyAuthorization(authorization *BuiltInAuthorizationOptions) {
|
|
if o == nil || authorization == nil {
|
|
return
|
|
}
|
|
}
|