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 authorizer
18
19import (
20	"errors"
21	"fmt"
22	"time"
23
24	utilnet "k8s.io/apimachinery/pkg/util/net"
25	"k8s.io/apimachinery/pkg/util/wait"
26	"k8s.io/apiserver/pkg/authorization/authorizer"
27	"k8s.io/apiserver/pkg/authorization/authorizerfactory"
28	"k8s.io/apiserver/pkg/authorization/union"
29	"k8s.io/apiserver/plugin/pkg/authorizer/webhook"
30	versionedinformers "k8s.io/client-go/informers"
31	"k8s.io/kubernetes/pkg/auth/authorizer/abac"
32	"k8s.io/kubernetes/pkg/auth/nodeidentifier"
33	"k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes"
34	"k8s.io/kubernetes/plugin/pkg/auth/authorizer/node"
35	"k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac"
36	"k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac/bootstrappolicy"
37)
38
39// Config contains the data on how to authorize a request to the Kube API Server
40type Config struct {
41	AuthorizationModes []string
42
43	// Options for ModeABAC
44
45	// Path to an ABAC policy file.
46	PolicyFile string
47
48	// Options for ModeWebhook
49
50	// Kubeconfig file for Webhook authorization plugin.
51	WebhookConfigFile string
52	// API version of subject access reviews to send to the webhook (e.g. "v1", "v1beta1")
53	WebhookVersion string
54	// TTL for caching of authorized responses from the webhook server.
55	WebhookCacheAuthorizedTTL time.Duration
56	// TTL for caching of unauthorized responses from the webhook server.
57	WebhookCacheUnauthorizedTTL time.Duration
58	// WebhookRetryBackoff specifies the backoff parameters for the authorization webhook retry logic.
59	// This allows us to configure the sleep time at each iteration and the maximum number of retries allowed
60	// before we fail the webhook call in order to limit the fan out that ensues when the system is degraded.
61	WebhookRetryBackoff *wait.Backoff
62
63	VersionedInformerFactory versionedinformers.SharedInformerFactory
64
65	// Optional field, custom dial function used to connect to webhook
66	CustomDial utilnet.DialFunc
67}
68
69// New returns the right sort of union of multiple authorizer.Authorizer objects
70// based on the authorizationMode or an error.
71func (config Config) New() (authorizer.Authorizer, authorizer.RuleResolver, error) {
72	if len(config.AuthorizationModes) == 0 {
73		return nil, nil, fmt.Errorf("at least one authorization mode must be passed")
74	}
75
76	var (
77		authorizers   []authorizer.Authorizer
78		ruleResolvers []authorizer.RuleResolver
79	)
80
81	for _, authorizationMode := range config.AuthorizationModes {
82		// Keep cases in sync with constant list in k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes/modes.go.
83		switch authorizationMode {
84		case modes.ModeNode:
85			node.RegisterMetrics()
86			graph := node.NewGraph()
87			node.AddGraphEventHandlers(
88				graph,
89				config.VersionedInformerFactory.Core().V1().Nodes(),
90				config.VersionedInformerFactory.Core().V1().Pods(),
91				config.VersionedInformerFactory.Core().V1().PersistentVolumes(),
92				config.VersionedInformerFactory.Storage().V1().VolumeAttachments(),
93			)
94			nodeAuthorizer := node.NewAuthorizer(graph, nodeidentifier.NewDefaultNodeIdentifier(), bootstrappolicy.NodeRules())
95			authorizers = append(authorizers, nodeAuthorizer)
96			ruleResolvers = append(ruleResolvers, nodeAuthorizer)
97
98		case modes.ModeAlwaysAllow:
99			alwaysAllowAuthorizer := authorizerfactory.NewAlwaysAllowAuthorizer()
100			authorizers = append(authorizers, alwaysAllowAuthorizer)
101			ruleResolvers = append(ruleResolvers, alwaysAllowAuthorizer)
102		case modes.ModeAlwaysDeny:
103			alwaysDenyAuthorizer := authorizerfactory.NewAlwaysDenyAuthorizer()
104			authorizers = append(authorizers, alwaysDenyAuthorizer)
105			ruleResolvers = append(ruleResolvers, alwaysDenyAuthorizer)
106		case modes.ModeABAC:
107			abacAuthorizer, err := abac.NewFromFile(config.PolicyFile)
108			if err != nil {
109				return nil, nil, err
110			}
111			authorizers = append(authorizers, abacAuthorizer)
112			ruleResolvers = append(ruleResolvers, abacAuthorizer)
113		case modes.ModeWebhook:
114			if config.WebhookRetryBackoff == nil {
115				return nil, nil, errors.New("retry backoff parameters for authorization webhook has not been specified")
116			}
117			webhookAuthorizer, err := webhook.New(config.WebhookConfigFile,
118				config.WebhookVersion,
119				config.WebhookCacheAuthorizedTTL,
120				config.WebhookCacheUnauthorizedTTL,
121				*config.WebhookRetryBackoff,
122				config.CustomDial)
123			if err != nil {
124				return nil, nil, err
125			}
126			authorizers = append(authorizers, webhookAuthorizer)
127			ruleResolvers = append(ruleResolvers, webhookAuthorizer)
128		case modes.ModeRBAC:
129			rbacAuthorizer := rbac.New(
130				&rbac.RoleGetter{Lister: config.VersionedInformerFactory.Rbac().V1().Roles().Lister()},
131				&rbac.RoleBindingLister{Lister: config.VersionedInformerFactory.Rbac().V1().RoleBindings().Lister()},
132				&rbac.ClusterRoleGetter{Lister: config.VersionedInformerFactory.Rbac().V1().ClusterRoles().Lister()},
133				&rbac.ClusterRoleBindingLister{Lister: config.VersionedInformerFactory.Rbac().V1().ClusterRoleBindings().Lister()},
134			)
135			authorizers = append(authorizers, rbacAuthorizer)
136			ruleResolvers = append(ruleResolvers, rbacAuthorizer)
137		default:
138			return nil, nil, fmt.Errorf("unknown authorization mode %s specified", authorizationMode)
139		}
140	}
141
142	return union.New(authorizers...), union.NewRuleResolvers(ruleResolvers...), nil
143}
144