// RunCreateToken generates a new bootstrap token and stores it as a secret on the server. func RunCreateToken(out io.Writer, cmd *cobra.Command, tokenDuration time.Duration, token string) error { client, err := kubemaster.CreateClientFromFile(path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, "admin.conf")) if err != nil { return err } d := &kubeadmapi.TokenDiscovery{} if token != "" { parsedID, parsedSecret, err := kubeadmutil.ParseToken(token) if err != nil { return err } d.ID = parsedID d.Secret = parsedSecret } err = kubeadmutil.GenerateTokenIfNeeded(d) if err != nil { return err } err = kubeadmutil.UpdateOrCreateToken(client, d, tokenDuration) if err != nil { return err } fmt.Fprintln(out, kubeadmutil.BearerToken(d)) return nil }
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 }
// EstablishMasterConnection establishes a connection with exactly one of the provided API endpoints. // The function builds a client for every endpoint and concurrently keeps trying to connect to any one // of the provided endpoints. Blocks until at least one connection is established, then it stops the // connection attempts for other endpoints. func EstablishMasterConnection(c *kubeadmapi.TokenDiscovery, clusterInfo *kubeadmapi.ClusterInfo) (*ConnectionDetails, error) { hostName, err := os.Hostname() if err != nil { return nil, fmt.Errorf("failed to get node hostname [%v]", err) } // TODO(phase1+) https://github.com/kubernetes/kubernetes/issues/33641 nodeName := types.NodeName(hostName) endpoints := clusterInfo.Endpoints caCert := []byte(clusterInfo.CertificateAuthorities[0]) stopChan := make(chan struct{}) result := make(chan *ConnectionDetails) var wg sync.WaitGroup for _, endpoint := range endpoints { clientSet, err := createClients(caCert, endpoint, kubeadmutil.BearerToken(c), nodeName) if err != nil { fmt.Printf("[bootstrap] Warning: %s. Skipping endpoint %s\n", err, endpoint) continue } wg.Add(1) go func(apiEndpoint string) { defer wg.Done() wait.Until(func() { fmt.Printf("[bootstrap] Trying to connect to endpoint %s\n", apiEndpoint) err := checkAPIEndpoint(clientSet, apiEndpoint) if err != nil { fmt.Printf("[bootstrap] Endpoint check failed [%v]\n", err) return } fmt.Printf("[bootstrap] Successfully established connection with endpoint %q\n", apiEndpoint) // connection established, stop all wait threads close(stopChan) result <- &ConnectionDetails{ ClientSet: clientSet, CertClient: clientSet.CertificatesV1alpha1Client, Endpoint: apiEndpoint, CACert: caCert, NodeName: nodeName, } }, retryTimeout*time.Second, stopChan) }(endpoint) } go func() { wg.Wait() // all wait.Until() calls have finished now close(result) }() establishedConnection, ok := <-result if !ok { return nil, fmt.Errorf("failed to create bootstrap clients for any of the provided API endpoints") } return establishedConnection, nil }
func RunGenerateToken(out io.Writer) error { td := &kubeadmapi.TokenDiscovery{} err := kubeadmutil.GenerateToken(td) if err != nil { return err } fmt.Fprintln(out, kubeadmutil.BearerToken(td)) return nil }
func generateTokenIfNeeded(d *kubeadmapi.TokenDiscovery) error { ok, err := kubeadmutil.IsTokenValid(d) if err != nil { return err } if ok { fmt.Println("[tokens] Accepted provided token") return nil } if err := kubeadmutil.GenerateToken(d); err != nil { return err } fmt.Printf("[tokens] Generated token: %q\n", kubeadmutil.BearerToken(d)) return nil }
// EstablishMasterConnection establishes a connection with exactly one of the provided API endpoints. // The function builds a client for every endpoint and concurrently keeps trying to connect to any one // of the provided endpoints. Blocks until at least one connection is established, then it stops the // connection attempts for other endpoints and returns the valid client configuration, if any. func EstablishMasterConnection(c *kubeadmapi.TokenDiscovery, clusterInfo *kubeadmapi.ClusterInfo) (*clientcmdapi.Config, error) { hostName, err := os.Hostname() if err != nil { return nil, fmt.Errorf("failed to get node hostname [%v]", err) } // TODO(phase1+) https://github.com/kubernetes/kubernetes/issues/33641 nodeName := types.NodeName(hostName) endpoints := clusterInfo.Endpoints caCert := []byte(clusterInfo.CertificateAuthorities[0]) stopChan := make(chan struct{}) var clientConfig *clientcmdapi.Config var once sync.Once var wg sync.WaitGroup for _, endpoint := range endpoints { ac, err := createClients(caCert, endpoint, kubeadmutil.BearerToken(c), nodeName) if err != nil { fmt.Printf("[bootstrap] Warning: %s. Skipping endpoint %s\n", err, endpoint) continue } wg.Add(1) go func(apiEndpoint string) { defer wg.Done() wait.Until(func() { fmt.Printf("[bootstrap] Trying to connect to endpoint %s\n", apiEndpoint) err := checkAPIEndpoint(ac.clientSet, apiEndpoint) if err != nil { fmt.Printf("[bootstrap] Endpoint check failed [%v]\n", err) return } fmt.Printf("[bootstrap] Successfully established connection with endpoint %q\n", apiEndpoint) // connection established, stop all wait threads close(stopChan) once.Do(func() { clientConfig = ac.clientConfig }) }, retryTimeout*time.Second, stopChan) }(endpoint) } wg.Wait() if clientConfig == nil { return nil, fmt.Errorf("failed to create bootstrap clients for any of the provided API endpoints") } return clientConfig, nil }
// RunCreateToken generates a new bootstrap token and stores it as a secret on the server. func RunCreateToken(out io.Writer, cmd *cobra.Command, tokenDuration time.Duration, token string) error { client, err := kubemaster.CreateClientFromFile(path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, kubeconfig.AdminKubeConfigFileName)) if err != nil { return err } parsedID, parsedSecret, err := kubeadmutil.ParseToken(token) if err != nil { return err } td := &kubeadmapi.TokenDiscovery{ID: parsedID, Secret: parsedSecret} err = kubeadmutil.UpdateOrCreateToken(client, td, tokenDuration) if err != nil { return err } fmt.Fprintln(out, kubeadmutil.BearerToken(td)) return nil }
// Run executes master node provisioning, including certificates, needed static pod manifests, etc. func (i *Init) Run(out io.Writer) error { if i.cfg.Discovery.Token != nil { if err := kubemaster.PrepareTokenDiscovery(i.cfg.Discovery.Token); err != nil { return err } if err := kubemaster.CreateTokenAuthFile(kubeadmutil.BearerToken(i.cfg.Discovery.Token)); err != nil { return err } } if err := kubemaster.WriteStaticPodManifests(i.cfg); err != nil { return err } caKey, caCert, err := kubemaster.CreatePKIAssets(i.cfg) if err != nil { return err } kubeconfigs, err := kubemaster.CreateCertsAndConfigForClients(i.cfg.API, []string{"kubelet", "admin"}, caKey, caCert) if err != nil { return err } // kubeadm is responsible for writing the following kubeconfig file, which // kubelet should be waiting for. Help user avoid foot-shooting by refusing to // write a file that has already been written (the kubelet will be up and // running in that case - they'd need to stop the kubelet, remove the file, and // start it again in that case). // TODO(phase1+) this is no longer the right place to guard against foo-shooting, // we need to decide how to handle existing files (it may be handy to support // importing existing files, may be we could even make our command idempotant, // or at least allow for external PKI and stuff) for name, kubeconfig := range kubeconfigs { if err := kubeadmutil.WriteKubeconfigIfNotExists(name, kubeconfig); err != nil { return err } } client, err := kubemaster.CreateClientAndWaitForAPI(kubeconfigs["admin"]) if err != nil { return err } if err := kubemaster.UpdateMasterRoleLabelsAndTaints(client, false); err != nil { return err } if i.cfg.Discovery.Token != nil { if err := kubemaster.CreateDiscoveryDeploymentAndSecret(i.cfg, client, caCert); err != nil { return err } } if err := kubemaster.CreateEssentialAddons(i.cfg, client); err != nil { return err } fmt.Fprintf(out, initDoneMsgf, generateJoinArgs(i.cfg)) return nil }
// Run executes master node provisioning, including certificates, needed static pod manifests, etc. func (i *Init) Run(out io.Writer) error { // PHASE 1: Generate certificates caCert, err := certphase.CreatePKIAssets(i.cfg, kubeadmapi.GlobalEnvParams.HostPKIPath) if err != nil { return err } // PHASE 2: Generate kubeconfig files for the admin and the kubelet // TODO this is not great, but there is only one address we can use here // so we'll pick the first one, there is much of chance to have an empty // slice by the time this gets called masterEndpoint := fmt.Sprintf("https://%s:%d", i.cfg.API.AdvertiseAddresses[0], i.cfg.API.Port) err = kubeconfigphase.CreateAdminAndKubeletKubeConfig(masterEndpoint, kubeadmapi.GlobalEnvParams.HostPKIPath, kubeadmapi.GlobalEnvParams.KubernetesDir) if err != nil { 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 } client, err := kubemaster.CreateClientAndWaitForAPI(path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, kubeconfigphase.AdminKubeConfigFileName)) if err != nil { return err } if i.cfg.AuthorizationMode == "RBAC" { err = apiconfig.CreateBootstrapRBACClusterRole(client) if err != nil { return err } err = apiconfig.CreateKubeDNSRBACClusterRole(client) if err != nil { return err } // TODO: remove this when https://github.com/kubernetes/kubeadm/issues/114 is fixed err = apiconfig.CreateKubeProxyClusterRoleBinding(client) if err != nil { return err } } if err := kubemaster.UpdateMasterRoleLabelsAndTaints(client, false); err != nil { return err } if i.cfg.Discovery.Token != nil { fmt.Printf("[token-discovery] Using token: %s\n", kubeadmutil.BearerToken(i.cfg.Discovery.Token)) if err := kubemaster.CreateDiscoveryDeploymentAndSecret(i.cfg, client, caCert); err != nil { return err } if err := kubeadmutil.UpdateOrCreateToken(client, i.cfg.Discovery.Token, kubeadmutil.DefaultTokenDuration); err != nil { return err } } if err := kubemaster.CreateEssentialAddons(i.cfg, client); err != nil { return err } fmt.Fprintf(out, initDoneMsgf, generateJoinArgs(i.cfg)) return nil }