1
16
17
18 package options
19
20 import (
21 "fmt"
22 "net"
23 "os"
24 "strings"
25 "time"
26
27 peerreconcilers "k8s.io/apiserver/pkg/reconcilers"
28 genericoptions "k8s.io/apiserver/pkg/server/options"
29 "k8s.io/apiserver/pkg/storage/storagebackend"
30 "k8s.io/client-go/util/keyutil"
31 cliflag "k8s.io/component-base/cli/flag"
32 "k8s.io/component-base/logs"
33 logsapi "k8s.io/component-base/logs/api/v1"
34 "k8s.io/component-base/metrics"
35 "k8s.io/klog/v2"
36 netutil "k8s.io/utils/net"
37
38 _ "k8s.io/kubernetes/pkg/features"
39 kubeauthenticator "k8s.io/kubernetes/pkg/kubeapiserver/authenticator"
40 kubeoptions "k8s.io/kubernetes/pkg/kubeapiserver/options"
41 "k8s.io/kubernetes/pkg/serviceaccount"
42 )
43
44
45
46 type Options struct {
47 GenericServerRunOptions *genericoptions.ServerRunOptions
48 Etcd *genericoptions.EtcdOptions
49 SecureServing *genericoptions.SecureServingOptionsWithLoopback
50 Audit *genericoptions.AuditOptions
51 Features *genericoptions.FeatureOptions
52 Admission *kubeoptions.AdmissionOptions
53 Authentication *kubeoptions.BuiltInAuthenticationOptions
54 Authorization *kubeoptions.BuiltInAuthorizationOptions
55 APIEnablement *genericoptions.APIEnablementOptions
56 EgressSelector *genericoptions.EgressSelectorOptions
57 Metrics *metrics.Options
58 Logs *logs.Options
59 Traces *genericoptions.TracingOptions
60
61 EnableLogsHandler bool
62 EventTTL time.Duration
63 MaxConnectionBytesPerSec int64
64
65 ProxyClientCertFile string
66 ProxyClientKeyFile string
67
68
69
70
71 PeerCAFile string
72
73
74
75
76 PeerAdvertiseAddress peerreconcilers.PeerAdvertiseAddress
77
78 EnableAggregatorRouting bool
79 AggregatorRejectForwardingRedirects bool
80
81 ServiceAccountSigningKeyFile string
82 ServiceAccountIssuer serviceaccount.TokenGenerator
83 ServiceAccountTokenMaxExpiration time.Duration
84
85 ShowHiddenMetricsForVersion string
86 }
87
88
89 type completedOptions struct {
90 Options
91 }
92
93 type CompletedOptions struct {
94
95 *completedOptions
96 }
97
98
99 func NewOptions() *Options {
100 s := Options{
101 GenericServerRunOptions: genericoptions.NewServerRunOptions(),
102 Etcd: genericoptions.NewEtcdOptions(storagebackend.NewDefaultConfig(kubeoptions.DefaultEtcdPathPrefix, nil)),
103 SecureServing: kubeoptions.NewSecureServingOptions(),
104 Audit: genericoptions.NewAuditOptions(),
105 Features: genericoptions.NewFeatureOptions(),
106 Admission: kubeoptions.NewAdmissionOptions(),
107 Authentication: kubeoptions.NewBuiltInAuthenticationOptions().WithAll(),
108 Authorization: kubeoptions.NewBuiltInAuthorizationOptions(),
109 APIEnablement: genericoptions.NewAPIEnablementOptions(),
110 EgressSelector: genericoptions.NewEgressSelectorOptions(),
111 Metrics: metrics.NewOptions(),
112 Logs: logs.NewOptions(),
113 Traces: genericoptions.NewTracingOptions(),
114
115 EnableLogsHandler: true,
116 EventTTL: 1 * time.Hour,
117 AggregatorRejectForwardingRedirects: true,
118 }
119
120
121 s.Etcd.DefaultStorageMediaType = "application/vnd.kubernetes.protobuf"
122
123 return &s
124 }
125
126 func (s *Options) AddFlags(fss *cliflag.NamedFlagSets) {
127
128 s.GenericServerRunOptions.AddUniversalFlags(fss.FlagSet("generic"))
129 s.Etcd.AddFlags(fss.FlagSet("etcd"))
130 s.SecureServing.AddFlags(fss.FlagSet("secure serving"))
131 s.Audit.AddFlags(fss.FlagSet("auditing"))
132 s.Features.AddFlags(fss.FlagSet("features"))
133 s.Authentication.AddFlags(fss.FlagSet("authentication"))
134 s.Authorization.AddFlags(fss.FlagSet("authorization"))
135 s.APIEnablement.AddFlags(fss.FlagSet("API enablement"))
136 s.EgressSelector.AddFlags(fss.FlagSet("egress selector"))
137 s.Admission.AddFlags(fss.FlagSet("admission"))
138 s.Metrics.AddFlags(fss.FlagSet("metrics"))
139 logsapi.AddFlags(s.Logs, fss.FlagSet("logs"))
140 s.Traces.AddFlags(fss.FlagSet("traces"))
141
142
143
144 fs := fss.FlagSet("misc")
145 fs.DurationVar(&s.EventTTL, "event-ttl", s.EventTTL,
146 "Amount of time to retain events.")
147
148 fs.BoolVar(&s.EnableLogsHandler, "enable-logs-handler", s.EnableLogsHandler,
149 "If true, install a /logs handler for the apiserver logs.")
150 fs.MarkDeprecated("enable-logs-handler", "This flag will be removed in v1.19")
151
152 fs.Int64Var(&s.MaxConnectionBytesPerSec, "max-connection-bytes-per-sec", s.MaxConnectionBytesPerSec, ""+
153 "If non-zero, throttle each user connection to this number of bytes/sec. "+
154 "Currently only applies to long-running requests.")
155
156 fs.StringVar(&s.ProxyClientCertFile, "proxy-client-cert-file", s.ProxyClientCertFile, ""+
157 "Client certificate used to prove the identity of the aggregator or kube-apiserver "+
158 "when it must call out during a request. This includes proxying requests to a user "+
159 "api-server and calling out to webhook admission plugins. It is expected that this "+
160 "cert includes a signature from the CA in the --requestheader-client-ca-file flag. "+
161 "That CA is published in the 'extension-apiserver-authentication' configmap in "+
162 "the kube-system namespace. Components receiving calls from kube-aggregator should "+
163 "use that CA to perform their half of the mutual TLS verification.")
164 fs.StringVar(&s.ProxyClientKeyFile, "proxy-client-key-file", s.ProxyClientKeyFile, ""+
165 "Private key for the client certificate used to prove the identity of the aggregator or kube-apiserver "+
166 "when it must call out during a request. This includes proxying requests to a user "+
167 "api-server and calling out to webhook admission plugins.")
168
169 fs.StringVar(&s.PeerCAFile, "peer-ca-file", s.PeerCAFile,
170 "If set and the UnknownVersionInteroperabilityProxy feature gate is enabled, this file will be used to verify serving certificates of peer kube-apiservers. "+
171 "This flag is only used in clusters configured with multiple kube-apiservers for high availability.")
172
173 fs.StringVar(&s.PeerAdvertiseAddress.PeerAdvertiseIP, "peer-advertise-ip", s.PeerAdvertiseAddress.PeerAdvertiseIP,
174 "If set and the UnknownVersionInteroperabilityProxy feature gate is enabled, this IP will be used by peer kube-apiservers to proxy requests to this kube-apiserver "+
175 "when the request cannot be handled by the peer due to version skew between the kube-apiservers. "+
176 "This flag is only used in clusters configured with multiple kube-apiservers for high availability. ")
177
178 fs.StringVar(&s.PeerAdvertiseAddress.PeerAdvertisePort, "peer-advertise-port", s.PeerAdvertiseAddress.PeerAdvertisePort,
179 "If set and the UnknownVersionInteroperabilityProxy feature gate is enabled, this port will be used by peer kube-apiservers to proxy requests to this kube-apiserver "+
180 "when the request cannot be handled by the peer due to version skew between the kube-apiservers. "+
181 "This flag is only used in clusters configured with multiple kube-apiservers for high availability. ")
182
183 fs.BoolVar(&s.EnableAggregatorRouting, "enable-aggregator-routing", s.EnableAggregatorRouting,
184 "Turns on aggregator routing requests to endpoints IP rather than cluster IP.")
185
186 fs.BoolVar(&s.AggregatorRejectForwardingRedirects, "aggregator-reject-forwarding-redirect", s.AggregatorRejectForwardingRedirects,
187 "Aggregator reject forwarding redirect response back to client.")
188
189 fs.StringVar(&s.ServiceAccountSigningKeyFile, "service-account-signing-key-file", s.ServiceAccountSigningKeyFile, ""+
190 "Path to the file that contains the current private key of the service account token issuer. The issuer will sign issued ID tokens with this private key.")
191 }
192
193 func (o *Options) Complete(alternateDNS []string, alternateIPs []net.IP) (CompletedOptions, error) {
194 if o == nil {
195 return CompletedOptions{completedOptions: &completedOptions{}}, nil
196 }
197
198 completed := completedOptions{
199 Options: *o,
200 }
201
202
203 if err := completed.GenericServerRunOptions.DefaultAdvertiseAddress(completed.SecureServing.SecureServingOptions); err != nil {
204 return CompletedOptions{}, err
205 }
206
207 if err := completed.SecureServing.MaybeDefaultWithSelfSignedCerts(completed.GenericServerRunOptions.AdvertiseAddress.String(), alternateDNS, alternateIPs); err != nil {
208 return CompletedOptions{}, fmt.Errorf("error creating self-signed certificates: %v", err)
209 }
210
211 if len(completed.GenericServerRunOptions.ExternalHost) == 0 {
212 if len(completed.GenericServerRunOptions.AdvertiseAddress) > 0 {
213 completed.GenericServerRunOptions.ExternalHost = completed.GenericServerRunOptions.AdvertiseAddress.String()
214 } else {
215 hostname, err := os.Hostname()
216 if err != nil {
217 return CompletedOptions{}, fmt.Errorf("error finding host name: %v", err)
218 }
219 completed.GenericServerRunOptions.ExternalHost = hostname
220 }
221 klog.Infof("external host was not specified, using %v", completed.GenericServerRunOptions.ExternalHost)
222 }
223
224
225 completed.Authorization.Complete()
226
227 completed.Authentication.ApplyAuthorization(completed.Authorization)
228
229
230
231
232
233
234 if completed.ServiceAccountSigningKeyFile == "" {
235
236 if len(completed.Authentication.ServiceAccounts.KeyFiles) == 0 && completed.SecureServing.ServerCert.CertKey.KeyFile != "" {
237 if kubeauthenticator.IsValidServiceAccountKeyFile(completed.SecureServing.ServerCert.CertKey.KeyFile) {
238 completed.Authentication.ServiceAccounts.KeyFiles = []string{completed.SecureServing.ServerCert.CertKey.KeyFile}
239 } else {
240 klog.Warning("No TLS key provided, service account token authentication disabled")
241 }
242 }
243 }
244
245 if completed.ServiceAccountSigningKeyFile != "" && len(completed.Authentication.ServiceAccounts.Issuers) != 0 && completed.Authentication.ServiceAccounts.Issuers[0] != "" {
246 sk, err := keyutil.PrivateKeyFromFile(completed.ServiceAccountSigningKeyFile)
247 if err != nil {
248 return CompletedOptions{}, fmt.Errorf("failed to parse service-account-issuer-key-file: %v", err)
249 }
250 if completed.Authentication.ServiceAccounts.MaxExpiration != 0 {
251 lowBound := time.Hour
252 upBound := time.Duration(1<<32) * time.Second
253 if completed.Authentication.ServiceAccounts.MaxExpiration < lowBound ||
254 completed.Authentication.ServiceAccounts.MaxExpiration > upBound {
255 return CompletedOptions{}, fmt.Errorf("the service-account-max-token-expiration must be between 1 hour and 2^32 seconds")
256 }
257 if completed.Authentication.ServiceAccounts.ExtendExpiration {
258 if completed.Authentication.ServiceAccounts.MaxExpiration < serviceaccount.WarnOnlyBoundTokenExpirationSeconds*time.Second {
259 klog.Warningf("service-account-extend-token-expiration is true, in order to correctly trigger safe transition logic, service-account-max-token-expiration must be set longer than %d seconds (currently %s)", serviceaccount.WarnOnlyBoundTokenExpirationSeconds, completed.Authentication.ServiceAccounts.MaxExpiration)
260 }
261 if completed.Authentication.ServiceAccounts.MaxExpiration < serviceaccount.ExpirationExtensionSeconds*time.Second {
262 klog.Warningf("service-account-extend-token-expiration is true, enabling tokens valid up to %d seconds, which is longer than service-account-max-token-expiration set to %s seconds", serviceaccount.ExpirationExtensionSeconds, completed.Authentication.ServiceAccounts.MaxExpiration)
263 }
264 }
265 }
266
267 completed.ServiceAccountIssuer, err = serviceaccount.JWTTokenGenerator(completed.Authentication.ServiceAccounts.Issuers[0], sk)
268 if err != nil {
269 return CompletedOptions{}, fmt.Errorf("failed to build token generator: %v", err)
270 }
271 completed.ServiceAccountTokenMaxExpiration = completed.Authentication.ServiceAccounts.MaxExpiration
272 }
273
274 for key, value := range completed.APIEnablement.RuntimeConfig {
275 if key == "v1" || strings.HasPrefix(key, "v1/") ||
276 key == "api/v1" || strings.HasPrefix(key, "api/v1/") {
277 delete(completed.APIEnablement.RuntimeConfig, key)
278 completed.APIEnablement.RuntimeConfig["/v1"] = value
279 }
280 if key == "api/legacy" {
281 delete(completed.APIEnablement.RuntimeConfig, key)
282 }
283 }
284
285 return CompletedOptions{
286 completedOptions: &completed,
287 }, nil
288 }
289
290
291
292
293
294 func ServiceIPRange(passedServiceClusterIPRange net.IPNet) (net.IPNet, net.IP, error) {
295 serviceClusterIPRange := passedServiceClusterIPRange
296 if passedServiceClusterIPRange.IP == nil {
297 klog.Warningf("No CIDR for service cluster IPs specified. Default value which was %s is deprecated and will be removed in future releases. Please specify it using --service-cluster-ip-range on kube-apiserver.", kubeoptions.DefaultServiceIPCIDR.String())
298 serviceClusterIPRange = kubeoptions.DefaultServiceIPCIDR
299 }
300
301 size := min(netutil.RangeSize(&serviceClusterIPRange), 1<<16)
302 if size < 8 {
303 return net.IPNet{}, net.IP{}, fmt.Errorf("the service cluster IP range must be at least %d IP addresses", 8)
304 }
305
306
307 apiServerServiceIP, err := netutil.GetIndexedIP(&serviceClusterIPRange, 1)
308 if err != nil {
309 return net.IPNet{}, net.IP{}, err
310 }
311 klog.V(4).Infof("Setting service IP to %q (read-write).", apiServerServiceIP)
312
313 return serviceClusterIPRange, apiServerServiceIP, nil
314 }
315
View as plain text