mirror of
https://github.com/k3s-io/kubernetes.git
synced 2026-07-17 02:06:23 +00:00
Merge pull request #138686 from neolit123/automated-cherry-pick-of-#138449-origin-release-1.33
Automated cherry pick of #138449: kubeadm: use the localAPIEndpoint for all API calls in 'init'
This commit is contained in:
@@ -19,10 +19,8 @@ package cmd
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -92,6 +90,7 @@ type initData struct {
|
||||
skipTokenPrint bool
|
||||
dryRun bool
|
||||
kubeconfig *clientcmdapi.Config
|
||||
kubeconfigOriginal *clientcmdapi.Config
|
||||
kubeconfigDir string
|
||||
kubeconfigPath string
|
||||
ignorePreflightErrors sets.Set[string]
|
||||
@@ -462,6 +461,9 @@ func (d *initData) CertificateDir() string {
|
||||
}
|
||||
|
||||
// KubeConfig returns a kubeconfig after loading it from KubeConfigPath().
|
||||
// If the default kubeconfig path is used (admin.conf), instead of constructing
|
||||
// a kubeconfig that points to the control plane endpoint, make it point to the localAPIEndpoint.
|
||||
// This would allow 'kubeadm init' to only talk to the local kube-apiserver instance.
|
||||
func (d *initData) KubeConfig() (*clientcmdapi.Config, error) {
|
||||
if d.kubeconfig != nil {
|
||||
return d.kubeconfig, nil
|
||||
@@ -472,10 +474,26 @@ func (d *initData) KubeConfig() (*clientcmdapi.Config, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
d.kubeconfigOriginal = d.kubeconfig.DeepCopy()
|
||||
|
||||
if d.kubeconfigPath == kubeadmconstants.GetAdminKubeConfigPath() {
|
||||
kubeconfigutil.PointKubeConfigToLocalAPIEndpoint(d.kubeconfig, &d.Cfg().LocalAPIEndpoint)
|
||||
}
|
||||
|
||||
return d.kubeconfig, nil
|
||||
}
|
||||
|
||||
// KubeConfigOriginal returns the original kubeconfig loaded from file, without any modifications.
|
||||
func (d *initData) KubeConfigOriginal() (*clientcmdapi.Config, error) {
|
||||
if d.kubeconfigOriginal == nil {
|
||||
if _, err := d.KubeConfig(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return d.kubeconfigOriginal, nil
|
||||
}
|
||||
|
||||
// KubeConfigDir returns the path of the Kubernetes configuration folder or the temporary folder path in case of DryRun.
|
||||
func (d *initData) KubeConfigDir() string {
|
||||
if d.dryRun {
|
||||
@@ -520,8 +538,12 @@ func (d *initData) OutputWriter() io.Writer {
|
||||
|
||||
// getDryRunClient creates a fake client that answers some GET calls in order to be able to do the full init flow in dry-run mode.
|
||||
func getDryRunClient(d *initData) (clientset.Interface, error) {
|
||||
kubeconfig, err := d.KubeConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dryRun := apiclient.NewDryRun()
|
||||
if err := dryRun.WithKubeConfigFile(d.KubeConfigPath()); err != nil {
|
||||
if err := dryRun.WithKubeConfig(kubeconfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dryRun.WithDefaultMarshalFunction().
|
||||
@@ -549,7 +571,11 @@ func (d *initData) Client() (clientset.Interface, error) {
|
||||
// and if the bootstrapping was not already done
|
||||
if !d.adminKubeConfigBootstrapped && isDefaultKubeConfigPath {
|
||||
// Call EnsureAdminClusterRoleBinding() to obtain a working client from admin.conf.
|
||||
d.client, err = kubeconfigphase.EnsureAdminClusterRoleBinding(kubeadmconstants.KubernetesDir, nil)
|
||||
d.client, err = kubeconfigphase.EnsureAdminClusterRoleBinding(
|
||||
kubeadmconstants.KubernetesDir,
|
||||
&d.Cfg().LocalAPIEndpoint,
|
||||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not bootstrap the admin user in file %s", kubeadmconstants.AdminKubeConfigFileName)
|
||||
}
|
||||
@@ -570,30 +596,6 @@ func (d *initData) Client() (clientset.Interface, error) {
|
||||
return d.client, nil
|
||||
}
|
||||
|
||||
// WaitControlPlaneClient returns a basic client used for the purpose of waiting
|
||||
// for control plane components to report 'ok' on their respective health check endpoints.
|
||||
// It uses the admin.conf as the base, but modifies it to point at the local API server instead
|
||||
// of the control plane endpoint.
|
||||
func (d *initData) WaitControlPlaneClient() (clientset.Interface, error) {
|
||||
config, err := clientcmd.LoadFromFile(d.KubeConfigPath())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, v := range config.Clusters {
|
||||
v.Server = fmt.Sprintf("https://%s",
|
||||
net.JoinHostPort(
|
||||
d.Cfg().LocalAPIEndpoint.AdvertiseAddress,
|
||||
strconv.Itoa(int(d.Cfg().LocalAPIEndpoint.BindPort)),
|
||||
),
|
||||
)
|
||||
}
|
||||
client, err := kubeconfigutil.ToClientSet(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// Tokens returns an array of token strings.
|
||||
func (d *initData) Tokens() []string {
|
||||
tokens := []string{}
|
||||
|
||||
@@ -72,7 +72,7 @@ func runBootstrapToken(c workflow.RunData) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
kubeconfig, err := data.KubeConfig()
|
||||
kubeconfig, err := data.KubeConfigOriginal()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ type InitData interface {
|
||||
CertificateWriteDir() string
|
||||
CertificateDir() string
|
||||
KubeConfig() (*clientcmdapi.Config, error)
|
||||
KubeConfigOriginal() (*clientcmdapi.Config, error)
|
||||
KubeConfigDir() string
|
||||
KubeConfigPath() string
|
||||
ManifestDir() string
|
||||
@@ -47,7 +48,6 @@ type InitData interface {
|
||||
ExternalCA() bool
|
||||
OutputWriter() io.Writer
|
||||
Client() (clientset.Interface, error)
|
||||
WaitControlPlaneClient() (clientset.Interface, error)
|
||||
Tokens() []string
|
||||
PatchesDir() string
|
||||
}
|
||||
|
||||
@@ -32,24 +32,24 @@ type testInitData struct{}
|
||||
// testInitData must satisfy InitData.
|
||||
var _ InitData = &testInitData{}
|
||||
|
||||
func (t *testInitData) UploadCerts() bool { return false }
|
||||
func (t *testInitData) CertificateKey() string { return "" }
|
||||
func (t *testInitData) SetCertificateKey(key string) {}
|
||||
func (t *testInitData) SkipCertificateKeyPrint() bool { return false }
|
||||
func (t *testInitData) Cfg() *kubeadmapi.InitConfiguration { return nil }
|
||||
func (t *testInitData) DryRun() bool { return false }
|
||||
func (t *testInitData) SkipTokenPrint() bool { return false }
|
||||
func (t *testInitData) IgnorePreflightErrors() sets.Set[string] { return nil }
|
||||
func (t *testInitData) CertificateWriteDir() string { return "" }
|
||||
func (t *testInitData) CertificateDir() string { return "" }
|
||||
func (t *testInitData) KubeConfig() (*clientcmdapi.Config, error) { return nil, nil }
|
||||
func (t *testInitData) KubeConfigDir() string { return "" }
|
||||
func (t *testInitData) KubeConfigPath() string { return "" }
|
||||
func (t *testInitData) ManifestDir() string { return "" }
|
||||
func (t *testInitData) KubeletDir() string { return "" }
|
||||
func (t *testInitData) ExternalCA() bool { return false }
|
||||
func (t *testInitData) OutputWriter() io.Writer { return nil }
|
||||
func (t *testInitData) Client() (clientset.Interface, error) { return nil, nil }
|
||||
func (t *testInitData) WaitControlPlaneClient() (clientset.Interface, error) { return nil, nil }
|
||||
func (t *testInitData) Tokens() []string { return nil }
|
||||
func (t *testInitData) PatchesDir() string { return "" }
|
||||
func (t *testInitData) UploadCerts() bool { return false }
|
||||
func (t *testInitData) CertificateKey() string { return "" }
|
||||
func (t *testInitData) SetCertificateKey(key string) {}
|
||||
func (t *testInitData) SkipCertificateKeyPrint() bool { return false }
|
||||
func (t *testInitData) Cfg() *kubeadmapi.InitConfiguration { return nil }
|
||||
func (t *testInitData) DryRun() bool { return false }
|
||||
func (t *testInitData) SkipTokenPrint() bool { return false }
|
||||
func (t *testInitData) IgnorePreflightErrors() sets.Set[string] { return nil }
|
||||
func (t *testInitData) CertificateWriteDir() string { return "" }
|
||||
func (t *testInitData) CertificateDir() string { return "" }
|
||||
func (t *testInitData) KubeConfig() (*clientcmdapi.Config, error) { return nil, nil }
|
||||
func (t *testInitData) KubeConfigOriginal() (*clientcmdapi.Config, error) { return nil, nil }
|
||||
func (t *testInitData) KubeConfigDir() string { return "" }
|
||||
func (t *testInitData) KubeConfigPath() string { return "" }
|
||||
func (t *testInitData) ManifestDir() string { return "" }
|
||||
func (t *testInitData) KubeletDir() string { return "" }
|
||||
func (t *testInitData) ExternalCA() bool { return false }
|
||||
func (t *testInitData) OutputWriter() io.Writer { return nil }
|
||||
func (t *testInitData) Client() (clientset.Interface, error) { return nil, nil }
|
||||
func (t *testInitData) Tokens() []string { return nil }
|
||||
func (t *testInitData) PatchesDir() string { return "" }
|
||||
|
||||
@@ -63,7 +63,7 @@ func runWaitControlPlanePhase(c workflow.RunData) error {
|
||||
}
|
||||
}
|
||||
|
||||
client, err := data.WaitControlPlaneClient()
|
||||
client, err := data.Client()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "cannot obtain client without bootstrap")
|
||||
}
|
||||
|
||||
@@ -623,14 +623,19 @@ type EnsureRBACFunc func(context.Context, clientset.Interface, clientset.Interfa
|
||||
// constructs a client from super-admin.conf if the file exists. It then proceeds
|
||||
// to pass the clients to EnsureAdminClusterRoleBindingImpl. The function returns a
|
||||
// usable client from admin.conf with RBAC properly constructed or an error.
|
||||
func EnsureAdminClusterRoleBinding(outDir string, ensureRBACFunc EnsureRBACFunc) (clientset.Interface, error) {
|
||||
func EnsureAdminClusterRoleBinding(outDir string, lae *kubeadmapi.APIEndpoint, ensureRBACFunc EnsureRBACFunc) (clientset.Interface, error) {
|
||||
var (
|
||||
err error
|
||||
adminClient, superAdminClient clientset.Interface
|
||||
)
|
||||
|
||||
// Create a client from admin.conf.
|
||||
adminClient, err = kubeconfigutil.ClientSetFromFile(filepath.Join(outDir, kubeadmconstants.AdminKubeConfigFileName))
|
||||
kubeconfig, err := clientcmd.LoadFromFile(filepath.Join(outDir, kubeadmconstants.AdminKubeConfigFileName))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
kubeconfigutil.PointKubeConfigToLocalAPIEndpoint(kubeconfig, lae)
|
||||
adminClient, err = kubeconfigutil.ToClientSet(kubeconfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -638,7 +643,12 @@ func EnsureAdminClusterRoleBinding(outDir string, ensureRBACFunc EnsureRBACFunc)
|
||||
// Create a client from super-admin.conf.
|
||||
superAdminPath := filepath.Join(outDir, kubeadmconstants.SuperAdminKubeConfigFileName)
|
||||
if _, err := os.Stat(superAdminPath); err == nil {
|
||||
superAdminClient, err = kubeconfigutil.ClientSetFromFile(superAdminPath)
|
||||
kubeconfig, err := clientcmd.LoadFromFile(superAdminPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
kubeconfigutil.PointKubeConfigToLocalAPIEndpoint(kubeconfig, lae)
|
||||
superAdminClient, err = kubeconfigutil.ToClientSet(kubeconfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -991,7 +991,7 @@ func TestEnsureAdminClusterRoleBinding(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
client, err := EnsureAdminClusterRoleBinding(dir, ensureRBACFunc)
|
||||
client, err := EnsureAdminClusterRoleBinding(dir, &kubeadmapi.APIEndpoint{}, ensureRBACFunc)
|
||||
if (err != nil) != tc.expectedError {
|
||||
t.Fatalf("expected error: %v, got: %v, error: %v", err != nil, tc.expectedError, err)
|
||||
}
|
||||
|
||||
@@ -18,13 +18,17 @@ package kubeconfig
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
)
|
||||
|
||||
// CreateBasic creates a basic, general KubeConfig object that then can be extended
|
||||
@@ -121,6 +125,18 @@ func GetClusterFromKubeConfig(config *clientcmdapi.Config) (string, *clientcmdap
|
||||
return "", nil, errors.Errorf("the current context is invalid: %s", config.CurrentContext)
|
||||
}
|
||||
|
||||
// PointKubeConfigToLocalAPIEndpoint modifies the provided kubeconfig to point to the given APIEndpoint.
|
||||
func PointKubeConfigToLocalAPIEndpoint(config *clientcmdapi.Config, lae *kubeadmapi.APIEndpoint) {
|
||||
for _, v := range config.Clusters {
|
||||
v.Server = fmt.Sprintf("https://%s",
|
||||
net.JoinHostPort(
|
||||
lae.AdvertiseAddress,
|
||||
strconv.Itoa(int(lae.BindPort)),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// HasAuthenticationCredentials returns true if the current user has valid authentication credentials for
|
||||
// token authentication, basic authentication or X509 authentication
|
||||
func HasAuthenticationCredentials(config *clientcmdapi.Config) bool {
|
||||
|
||||
Reference in New Issue
Block a user