diff --git a/cmd/kubeadm/app/apis/kubeadm/v1alpha1/defaults.go b/cmd/kubeadm/app/apis/kubeadm/v1alpha1/defaults.go index 2d5c0d27303..23785f3abc7 100644 --- a/cmd/kubeadm/app/apis/kubeadm/v1alpha1/defaults.go +++ b/cmd/kubeadm/app/apis/kubeadm/v1alpha1/defaults.go @@ -19,13 +19,15 @@ package v1alpha1 import "k8s.io/apimachinery/pkg/runtime" const ( - DefaultServiceDNSDomain = "cluster.local" - DefaultServicesSubnet = "10.96.0.0/12" - DefaultKubernetesVersion = "stable" - DefaultKubernetesFallbackVersion = "v1.5.0" + DefaultServiceDNSDomain = "cluster.local" + DefaultServicesSubnet = "10.96.0.0/12" + DefaultKubernetesVersion = "stable" + // This is only for clusters without internet, were the latest stable version can't be determined + DefaultKubernetesFallbackVersion = "v1.5.2" DefaultAPIBindPort = 6443 DefaultDiscoveryBindPort = 9898 - DefaultAuthorizationMode = "RBAC" + // TODO: Default this to RBAC when DefaultKubernetesFallbackVersion is v1.6-something + DefaultAuthorizationMode = "AlwaysAllow" ) func addDefaultingFuncs(scheme *runtime.Scheme) error { diff --git a/cmd/kubeadm/app/cmd/BUILD b/cmd/kubeadm/app/cmd/BUILD index 880f7acd327..646c48808f3 100644 --- a/cmd/kubeadm/app/cmd/BUILD +++ b/cmd/kubeadm/app/cmd/BUILD @@ -12,6 +12,7 @@ go_library( name = "go_default_library", srcs = [ "cmd.go", + "defaults.go", "init.go", "join.go", "reset.go", @@ -39,6 +40,7 @@ go_library( "//pkg/util/flag:go_default_library", "//pkg/util/initsystem:go_default_library", "//pkg/version:go_default_library", + "//vendor:github.com/blang/semver", "//vendor:github.com/renstrom/dedent", "//vendor:github.com/spf13/cobra", "//vendor:k8s.io/apimachinery/pkg/fields", diff --git a/cmd/kubeadm/app/cmd/defaults.go b/cmd/kubeadm/app/cmd/defaults.go new file mode 100644 index 00000000000..c834f05cab9 --- /dev/null +++ b/cmd/kubeadm/app/cmd/defaults.go @@ -0,0 +1,94 @@ +/* +Copyright 2017 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 cmd + +import ( + "fmt" + "strconv" + + netutil "k8s.io/apimachinery/pkg/util/net" + kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" + kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1" + kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" + + "github.com/blang/semver" +) + +var ( + // Maximum version when using AllowAll as the default authz mode. Everything above this will use RBAC by default. + allowAllMaxVersion = semver.MustParse("1.6.0-alpha.0") +) + +func setInitDynamicDefaults(cfg *kubeadmapi.MasterConfiguration) error { + // Auto-detect the IP + if len(cfg.API.AdvertiseAddresses) == 0 { + ip, err := netutil.ChooseHostInterface() + if err != nil { + return err + } + cfg.API.AdvertiseAddresses = []string{ip.String()} + } + + // Validate version argument + ver, err := kubeadmutil.KubernetesReleaseVersion(cfg.KubernetesVersion) + if err != nil { + if cfg.KubernetesVersion != kubeadmapiext.DefaultKubernetesVersion { + return err + } else { + ver = kubeadmapiext.DefaultKubernetesFallbackVersion + } + } + cfg.KubernetesVersion = ver + fmt.Println("[init] Using Kubernetes version:", ver) + + // Omit the "v" in the beginning, otherwise semver will fail + // If the version is newer than the specified version, RBAC v1beta1 support is enabled in the apiserver so we can default to RBAC + k8sVersion, err := semver.Parse(cfg.KubernetesVersion[1:]) + if k8sVersion.GT(allowAllMaxVersion) { + cfg.AuthorizationMode = "RBAC" + } + + fmt.Println("[init] Using Authorization mode:", cfg.AuthorizationMode) + + // Warn about the limitations with the current cloudprovider solution. + if cfg.CloudProvider != "" { + fmt.Println("[init] WARNING: For cloudprovider integrations to work --cloud-provider must be set for all kubelets in the cluster.") + fmt.Println("\t(/etc/systemd/system/kubelet.service.d/10-kubeadm.conf should be edited for this purpose)") + } + + // Validate token if any, otherwise generate + if cfg.Discovery.Token != nil { + if cfg.Discovery.Token.ID != "" && cfg.Discovery.Token.Secret != "" { + fmt.Printf("[init] A token has been provided, validating [%s]\n", kubeadmutil.BearerToken(cfg.Discovery.Token)) + if valid, err := kubeadmutil.ValidateToken(cfg.Discovery.Token); valid == false { + return err + } + } else { + fmt.Println("[init] A token has not been provided, generating one") + if err := kubeadmutil.GenerateToken(cfg.Discovery.Token); err != nil { + return err + } + } + + // If there aren't any addresses specified, default to the first advertised address which can be user-provided or the default network interface's IP address + if len(cfg.Discovery.Token.Addresses) == 0 { + cfg.Discovery.Token.Addresses = []string{cfg.API.AdvertiseAddresses[0] + ":" + strconv.Itoa(kubeadmapiext.DefaultDiscoveryBindPort)} + } + } + + return nil +} diff --git a/cmd/kubeadm/app/cmd/init.go b/cmd/kubeadm/app/cmd/init.go index 0952f46a740..124f15e17e3 100644 --- a/cmd/kubeadm/app/cmd/init.go +++ b/cmd/kubeadm/app/cmd/init.go @@ -21,7 +21,6 @@ import ( "io" "io/ioutil" "path" - "strconv" "github.com/renstrom/dedent" "github.com/spf13/cobra" @@ -38,7 +37,7 @@ import ( kubeconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig" "k8s.io/apimachinery/pkg/runtime" - netutil "k8s.io/apimachinery/pkg/util/net" + "k8s.io/kubernetes/cmd/kubeadm/app/preflight" kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" "k8s.io/kubernetes/pkg/api" @@ -145,13 +144,10 @@ func NewInit(cfgPath string, cfg *kubeadmapi.MasterConfiguration, skipPreFlight } } - // Auto-detect the IP - if len(cfg.API.AdvertiseAddresses) == 0 { - ip, err := netutil.ChooseHostInterface() - if err != nil { - return nil, err - } - cfg.API.AdvertiseAddresses = []string{ip.String()} + // Set defaults dynamically that the API group defaulting can't (by fetching information from the internet, looking up network interfaces, etc.) + err := setInitDynamicDefaults(cfg) + if err != nil { + return nil, err } if !skipPreFlight { @@ -173,25 +169,6 @@ func NewInit(cfgPath string, cfg *kubeadmapi.MasterConfiguration, skipPreFlight // Try to start the kubelet service in case it's inactive preflight.TryStartKubelet() - // validate version argument - ver, err := kubeadmutil.KubernetesReleaseVersion(cfg.KubernetesVersion) - if err != nil { - if cfg.KubernetesVersion != kubeadmapiext.DefaultKubernetesVersion { - return nil, err - } else { - ver = kubeadmapiext.DefaultKubernetesFallbackVersion - } - } - cfg.KubernetesVersion = ver - fmt.Println("[init] Using Kubernetes version:", ver) - fmt.Println("[init] Using Authorization mode:", cfg.AuthorizationMode) - - // Warn about the limitations with the current cloudprovider solution. - if cfg.CloudProvider != "" { - fmt.Println("WARNING: For cloudprovider integrations to work --cloud-provider must be set for all kubelets in the cluster.") - fmt.Println("\t(/etc/systemd/system/kubelet.service.d/10-kubeadm.conf should be edited for this purpose)") - } - return &Init{cfg: cfg}, nil } @@ -202,34 +179,6 @@ func (i *Init) Validate() error { // Run executes master node provisioning, including certificates, needed static pod manifests, etc. func (i *Init) Run(out io.Writer) error { - // Validate token if any, otherwise generate - if i.cfg.Discovery.Token != nil { - if i.cfg.Discovery.Token.ID != "" && i.cfg.Discovery.Token.Secret != "" { - fmt.Printf("[token-discovery] A token has been provided, validating [%s]\n", kubeadmutil.BearerToken(i.cfg.Discovery.Token)) - if valid, err := kubeadmutil.ValidateToken(i.cfg.Discovery.Token); valid == false { - return err - } - } else { - fmt.Println("[token-discovery] A token has not been provided, generating one") - if err := kubeadmutil.GenerateToken(i.cfg.Discovery.Token); err != nil { - return err - } - } - - // Make sure there is at least one address - if len(i.cfg.Discovery.Token.Addresses) == 0 { - ip, err := netutil.ChooseHostInterface() - if err != nil { - return err - } - i.cfg.Discovery.Token.Addresses = []string{ip.String() + ":" + strconv.Itoa(kubeadmapiext.DefaultDiscoveryBindPort)} - } - - if err := kubemaster.CreateTokenAuthFile(kubeadmutil.BearerToken(i.cfg.Discovery.Token)); err != nil { - return err - } - } - // PHASE 1: Generate certificates caCert, err := certphase.CreatePKIAssets(i.cfg, kubeadmapi.GlobalEnvParams.HostPKIPath) if err != nil { @@ -247,6 +196,14 @@ func (i *Init) Run(out io.Writer) error { return err } + // TODO: It's not great to have an exception for token here, but necessary because the apiserver doesn't handle this properly in the API yet + // but relies on files on disk for now, which is daunting. + if i.cfg.Discovery.Token != nil { + if err := kubemaster.CreateTokenAuthFile(kubeadmutil.BearerToken(i.cfg.Discovery.Token)); err != nil { + return err + } + } + // Phase 3: Bootstrap the control plane if err := kubemaster.WriteStaticPodManifests(i.cfg); err != nil { return err