1/*
2Copyright 2016 The Kubernetes Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package app
18
19import (
20	"errors"
21	"fmt"
22	"reflect"
23
24	"k8s.io/apimachinery/pkg/types"
25	"k8s.io/apiserver/pkg/authentication/authenticator"
26	"k8s.io/apiserver/pkg/authentication/authenticatorfactory"
27	"k8s.io/apiserver/pkg/authorization/authorizer"
28	"k8s.io/apiserver/pkg/authorization/authorizerfactory"
29	"k8s.io/apiserver/pkg/server/dynamiccertificates"
30	genericoptions "k8s.io/apiserver/pkg/server/options"
31	clientset "k8s.io/client-go/kubernetes"
32	authenticationclient "k8s.io/client-go/kubernetes/typed/authentication/v1"
33	authorizationclient "k8s.io/client-go/kubernetes/typed/authorization/v1"
34
35	kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
36	"k8s.io/kubernetes/pkg/kubelet/server"
37)
38
39// BuildAuth creates an authenticator, an authorizer, and a matching authorizer attributes getter compatible with the kubelet's needs
40// It returns AuthInterface, a run method to start internal controllers (like cert reloading) and error.
41func BuildAuth(nodeName types.NodeName, client clientset.Interface, config kubeletconfig.KubeletConfiguration) (server.AuthInterface, func(<-chan struct{}), error) {
42	// Get clients, if provided
43	var (
44		tokenClient authenticationclient.AuthenticationV1Interface
45		sarClient   authorizationclient.AuthorizationV1Interface
46	)
47	if client != nil && !reflect.ValueOf(client).IsNil() {
48		tokenClient = client.AuthenticationV1()
49		sarClient = client.AuthorizationV1()
50	}
51
52	authenticator, runAuthenticatorCAReload, err := BuildAuthn(tokenClient, config.Authentication)
53	if err != nil {
54		return nil, nil, err
55	}
56
57	attributes := server.NewNodeAuthorizerAttributesGetter(nodeName)
58
59	authorizer, err := BuildAuthz(sarClient, config.Authorization)
60	if err != nil {
61		return nil, nil, err
62	}
63
64	return server.NewKubeletAuth(authenticator, attributes, authorizer), runAuthenticatorCAReload, nil
65}
66
67// BuildAuthn creates an authenticator compatible with the kubelet's needs
68func BuildAuthn(client authenticationclient.AuthenticationV1Interface, authn kubeletconfig.KubeletAuthentication) (authenticator.Request, func(<-chan struct{}), error) {
69	var dynamicCAContentFromFile *dynamiccertificates.DynamicFileCAContent
70	var err error
71	if len(authn.X509.ClientCAFile) > 0 {
72		dynamicCAContentFromFile, err = dynamiccertificates.NewDynamicCAContentFromFile("client-ca-bundle", authn.X509.ClientCAFile)
73		if err != nil {
74			return nil, nil, err
75		}
76	}
77
78	authenticatorConfig := authenticatorfactory.DelegatingAuthenticatorConfig{
79		Anonymous:                          authn.Anonymous.Enabled,
80		CacheTTL:                           authn.Webhook.CacheTTL.Duration,
81		ClientCertificateCAContentProvider: dynamicCAContentFromFile,
82	}
83
84	if authn.Webhook.Enabled {
85		if client == nil {
86			return nil, nil, errors.New("no client provided, cannot use webhook authentication")
87		}
88		authenticatorConfig.WebhookRetryBackoff = genericoptions.DefaultAuthWebhookRetryBackoff()
89		authenticatorConfig.TokenAccessReviewClient = client
90	}
91
92	authenticator, _, err := authenticatorConfig.New()
93	if err != nil {
94		return nil, nil, err
95	}
96
97	return authenticator, func(stopCh <-chan struct{}) {
98		if dynamicCAContentFromFile != nil {
99			go dynamicCAContentFromFile.Run(1, stopCh)
100		}
101	}, err
102}
103
104// BuildAuthz creates an authorizer compatible with the kubelet's needs
105func BuildAuthz(client authorizationclient.AuthorizationV1Interface, authz kubeletconfig.KubeletAuthorization) (authorizer.Authorizer, error) {
106	switch authz.Mode {
107	case kubeletconfig.KubeletAuthorizationModeAlwaysAllow:
108		return authorizerfactory.NewAlwaysAllowAuthorizer(), nil
109
110	case kubeletconfig.KubeletAuthorizationModeWebhook:
111		if client == nil {
112			return nil, errors.New("no client provided, cannot use webhook authorization")
113		}
114		authorizerConfig := authorizerfactory.DelegatingAuthorizerConfig{
115			SubjectAccessReviewClient: client,
116			AllowCacheTTL:             authz.Webhook.CacheAuthorizedTTL.Duration,
117			DenyCacheTTL:              authz.Webhook.CacheUnauthorizedTTL.Duration,
118			WebhookRetryBackoff:       genericoptions.DefaultAuthWebhookRetryBackoff(),
119		}
120		return authorizerConfig.New()
121
122	case "":
123		return nil, fmt.Errorf("no authorization mode specified")
124
125	default:
126		return nil, fmt.Errorf("unknown authorization mode %s", authz.Mode)
127
128	}
129}
130