Skip to content

Commit c5ea727

Browse files
Merge pull request #2664 from jubittajohn/rebase-v1.35.5
OCPBUGS-85499: Bump Kubernetes v1.35.5 to release-4.22
2 parents 6b9ddbe + c3b2ba2 commit c5ea727

36 files changed

Lines changed: 2389 additions & 254 deletions

CHANGELOG/CHANGELOG-1.35.md

Lines changed: 169 additions & 53 deletions
Large diffs are not rendered by default.

cmd/kubeadm/app/cmd/init.go

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,9 @@ package cmd
1919
import (
2020
"fmt"
2121
"io"
22-
"net"
2322
"os"
2423
"path/filepath"
2524
"slices"
26-
"strconv"
2725

2826
"github.com/spf13/cobra"
2927
flag "github.com/spf13/pflag"
@@ -93,6 +91,7 @@ type initData struct {
9391
skipTokenPrint bool
9492
dryRun bool
9593
kubeconfig *clientcmdapi.Config
94+
kubeconfigOriginal *clientcmdapi.Config
9695
kubeconfigDir string
9796
kubeconfigPath string
9897
ignorePreflightErrors sets.Set[string]
@@ -463,6 +462,9 @@ func (d *initData) CertificateDir() string {
463462
}
464463

465464
// KubeConfig returns a kubeconfig after loading it from KubeConfigPath().
465+
// If the default kubeconfig path is used (admin.conf), instead of constructing
466+
// a kubeconfig that points to the control plane endpoint, make it point to the localAPIEndpoint.
467+
// This would allow 'kubeadm init' to only talk to the local kube-apiserver instance.
466468
func (d *initData) KubeConfig() (*clientcmdapi.Config, error) {
467469
if d.kubeconfig != nil {
468470
return d.kubeconfig, nil
@@ -473,10 +475,26 @@ func (d *initData) KubeConfig() (*clientcmdapi.Config, error) {
473475
if err != nil {
474476
return nil, err
475477
}
478+
d.kubeconfigOriginal = d.kubeconfig.DeepCopy()
479+
480+
if d.kubeconfigPath == kubeadmconstants.GetAdminKubeConfigPath() {
481+
kubeconfigutil.PointKubeConfigToLocalAPIEndpoint(d.kubeconfig, &d.Cfg().LocalAPIEndpoint)
482+
}
476483

477484
return d.kubeconfig, nil
478485
}
479486

487+
// KubeConfigOriginal returns the original kubeconfig loaded from file, without any modifications.
488+
func (d *initData) KubeConfigOriginal() (*clientcmdapi.Config, error) {
489+
if d.kubeconfigOriginal == nil {
490+
if _, err := d.KubeConfig(); err != nil {
491+
return nil, err
492+
}
493+
}
494+
495+
return d.kubeconfigOriginal, nil
496+
}
497+
480498
// KubeConfigDir returns the Kubernetes configuration directory or the temporary directory if DryRun is true.
481499
func (d *initData) KubeConfigDir() string {
482500
if d.dryRun {
@@ -521,8 +539,12 @@ func (d *initData) OutputWriter() io.Writer {
521539

522540
// 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.
523541
func getDryRunClient(d *initData) (clientset.Interface, error) {
542+
kubeconfig, err := d.KubeConfig()
543+
if err != nil {
544+
return nil, err
545+
}
524546
dryRun := apiclient.NewDryRun()
525-
if err := dryRun.WithKubeConfigFile(d.KubeConfigPath()); err != nil {
547+
if err := dryRun.WithKubeConfig(kubeconfig); err != nil {
526548
return nil, err
527549
}
528550
dryRun.WithDefaultMarshalFunction().
@@ -550,7 +572,11 @@ func (d *initData) Client() (clientset.Interface, error) {
550572
// and if the bootstrapping was not already done
551573
if !d.adminKubeConfigBootstrapped && isDefaultKubeConfigPath {
552574
// Call EnsureAdminClusterRoleBinding() to obtain a working client from admin.conf.
553-
d.client, err = kubeconfigphase.EnsureAdminClusterRoleBinding(kubeadmconstants.KubernetesDir, nil)
575+
d.client, err = kubeconfigphase.EnsureAdminClusterRoleBinding(
576+
kubeadmconstants.KubernetesDir,
577+
&d.Cfg().LocalAPIEndpoint,
578+
nil,
579+
)
554580
if err != nil {
555581
return nil, errors.Wrapf(err, "could not bootstrap the admin user in file %s", kubeadmconstants.AdminKubeConfigFileName)
556582
}
@@ -571,30 +597,6 @@ func (d *initData) Client() (clientset.Interface, error) {
571597
return d.client, nil
572598
}
573599

574-
// WaitControlPlaneClient returns a basic client used for the purpose of waiting
575-
// for control plane components to report 'ok' on their respective health check endpoints.
576-
// It uses the admin.conf as the base, but modifies it to point at the local API server instead
577-
// of the control plane endpoint.
578-
func (d *initData) WaitControlPlaneClient() (clientset.Interface, error) {
579-
config, err := clientcmd.LoadFromFile(d.KubeConfigPath())
580-
if err != nil {
581-
return nil, err
582-
}
583-
for _, v := range config.Clusters {
584-
v.Server = fmt.Sprintf("https://%s",
585-
net.JoinHostPort(
586-
d.Cfg().LocalAPIEndpoint.AdvertiseAddress,
587-
strconv.Itoa(int(d.Cfg().LocalAPIEndpoint.BindPort)),
588-
),
589-
)
590-
}
591-
client, err := kubeconfigutil.ToClientSet(config)
592-
if err != nil {
593-
return nil, err
594-
}
595-
return client, nil
596-
}
597-
598600
// Tokens returns an array of token strings.
599601
func (d *initData) Tokens() []string {
600602
tokens := []string{}

cmd/kubeadm/app/cmd/phases/init/bootstraptoken.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ func runBootstrapToken(c workflow.RunData) error {
7171
if err != nil {
7272
return err
7373
}
74-
kubeconfig, err := data.KubeConfig()
74+
kubeconfig, err := data.KubeConfigOriginal()
7575
if err != nil {
7676
return err
7777
}
@@ -108,6 +108,11 @@ func runBootstrapToken(c workflow.RunData) error {
108108
return err
109109
}
110110

111+
// Create RBAC rules that allow the API server kubelet client to access the kubelet API
112+
if err := nodebootstraptokenphase.AllowAPIServerToAccessKubeletAPI(client); err != nil {
113+
return errors.Wrap(err, "error allowing API server to access kubelet API")
114+
}
115+
111116
// Create the cluster-info ConfigMap with the associated RBAC rules
112117
if err := clusterinfophase.CreateBootstrapConfigMapIfNotExists(client, kubeconfig); err != nil {
113118
return errors.Wrap(err, "error creating bootstrap ConfigMap")

cmd/kubeadm/app/cmd/phases/init/data.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,14 @@ type InitData interface {
4040
CertificateWriteDir() string
4141
CertificateDir() string
4242
KubeConfig() (*clientcmdapi.Config, error)
43+
KubeConfigOriginal() (*clientcmdapi.Config, error)
4344
KubeConfigDir() string
4445
KubeConfigPath() string
4546
ManifestDir() string
4647
KubeletDir() string
4748
ExternalCA() bool
4849
OutputWriter() io.Writer
4950
Client() (clientset.Interface, error)
50-
WaitControlPlaneClient() (clientset.Interface, error)
5151
Tokens() []string
5252
PatchesDir() string
5353
}

cmd/kubeadm/app/cmd/phases/init/data_test.go

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -32,24 +32,24 @@ type testInitData struct{}
3232
// testInitData must satisfy InitData.
3333
var _ InitData = &testInitData{}
3434

35-
func (t *testInitData) UploadCerts() bool { return false }
36-
func (t *testInitData) CertificateKey() string { return "" }
37-
func (t *testInitData) SetCertificateKey(key string) {}
38-
func (t *testInitData) SkipCertificateKeyPrint() bool { return false }
39-
func (t *testInitData) Cfg() *kubeadmapi.InitConfiguration { return nil }
40-
func (t *testInitData) DryRun() bool { return false }
41-
func (t *testInitData) SkipTokenPrint() bool { return false }
42-
func (t *testInitData) IgnorePreflightErrors() sets.Set[string] { return nil }
43-
func (t *testInitData) CertificateWriteDir() string { return "" }
44-
func (t *testInitData) CertificateDir() string { return "" }
45-
func (t *testInitData) KubeConfig() (*clientcmdapi.Config, error) { return nil, nil }
46-
func (t *testInitData) KubeConfigDir() string { return "" }
47-
func (t *testInitData) KubeConfigPath() string { return "" }
48-
func (t *testInitData) ManifestDir() string { return "" }
49-
func (t *testInitData) KubeletDir() string { return "" }
50-
func (t *testInitData) ExternalCA() bool { return false }
51-
func (t *testInitData) OutputWriter() io.Writer { return nil }
52-
func (t *testInitData) Client() (clientset.Interface, error) { return nil, nil }
53-
func (t *testInitData) WaitControlPlaneClient() (clientset.Interface, error) { return nil, nil }
54-
func (t *testInitData) Tokens() []string { return nil }
55-
func (t *testInitData) PatchesDir() string { return "" }
35+
func (t *testInitData) UploadCerts() bool { return false }
36+
func (t *testInitData) CertificateKey() string { return "" }
37+
func (t *testInitData) SetCertificateKey(key string) {}
38+
func (t *testInitData) SkipCertificateKeyPrint() bool { return false }
39+
func (t *testInitData) Cfg() *kubeadmapi.InitConfiguration { return nil }
40+
func (t *testInitData) DryRun() bool { return false }
41+
func (t *testInitData) SkipTokenPrint() bool { return false }
42+
func (t *testInitData) IgnorePreflightErrors() sets.Set[string] { return nil }
43+
func (t *testInitData) CertificateWriteDir() string { return "" }
44+
func (t *testInitData) CertificateDir() string { return "" }
45+
func (t *testInitData) KubeConfig() (*clientcmdapi.Config, error) { return nil, nil }
46+
func (t *testInitData) KubeConfigOriginal() (*clientcmdapi.Config, error) { return nil, nil }
47+
func (t *testInitData) KubeConfigDir() string { return "" }
48+
func (t *testInitData) KubeConfigPath() string { return "" }
49+
func (t *testInitData) ManifestDir() string { return "" }
50+
func (t *testInitData) KubeletDir() string { return "" }
51+
func (t *testInitData) ExternalCA() bool { return false }
52+
func (t *testInitData) OutputWriter() io.Writer { return nil }
53+
func (t *testInitData) Client() (clientset.Interface, error) { return nil, nil }
54+
func (t *testInitData) Tokens() []string { return nil }
55+
func (t *testInitData) PatchesDir() string { return "" }

cmd/kubeadm/app/cmd/phases/init/waitcontrolplane.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func runWaitControlPlanePhase(c workflow.RunData) error {
5858
}
5959
}
6060

61-
client, err := data.WaitControlPlaneClient()
61+
client, err := data.Client()
6262
if err != nil {
6363
return errors.Wrap(err, "cannot obtain client without bootstrap")
6464
}

cmd/kubeadm/app/cmd/phases/upgrade/apply/bootstraptoken.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ func runBootstrapToken(c workflow.RunData) error {
7979
errs = append(errs, err)
8080
}
8181

82+
// Create/update RBAC rules that allow the API server kubelet client to access the kubelet API
83+
if err := nodebootstraptoken.AllowAPIServerToAccessKubeletAPI(client); err != nil {
84+
errs = append(errs, err)
85+
}
86+
8287
// Create/update RBAC rules that makes the cluster-info ConfigMap reachable
8388
if err := clusterinfophase.CreateClusterInfoRBACRules(client); err != nil {
8489
errs = append(errs, err)

cmd/kubeadm/app/constants/constants.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,11 @@ const (
210210
// built-in ClusterRole.
211211
ClusterAdminsGroupAndClusterRoleBinding = "kubeadm:cluster-admins"
212212

213+
// KubeletAPIAdminClusterRoleBindingName is the name of the ClusterRoleBinding for the apiserver kubelet client
214+
KubeletAPIAdminClusterRoleBindingName = "kubeadm:apiserver-kubelet-client"
215+
// KubeletAPIAdminClusterRoleName is the name of the built-in ClusterRole for kubelet API access
216+
KubeletAPIAdminClusterRoleName = "system:kubelet-api-admin"
217+
213218
// KubernetesAPICallTimeout specifies how long kubeadm should wait for API calls
214219
KubernetesAPICallTimeout = 1 * time.Minute
215220
// KubernetesAPICallRetryInterval defines how long kubeadm should wait before retrying a failed API operation

cmd/kubeadm/app/phases/bootstraptoken/node/tlsbootstrap.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,3 +130,25 @@ func AutoApproveNodeCertificateRotation(client clientset.Interface) error {
130130
},
131131
})
132132
}
133+
134+
// AllowAPIServerToAccessKubeletAPI creates RBAC rules that allow the API server kubelet client to access the kubelet API
135+
func AllowAPIServerToAccessKubeletAPI(client clientset.Interface) error {
136+
fmt.Println("[bootstrap-token] Configured RBAC rules to allow the API server kubelet client certificate to access the kubelet API")
137+
138+
return apiclient.CreateOrUpdate(client.RbacV1().ClusterRoleBindings(), &rbac.ClusterRoleBinding{
139+
ObjectMeta: metav1.ObjectMeta{
140+
Name: constants.KubeletAPIAdminClusterRoleBindingName,
141+
},
142+
RoleRef: rbac.RoleRef{
143+
APIGroup: rbac.GroupName,
144+
Kind: "ClusterRole",
145+
Name: constants.KubeletAPIAdminClusterRoleName,
146+
},
147+
Subjects: []rbac.Subject{
148+
{
149+
Kind: rbac.UserKind,
150+
Name: constants.APIServerKubeletClientCertCommonName,
151+
},
152+
},
153+
})
154+
}

cmd/kubeadm/app/phases/bootstraptoken/node/tlsbootstrap_test.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,63 @@ func TestAllowBootstrapTokensToGetNodes(t *testing.T) {
278278
}
279279
}
280280

281+
func TestAllowAPIServerToAccessKubeletAPI(t *testing.T) {
282+
tests := []struct {
283+
name string
284+
client clientset.Interface
285+
}{
286+
{
287+
name: "ClusterRoleBindings is empty",
288+
client: clientsetfake.NewSimpleClientset(),
289+
},
290+
{
291+
name: "ClusterRoleBindings already exists",
292+
client: newMockClusterRoleBinddingClientForTest(t, &rbac.ClusterRoleBinding{
293+
ObjectMeta: metav1.ObjectMeta{
294+
Name: constants.KubeletAPIAdminClusterRoleBindingName,
295+
},
296+
RoleRef: rbac.RoleRef{
297+
APIGroup: rbac.GroupName,
298+
Kind: "ClusterRole",
299+
Name: constants.KubeletAPIAdminClusterRoleName,
300+
},
301+
Subjects: []rbac.Subject{
302+
{
303+
Kind: rbac.UserKind,
304+
Name: constants.APIServerKubeletClientCertCommonName,
305+
},
306+
},
307+
}),
308+
},
309+
{
310+
name: "Create new ClusterRoleBindings",
311+
client: newMockClusterRoleBinddingClientForTest(t, &rbac.ClusterRoleBinding{
312+
ObjectMeta: metav1.ObjectMeta{
313+
Name: constants.KubeletAPIAdminClusterRoleBindingName,
314+
},
315+
RoleRef: rbac.RoleRef{
316+
APIGroup: rbac.GroupName,
317+
Kind: "ClusterRole",
318+
Name: constants.KubeletAPIAdminClusterRoleName,
319+
},
320+
Subjects: []rbac.Subject{
321+
{
322+
Kind: rbac.GroupKind,
323+
Name: constants.NodesGroup,
324+
},
325+
},
326+
}),
327+
},
328+
}
329+
for _, tt := range tests {
330+
t.Run(tt.name, func(t *testing.T) {
331+
if err := AllowAPIServerToAccessKubeletAPI(tt.client); err != nil {
332+
t.Errorf("AllowAPIServerToAccessKubeletAPI() return error = %v", err)
333+
}
334+
})
335+
}
336+
}
337+
281338
func newMockClusterRoleBinddingClientForTest(t *testing.T, clusterRoleBinding *rbac.ClusterRoleBinding) *clientsetfake.Clientset {
282339
client := clientsetfake.NewSimpleClientset()
283340
_, err := client.RbacV1().ClusterRoleBindings().Create(context.TODO(), clusterRoleBinding, metav1.CreateOptions{})

0 commit comments

Comments
 (0)