1/*
2Copyright 2017 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 options
18
19import (
20	"fmt"
21	"net"
22
23	"github.com/spf13/pflag"
24
25	"k8s.io/apiserver/pkg/server"
26	"k8s.io/client-go/rest"
27)
28
29// DeprecatedInsecureServingOptions are for creating an unauthenticated, unauthorized, insecure port.
30// No one should be using these anymore.
31// DEPRECATED: all insecure serving options are removed in a future version
32type DeprecatedInsecureServingOptions struct {
33	BindAddress net.IP
34	BindPort    int
35	// BindNetwork is the type of network to bind to - defaults to "tcp", accepts "tcp",
36	// "tcp4", and "tcp6".
37	BindNetwork string
38
39	// Listener is the secure server network listener.
40	// either Listener or BindAddress/BindPort/BindNetwork is set,
41	// if Listener is set, use it and omit BindAddress/BindPort/BindNetwork.
42	Listener net.Listener
43
44	// ListenFunc can be overridden to create a custom listener, e.g. for mocking in tests.
45	// It defaults to options.CreateListener.
46	ListenFunc func(network, addr string, config net.ListenConfig) (net.Listener, int, error)
47}
48
49// Validate ensures that the insecure port values within the range of the port.
50func (s *DeprecatedInsecureServingOptions) Validate() []error {
51	if s == nil {
52		return nil
53	}
54
55	errors := []error{}
56
57	if s.BindPort < 0 || s.BindPort > 65535 {
58		errors = append(errors, fmt.Errorf("insecure port %v must be between 0 and 65535, inclusive. 0 for turning off insecure (HTTP) port", s.BindPort))
59	}
60
61	return errors
62}
63
64// AddFlags adds flags related to insecure serving to the specified FlagSet.
65func (s *DeprecatedInsecureServingOptions) AddFlags(fs *pflag.FlagSet) {
66	if s == nil {
67		return
68	}
69
70	fs.IPVar(&s.BindAddress, "insecure-bind-address", s.BindAddress, ""+
71		"The IP address on which to serve the --insecure-port (set to 0.0.0.0 for all IPv4 interfaces and :: for all IPv6 interfaces).")
72	// Though this flag is deprecated, we discovered security concerns over how to do health checks without it e.g. #43784
73	fs.MarkDeprecated("insecure-bind-address", "This flag will be removed in a future version.")
74	fs.Lookup("insecure-bind-address").Hidden = false
75
76	fs.IntVar(&s.BindPort, "insecure-port", s.BindPort, ""+
77		"The port on which to serve unsecured, unauthenticated access.")
78	// Though this flag is deprecated, we discovered security concerns over how to do health checks without it e.g. #43784
79	fs.MarkDeprecated("insecure-port", "This flag will be removed in a future version.")
80	fs.Lookup("insecure-port").Hidden = false
81}
82
83// AddUnqualifiedFlags adds flags related to insecure serving without the --insecure prefix to the specified FlagSet.
84func (s *DeprecatedInsecureServingOptions) AddUnqualifiedFlags(fs *pflag.FlagSet) {
85	if s == nil {
86		return
87	}
88
89	fs.IPVar(&s.BindAddress, "address", s.BindAddress,
90		"The IP address on which to serve the insecure --port (set to 0.0.0.0 for all IPv4 interfaces and :: for all IPv6 interfaces).")
91	fs.MarkDeprecated("address", "see --bind-address instead.")
92	fs.Lookup("address").Hidden = false
93
94	fs.IntVar(&s.BindPort, "port", s.BindPort, "The port on which to serve unsecured, unauthenticated access. Set to 0 to disable.")
95	fs.MarkDeprecated("port", "see --secure-port instead.")
96	fs.Lookup("port").Hidden = false
97}
98
99// ApplyTo adds DeprecatedInsecureServingOptions to the insecureserverinfo and kube-controller manager configuration.
100// Note: the double pointer allows to set the *DeprecatedInsecureServingInfo to nil without referencing the struct hosting this pointer.
101func (s *DeprecatedInsecureServingOptions) ApplyTo(c **server.DeprecatedInsecureServingInfo) error {
102	if s == nil {
103		return nil
104	}
105	if s.BindPort <= 0 {
106		return nil
107	}
108
109	if s.Listener == nil {
110		var err error
111		listen := CreateListener
112		if s.ListenFunc != nil {
113			listen = s.ListenFunc
114		}
115		addr := net.JoinHostPort(s.BindAddress.String(), fmt.Sprintf("%d", s.BindPort))
116		s.Listener, s.BindPort, err = listen(s.BindNetwork, addr, net.ListenConfig{})
117		if err != nil {
118			return fmt.Errorf("failed to create listener: %v", err)
119		}
120	}
121
122	*c = &server.DeprecatedInsecureServingInfo{
123		Listener: s.Listener,
124	}
125
126	return nil
127}
128
129// WithLoopback adds loopback functionality to the serving options.
130func (o *DeprecatedInsecureServingOptions) WithLoopback() *DeprecatedInsecureServingOptionsWithLoopback {
131	return &DeprecatedInsecureServingOptionsWithLoopback{o}
132}
133
134// DeprecatedInsecureServingOptionsWithLoopback adds loopback functionality to the DeprecatedInsecureServingOptions.
135// DEPRECATED: all insecure serving options will be removed in a future version, however note that
136// there are security concerns over how health checks can work here - see e.g. #43784
137type DeprecatedInsecureServingOptionsWithLoopback struct {
138	*DeprecatedInsecureServingOptions
139}
140
141// ApplyTo fills up serving information in the server configuration.
142func (s *DeprecatedInsecureServingOptionsWithLoopback) ApplyTo(insecureServingInfo **server.DeprecatedInsecureServingInfo, loopbackClientConfig **rest.Config) error {
143	if s == nil || s.DeprecatedInsecureServingOptions == nil || insecureServingInfo == nil {
144		return nil
145	}
146
147	if err := s.DeprecatedInsecureServingOptions.ApplyTo(insecureServingInfo); err != nil {
148		return err
149	}
150
151	if *insecureServingInfo == nil || loopbackClientConfig == nil {
152		return nil
153	}
154
155	secureLoopbackClientConfig, err := (*insecureServingInfo).NewLoopbackClientConfig()
156	switch {
157	// if we failed and there's no fallback loopback client config, we need to fail
158	case err != nil && *loopbackClientConfig == nil:
159		return err
160
161		// if we failed, but we already have a fallback loopback client config (usually insecure), allow it
162	case err != nil && *loopbackClientConfig != nil:
163
164	default:
165		*loopbackClientConfig = secureLoopbackClientConfig
166	}
167
168	return nil
169}
170