2019-01-12 04:58:27 +00:00
/ *
Copyright 2014 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 (
"errors"
"fmt"
2019-09-27 21:51:53 +00:00
"net"
"strings"
2019-01-12 04:58:27 +00:00
apiextensionsapiserver "k8s.io/apiextensions-apiserver/pkg/apiserver"
2020-08-10 17:43:49 +00:00
genericfeatures "k8s.io/apiserver/pkg/features"
2019-01-12 04:58:27 +00:00
utilfeature "k8s.io/apiserver/pkg/util/feature"
aggregatorscheme "k8s.io/kube-aggregator/pkg/apiserver/scheme"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/features"
2019-09-27 21:51:53 +00:00
netutils "k8s.io/utils/net"
2019-01-12 04:58:27 +00:00
)
// TODO: Longer term we should read this from some config store, rather than a flag.
2019-09-27 21:51:53 +00:00
// validateClusterIPFlags is expected to be called after Complete()
2019-01-12 04:58:27 +00:00
func validateClusterIPFlags ( options * ServerRunOptions ) [ ] error {
var errs [ ] error
2020-08-10 17:43:49 +00:00
// maxCIDRBits is used to define the maximum CIDR size for the cluster ip(s)
const maxCIDRBits = 20
2019-01-12 04:58:27 +00:00
2019-09-27 21:51:53 +00:00
// validate that primary has been processed by user provided values or it has been defaulted
if options . PrimaryServiceClusterIPRange . IP == nil {
errs = append ( errs , errors . New ( "--service-cluster-ip-range must contain at least one valid cidr" ) )
2019-01-12 04:58:27 +00:00
}
2019-09-27 21:51:53 +00:00
serviceClusterIPRangeList := strings . Split ( options . ServiceClusterIPRanges , "," )
if len ( serviceClusterIPRangeList ) > 2 {
errs = append ( errs , errors . New ( "--service-cluster-ip-range must not contain more than two entries" ) )
}
// Complete() expected to have set Primary* and Secondary*
// primary CIDR validation
2020-08-10 17:43:49 +00:00
if err := validateMaxCIDRRange ( options . PrimaryServiceClusterIPRange , maxCIDRBits , "--service-cluster-ip-range" ) ; err != nil {
errs = append ( errs , err )
2019-01-12 04:58:27 +00:00
}
2019-09-27 21:51:53 +00:00
// Secondary IP validation
2021-03-18 22:40:29 +00:00
// ControllerManager needs DualStack feature flags
2019-09-27 21:51:53 +00:00
secondaryServiceClusterIPRangeUsed := ( options . SecondaryServiceClusterIPRange . IP != nil )
2021-03-18 22:40:29 +00:00
if secondaryServiceClusterIPRangeUsed && ! utilfeature . DefaultFeatureGate . Enabled ( features . IPv6DualStack ) {
errs = append ( errs , fmt . Errorf ( "secondary service cluster-ip range(--service-cluster-ip-range[1]) can only be used if %v feature is enabled" , string ( features . IPv6DualStack ) ) )
2019-09-27 21:51:53 +00:00
}
// note: While the cluster might be dualstack (i.e. pods with multiple IPs), the user may choose
// to only ingress traffic within and into the cluster on one IP family only. this family is decided
// by the range set on --service-cluster-ip-range. If/when the user decides to use dual stack services
// the Secondary* must be of different IPFamily than --service-cluster-ip-range
if secondaryServiceClusterIPRangeUsed {
// Should be dualstack IPFamily(PrimaryServiceClusterIPRange) != IPFamily(SecondaryServiceClusterIPRange)
dualstack , err := netutils . IsDualStackCIDRs ( [ ] * net . IPNet { & options . PrimaryServiceClusterIPRange , & options . SecondaryServiceClusterIPRange } )
if err != nil {
2020-12-01 01:06:26 +00:00
errs = append ( errs , fmt . Errorf ( "error attempting to validate dualstack for --service-cluster-ip-range value error:%v" , err ) )
2019-09-27 21:51:53 +00:00
}
if ! dualstack {
2020-12-01 01:06:26 +00:00
errs = append ( errs , errors . New ( "--service-cluster-ip-range[0] and --service-cluster-ip-range[1] must be of different IP family" ) )
2019-09-27 21:51:53 +00:00
}
2020-12-01 01:06:26 +00:00
if err := validateMaxCIDRRange ( options . SecondaryServiceClusterIPRange , maxCIDRBits , "--service-cluster-ip-range[1]" ) ; err != nil {
2020-08-10 17:43:49 +00:00
errs = append ( errs , err )
2019-09-27 21:51:53 +00:00
}
}
2019-01-12 04:58:27 +00:00
return errs
}
2020-08-10 17:43:49 +00:00
func validateMaxCIDRRange ( cidr net . IPNet , maxCIDRBits int , cidrFlag string ) error {
// Should be smallish sized cidr, this thing is kept in etcd
// bigger cidr (specially those offered by IPv6) will add no value
// significantly increase snapshotting time.
var ones , bits = cidr . Mask . Size ( )
if bits - ones > maxCIDRBits {
return fmt . Errorf ( "specified %s is too large; for %d-bit addresses, the mask must be >= %d" , cidrFlag , bits , bits - maxCIDRBits )
}
return nil
}
2019-01-12 04:58:27 +00:00
func validateServiceNodePort ( options * ServerRunOptions ) [ ] error {
var errs [ ] error
if options . KubernetesServiceNodePort < 0 || options . KubernetesServiceNodePort > 65535 {
errs = append ( errs , fmt . Errorf ( "--kubernetes-service-node-port %v must be between 0 and 65535, inclusive. If 0, the Kubernetes master service will be of type ClusterIP" , options . KubernetesServiceNodePort ) )
}
if options . KubernetesServiceNodePort > 0 && ! options . ServiceNodePortRange . Contains ( options . KubernetesServiceNodePort ) {
errs = append ( errs , fmt . Errorf ( "kubernetes service port range %v doesn't contain %v" , options . ServiceNodePortRange , ( options . KubernetesServiceNodePort ) ) )
}
return errs
}
func validateTokenRequest ( options * ServerRunOptions ) [ ] error {
var errs [ ] error
enableAttempted := options . ServiceAccountSigningKeyFile != "" ||
options . Authentication . ServiceAccounts . Issuer != "" ||
len ( options . Authentication . APIAudiences ) != 0
enableSucceeded := options . ServiceAccountIssuer != nil
2020-12-01 01:06:26 +00:00
if ! enableAttempted {
2019-08-30 18:33:25 +00:00
errs = append ( errs , errors . New ( "--service-account-signing-key-file and --service-account-issuer are required flags" ) )
}
2019-01-12 04:58:27 +00:00
if enableAttempted && ! enableSucceeded {
errs = append ( errs , errors . New ( "--service-account-signing-key-file, --service-account-issuer, and --api-audiences should be specified together" ) )
}
return errs
}
2020-08-10 17:43:49 +00:00
func validateAPIPriorityAndFairness ( options * ServerRunOptions ) [ ] error {
if utilfeature . DefaultFeatureGate . Enabled ( genericfeatures . APIPriorityAndFairness ) && options . GenericServerRunOptions . EnablePriorityAndFairness {
2020-12-01 01:06:26 +00:00
// If none of the following runtime config options are specified, APF is
// assumed to be turned on.
2020-08-10 17:43:49 +00:00
enabledAPIString := options . APIEnablement . RuntimeConfig . String ( )
2020-12-01 01:06:26 +00:00
testConfigs := [ ] string { "flowcontrol.apiserver.k8s.io/v1beta1" , "api/beta" , "api/all" } // in the order of precedence
for _ , testConfig := range testConfigs {
if strings . Contains ( enabledAPIString , fmt . Sprintf ( "%s=false" , testConfig ) ) {
2021-03-18 22:40:29 +00:00
return [ ] error { fmt . Errorf ( "--runtime-config=%s=false conflicts with --enable-priority-and-fairness=true and --feature-gates=APIPriorityAndFairness=true" , testConfig ) }
2020-12-01 01:06:26 +00:00
}
if strings . Contains ( enabledAPIString , fmt . Sprintf ( "%s=true" , testConfig ) ) {
return nil
}
2020-08-10 17:43:49 +00:00
}
}
return nil
}
2021-03-18 22:40:29 +00:00
func validateAPIServerIdentity ( options * ServerRunOptions ) [ ] error {
var errs [ ] error
if options . IdentityLeaseDurationSeconds <= 0 {
errs = append ( errs , fmt . Errorf ( "--identity-lease-duration-seconds should be a positive number, but value '%d' provided" , options . IdentityLeaseDurationSeconds ) )
}
if options . IdentityLeaseRenewIntervalSeconds <= 0 {
errs = append ( errs , fmt . Errorf ( "--identity-lease-renew-interval-seconds should be a positive number, but value '%d' provided" , options . IdentityLeaseRenewIntervalSeconds ) )
}
return errs
}
2019-01-12 04:58:27 +00:00
// Validate checks ServerRunOptions and return a slice of found errs.
func ( s * ServerRunOptions ) Validate ( ) [ ] error {
var errs [ ] error
if s . MasterCount <= 0 {
errs = append ( errs , fmt . Errorf ( "--apiserver-count should be a positive number, but value '%d' provided" , s . MasterCount ) )
}
errs = append ( errs , s . Etcd . Validate ( ) ... )
errs = append ( errs , validateClusterIPFlags ( s ) ... )
errs = append ( errs , validateServiceNodePort ( s ) ... )
2020-08-10 17:43:49 +00:00
errs = append ( errs , validateAPIPriorityAndFairness ( s ) ... )
2019-01-12 04:58:27 +00:00
errs = append ( errs , s . SecureServing . Validate ( ) ... )
errs = append ( errs , s . Authentication . Validate ( ) ... )
errs = append ( errs , s . Authorization . Validate ( ) ... )
errs = append ( errs , s . Audit . Validate ( ) ... )
errs = append ( errs , s . Admission . Validate ( ) ... )
errs = append ( errs , s . APIEnablement . Validate ( legacyscheme . Scheme , apiextensionsapiserver . Scheme , aggregatorscheme . Scheme ) ... )
errs = append ( errs , validateTokenRequest ( s ) ... )
2020-08-10 17:43:49 +00:00
errs = append ( errs , s . Metrics . Validate ( ) ... )
errs = append ( errs , s . Logs . Validate ( ) ... )
2021-03-18 22:40:29 +00:00
errs = append ( errs , validateAPIServerIdentity ( s ) ... )
2019-01-12 04:58:27 +00:00
return errs
}