diff --git a/build-scripts/components/kubernetes/patches/v1.32.0/0001-allow-all-nodes-to-get-k8sd-config.patch b/build-scripts/components/kubernetes/patches/v1.32.0/0001-allow-all-nodes-to-get-k8sd-config.patch new file mode 100644 index 000000000..b840e72e2 --- /dev/null +++ b/build-scripts/components/kubernetes/patches/v1.32.0/0001-allow-all-nodes-to-get-k8sd-config.patch @@ -0,0 +1,25 @@ +From 3ef3359a350e72687599f44906ecf2cc236347ee Mon Sep 17 00:00:00 2001 +From: Angelos Kolaitis +Date: Tue, 12 Mar 2024 16:53:02 +0200 +Subject: [PATCH] allow all nodes to get k8sd-config + +--- + plugin/pkg/auth/authorizer/node/node_authorizer.go | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/plugin/pkg/auth/authorizer/node/node_authorizer.go b/plugin/pkg/auth/authorizer/node/node_authorizer.go +index b03467ffd73..686d292b151 100644 +--- a/plugin/pkg/auth/authorizer/node/node_authorizer.go ++++ b/plugin/pkg/auth/authorizer/node/node_authorizer.go +@@ -112,6 +112,9 @@ func (r *NodeAuthorizer) Authorize(ctx context.Context, attrs authorizer.Attribu + case secretResource: + return r.authorizeReadNamespacedObject(nodeName, secretVertexType, attrs) + case configMapResource: ++ if (attrs.GetVerb() == "get" || attrs.GetVerb() == "watch") && attrs.GetName() == "k8sd-config" && attrs.GetNamespace() == "kube-system" { ++ return authorizer.DecisionAllow, "", nil ++ } + return r.authorizeReadNamespacedObject(nodeName, configMapVertexType, attrs) + case pvcResource: + if attrs.GetSubresource() == "status" { +-- +2.34.1 diff --git a/build-scripts/components/kubernetes/patches/v1.32.0/0001-single-kubernetes-binary.patch b/build-scripts/components/kubernetes/patches/v1.32.0/0001-single-kubernetes-binary.patch new file mode 100644 index 000000000..d5c60a9be --- /dev/null +++ b/build-scripts/components/kubernetes/patches/v1.32.0/0001-single-kubernetes-binary.patch @@ -0,0 +1,190 @@ +From 436a9056b639517bebb826c7121feefd692f6629 Mon Sep 17 00:00:00 2001 +From: Angelos Kolaitis +Date: Tue, 2 Jan 2024 16:43:16 +0200 +Subject: [PATCH] single kubernetes binary + +--- + cmd/kube-apiserver/apiserver.go | 4 +-- + .../controller-manager.go | 4 +-- + cmd/kube-proxy/proxy.go | 4 +-- + cmd/kube-scheduler/scheduler.go | 4 +-- + cmd/kubectl/kubectl.go | 4 +-- + cmd/kubelet/kubelet.go | 4 +-- + cmd/kubernetes/main.go | 34 +++++++++++++++++++ + 7 files changed, 46 insertions(+), 12 deletions(-) + create mode 100644 cmd/kubernetes/main.go + +diff --git a/cmd/kube-apiserver/apiserver.go b/cmd/kube-apiserver/apiserver.go +index 1bf05bc5684..53b781b8d41 100644 +--- a/cmd/kube-apiserver/apiserver.go ++++ b/cmd/kube-apiserver/apiserver.go +@@ -16,7 +16,7 @@ limitations under the License. + + // APIServer is the main API server and master for the cluster. + // It is responsible for serving the cluster management API. +-package main ++package apiserver + + import ( + "os" +@@ -29,7 +29,7 @@ import ( + "k8s.io/kubernetes/cmd/kube-apiserver/app" + ) + +-func main() { ++func Main() { + command := app.NewAPIServerCommand() + code := cli.Run(command) + os.Exit(code) +diff --git a/cmd/kube-controller-manager/controller-manager.go b/cmd/kube-controller-manager/controller-manager.go +index 77bc10a3517..3b95649afe4 100644 +--- a/cmd/kube-controller-manager/controller-manager.go ++++ b/cmd/kube-controller-manager/controller-manager.go +@@ -18,7 +18,7 @@ limitations under the License. + // controllers, and creating corresponding pods to achieve the desired + // state. It uses the API to listen for new controllers and to create/delete + // pods. +-package main ++package controllermanager + + import ( + "os" +@@ -31,7 +31,7 @@ import ( + "k8s.io/kubernetes/cmd/kube-controller-manager/app" + ) + +-func main() { ++func Main() { + command := app.NewControllerManagerCommand() + code := cli.Run(command) + os.Exit(code) +diff --git a/cmd/kube-proxy/proxy.go b/cmd/kube-proxy/proxy.go +index e167484781a..5ed91261468 100644 +--- a/cmd/kube-proxy/proxy.go ++++ b/cmd/kube-proxy/proxy.go +@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and + limitations under the License. + */ + +-package main ++package proxy + + import ( + "os" +@@ -26,7 +26,7 @@ import ( + "k8s.io/kubernetes/cmd/kube-proxy/app" + ) + +-func main() { ++func Main() { + command := app.NewProxyCommand() + code := cli.Run(command) + os.Exit(code) +diff --git a/cmd/kube-scheduler/scheduler.go b/cmd/kube-scheduler/scheduler.go +index 71739808dd2..8659324973a 100644 +--- a/cmd/kube-scheduler/scheduler.go ++++ b/cmd/kube-scheduler/scheduler.go +@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and + limitations under the License. + */ + +-package main ++package scheduler + + import ( + "os" +@@ -26,7 +26,7 @@ import ( + "k8s.io/kubernetes/cmd/kube-scheduler/app" + ) + +-func main() { ++func Main() { + command := app.NewSchedulerCommand() + code := cli.Run(command) + os.Exit(code) +diff --git a/cmd/kubectl/kubectl.go b/cmd/kubectl/kubectl.go +index 09c18cfa209..5a8d2d432c3 100644 +--- a/cmd/kubectl/kubectl.go ++++ b/cmd/kubectl/kubectl.go +@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and + limitations under the License. + */ + +-package main ++package kubectl + + import ( + "k8s.io/component-base/cli" +@@ -25,7 +25,7 @@ import ( + _ "k8s.io/client-go/plugin/pkg/client/auth" + ) + +-func main() { ++func Main() { + command := cmd.NewDefaultKubectlCommand() + if err := cli.RunNoErrOutput(command); err != nil { + // Pretty-print the error and exit with an error. +diff --git a/cmd/kubelet/kubelet.go b/cmd/kubelet/kubelet.go +index c6a73a0034d..24656e8727e 100644 +--- a/cmd/kubelet/kubelet.go ++++ b/cmd/kubelet/kubelet.go +@@ -19,7 +19,7 @@ limitations under the License. + // It then communicates with the container runtime (or a CRI shim for the runtime) to see what is + // currently running. It synchronizes the configuration data, with the running set of containers + // by starting or stopping containers. +-package main ++package kubelet + + import ( + "os" +@@ -31,7 +31,7 @@ import ( + "k8s.io/kubernetes/cmd/kubelet/app" + ) + +-func main() { ++func Main() { + command := app.NewKubeletCommand() + code := cli.Run(command) + os.Exit(code) +diff --git a/cmd/kubernetes/main.go b/cmd/kubernetes/main.go +new file mode 100644 +index 00000000000..9c82c6a89ee +--- /dev/null ++++ b/cmd/kubernetes/main.go +@@ -0,0 +1,34 @@ ++package main ++ ++import ( ++ "fmt" ++ "os" ++ "path/filepath" ++ ++ apiserver "k8s.io/kubernetes/cmd/kube-apiserver" ++ controllermanager "k8s.io/kubernetes/cmd/kube-controller-manager" ++ proxy "k8s.io/kubernetes/cmd/kube-proxy" ++ scheduler "k8s.io/kubernetes/cmd/kube-scheduler" ++ "k8s.io/kubernetes/cmd/kubectl" ++ "k8s.io/kubernetes/cmd/kubelet" ++) ++ ++func main() { ++ base := filepath.Base(os.Args[0]) ++ switch base { ++ case "kubelet": ++ kubelet.Main() ++ case "kube-proxy": ++ proxy.Main() ++ case "kube-controller-manager": ++ controllermanager.Main() ++ case "kubectl": ++ kubectl.Main() ++ case "kube-apiserver": ++ apiserver.Main() ++ case "kube-scheduler": ++ scheduler.Main() ++ default: ++ panic(fmt.Errorf("unknown entrypoint %s", base)) ++ } ++} +-- +2.34.1 diff --git a/build-scripts/components/kubernetes/patches/v1.32.0/0001-use-resolv.conf-file-with-non-loopback-nameservers.patch b/build-scripts/components/kubernetes/patches/v1.32.0/0001-use-resolv.conf-file-with-non-loopback-nameservers.patch new file mode 100644 index 000000000..93c7f37b5 --- /dev/null +++ b/build-scripts/components/kubernetes/patches/v1.32.0/0001-use-resolv.conf-file-with-non-loopback-nameservers.patch @@ -0,0 +1,277 @@ +diff --git a/pkg/kubelet/apis/config/fuzzer/fuzzer.go b/pkg/kubelet/apis/config/fuzzer/fuzzer.go +index 474d6db2ef0..b6ae5016353 100644 +--- a/pkg/kubelet/apis/config/fuzzer/fuzzer.go ++++ b/pkg/kubelet/apis/config/fuzzer/fuzzer.go +@@ -88,7 +88,7 @@ func Funcs(codecs runtimeserializer.CodecFactory) []interface{} { + obj.ReadOnlyPort = ports.KubeletReadOnlyPort + obj.RegistryBurst = 10 + obj.RegistryPullQPS = 5 +- obj.ResolverConfig = kubetypes.ResolvConfDefault ++ obj.ResolverConfig = kubetypes.ResolvConfDefault() + obj.SerializeImagePulls = true + obj.StreamingConnectionIdleTimeout = metav1.Duration{Duration: 4 * time.Hour} + obj.SyncFrequency = metav1.Duration{Duration: 1 * time.Minute} +diff --git a/pkg/kubelet/apis/config/v1beta1/defaults.go b/pkg/kubelet/apis/config/v1beta1/defaults.go +index 960b1489d30..c0ce7433b24 100644 +--- a/pkg/kubelet/apis/config/v1beta1/defaults.go ++++ b/pkg/kubelet/apis/config/v1beta1/defaults.go +@@ -200,7 +200,7 @@ func SetDefaults_KubeletConfiguration(obj *kubeletconfigv1beta1.KubeletConfigura + } + + if obj.ResolverConfig == nil { +- obj.ResolverConfig = ptr.To(kubetypes.ResolvConfDefault) ++ obj.ResolverConfig = ptr.To(kubetypes.ResolvConfDefault()) + } + if obj.CPUCFSQuota == nil { + obj.CPUCFSQuota = ptr.To(true) +diff --git a/pkg/kubelet/apis/config/v1beta1/defaults_test.go b/pkg/kubelet/apis/config/v1beta1/defaults_test.go +index c33c5c730ef..457784ebfa6 100644 +--- a/pkg/kubelet/apis/config/v1beta1/defaults_test.go ++++ b/pkg/kubelet/apis/config/v1beta1/defaults_test.go +@@ -92,7 +92,7 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) { + HairpinMode: v1beta1.PromiscuousBridge, + MaxPods: 110, + PodPidsLimit: ptr.To[int64](-1), +- ResolverConfig: ptr.To(kubetypes.ResolvConfDefault), ++ ResolverConfig: ptr.To(kubetypes.ResolvConfDefault()), + CPUCFSQuota: ptr.To(true), + CPUCFSQuotaPeriod: &metav1.Duration{Duration: 100 * time.Millisecond}, + NodeStatusMaxImages: ptr.To[int32](50), +@@ -736,7 +736,7 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) { + HairpinMode: v1beta1.PromiscuousBridge, + MaxPods: 110, + PodPidsLimit: ptr.To[int64](-1), +- ResolverConfig: ptr.To(kubetypes.ResolvConfDefault), ++ ResolverConfig: ptr.To(kubetypes.ResolvConfDefault()), + CPUCFSQuota: ptr.To(true), + CPUCFSQuotaPeriod: &metav1.Duration{Duration: 100 * time.Millisecond}, + NodeStatusMaxImages: ptr.To[int32](50), +@@ -831,7 +831,7 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) { + HairpinMode: v1beta1.PromiscuousBridge, + MaxPods: 110, + PodPidsLimit: ptr.To[int64](-1), +- ResolverConfig: ptr.To(kubetypes.ResolvConfDefault), ++ ResolverConfig: ptr.To(kubetypes.ResolvConfDefault()), + CPUCFSQuota: ptr.To(true), + CPUCFSQuotaPeriod: &metav1.Duration{Duration: 100 * time.Millisecond}, + NodeStatusMaxImages: ptr.To[int32](50), +@@ -926,7 +926,7 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) { + HairpinMode: v1beta1.PromiscuousBridge, + MaxPods: 110, + PodPidsLimit: ptr.To[int64](-1), +- ResolverConfig: ptr.To(kubetypes.ResolvConfDefault), ++ ResolverConfig: ptr.To(kubetypes.ResolvConfDefault()), + CPUCFSQuota: ptr.To(true), + CPUCFSQuotaPeriod: &metav1.Duration{Duration: 100 * time.Millisecond}, + NodeStatusMaxImages: ptr.To[int32](50), +@@ -1021,7 +1021,7 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) { + HairpinMode: v1beta1.PromiscuousBridge, + MaxPods: 110, + PodPidsLimit: ptr.To[int64](-1), +- ResolverConfig: ptr.To(kubetypes.ResolvConfDefault), ++ ResolverConfig: ptr.To(kubetypes.ResolvConfDefault()), + CPUCFSQuota: ptr.To(true), + CPUCFSQuotaPeriod: &metav1.Duration{Duration: 100 * time.Millisecond}, + NodeStatusMaxImages: ptr.To[int32](50), +diff --git a/pkg/kubelet/types/constants.go b/pkg/kubelet/types/constants.go +index 56cba9c43b8..9c0303760aa 100644 +--- a/pkg/kubelet/types/constants.go ++++ b/pkg/kubelet/types/constants.go +@@ -17,8 +17,8 @@ limitations under the License. + package types + + const ( +- // ResolvConfDefault is the system default DNS resolver configuration. +- ResolvConfDefault = "/etc/resolv.conf" ++ // ResolvConfDefault_Static is the system default DNS resolver configuration. ++ ResolvConfDefault_Static = "/etc/resolv.conf" + ) + + // User visible keys for managing node allocatable enforcement on the node. +diff --git a/pkg/kubelet/types/resolv_conf.go b/pkg/kubelet/types/resolv_conf.go +new file mode 100644 +index 00000000000..dbdd9eb84a5 +--- /dev/null ++++ b/pkg/kubelet/types/resolv_conf.go +@@ -0,0 +1,75 @@ ++package types ++ ++import ( ++ "net" ++ "os" ++ "regexp" ++ "strings" ++ ++ "k8s.io/klog/v2" ++) ++ ++var ( ++ // knownResolvConfFiles is a list of well-known locations to look for a resolv.conf file. ++ knownResolvConfFiles = []string{ ++ "/run/systemd/resolve/resolv.conf", ++ "/etc/resolv.conf", ++ } ++ ++ // nameserverRegex is a regular expression to match 'nameserver' lines in a resolv.conf file ++ // https://regex101.com/r/3WCriE/1 ++ nameserverRegex = regexp.MustCompile(`(?m)^\s*nameserver\s+(\S*)\s*$`) ++) ++ ++// ResolvConfDefault returns the default resolv.conf file to use. ++func ResolvConfDefault() string { ++ return resolvConfDefault(knownResolvConfFiles) ++} ++ ++// resolvConfDefault iterates over a list of candidate resolv.conf file paths and returns the first that does not contain upstream nameservers on a loopback address. ++// If we cannot find one, we default to ResolvConfDefault_Static. ++func resolvConfDefault(files []string) string { ++ for _, file := range files { ++ if resolvConfFileHasNonLoopbackNameservers(file) { ++ klog.Infof("Using %s for the DNS resolver config", file) ++ return file ++ } ++ } ++ ++ // fallback to the static default ++ klog.Infof("Failed to find a resolv.conf with non-loopback nameservers, falling back to %s", ResolvConfDefault_Static) ++ return ResolvConfDefault_Static ++} ++ ++// resolvConfFileHasNonLoopbackNameservers returns true if the specified resolv.conf file has a list of valid nameservers that are not loopback addresses. ++// resolvConfFileHasNonLoopbackNameservers returns false if any error occurs while processing the file. ++func resolvConfFileHasNonLoopbackNameservers(file string) bool { ++ // reject file if we cannot read it ++ b, err := os.ReadFile(file) ++ if err != nil { ++ return false ++ } ++ ++ // reject file if it does not have any 'nameserver' entries ++ matches := nameserverRegex.FindAllStringSubmatch(string(b), -1) ++ if len(matches) == 0 { ++ return false ++ } ++ ++ // reject file if it has at least one invalid or loopback address ++ for _, match := range matches { ++ if len(match) != 2 { ++ return false ++ } ++ ++ // IPv6 addresses may contain zone, e.g. "::1%2". Drop the '%' suffix, if any. ++ splitToDropScopeIfAny := strings.SplitN(match[1], "%", 2) ++ cleanIP := splitToDropScopeIfAny[0] ++ ++ if ip := net.ParseIP(cleanIP); ip == nil || ip.IsLoopback() { ++ return false ++ } ++ } ++ ++ return true ++} +diff --git a/pkg/kubelet/types/resolv_conf_test.go b/pkg/kubelet/types/resolv_conf_test.go +new file mode 100644 +index 00000000000..e67f2ab4e53 +--- /dev/null ++++ b/pkg/kubelet/types/resolv_conf_test.go +@@ -0,0 +1,87 @@ ++package types ++ ++import ( ++ "os" ++ "testing" ++) ++ ++func Test_resolvConfFileHasNonLoopbackNameservers(t *testing.T) { ++ if err := os.MkdirAll("testdata", 0755); err != nil { ++ t.Errorf("could not create temporary testdata dir: %v", err) ++ } ++ defer os.RemoveAll("testdata") ++ ++ for _, tc := range []struct { ++ name string ++ resolvConf string ++ expectValid bool ++ }{ ++ { ++ name: "no-nameservers", ++ resolvConf: "search .", ++ }, ++ { ++ name: "ipv4-loopback", ++ resolvConf: "nameserver 127.0.0.53", ++ }, ++ { ++ name: "ipv6-loopback", ++ resolvConf: "nameserver ::1", ++ }, ++ { ++ name: "ipv6-loopback-scoped", ++ resolvConf: "nameserver ::1%2", ++ }, ++ { ++ name: "ipv4-one", ++ resolvConf: "nameserver 10.0.0.1", ++ expectValid: true, ++ }, ++ { ++ name: "ipv4-two", ++ resolvConf: "nameserver 10.0.0.1\nnameserver 10.0.0.2", ++ expectValid: true, ++ }, ++ { ++ name: "ipv4-one-loopback-one-valid", ++ resolvConf: "nameserver 10.0.0.1\nnameserver 127.0.0.53", ++ }, ++ { ++ name: "ipv6-one", ++ resolvConf: "nameserver fade::", ++ expectValid: true, ++ }, ++ { ++ name: "ipv6-scoped", ++ resolvConf: "nameserver fade::%3", ++ expectValid: true, ++ }, ++ { ++ name: "ipv6-one-loopback-one-valid", ++ resolvConf: "nameserver fade::\nnameserver ::1", ++ }, ++ { ++ name: "dualstack", ++ resolvConf: "nameserver 10.0.0.1\nnameserver ::fade", ++ expectValid: true, ++ }, ++ { ++ name: "dualstack-scoped", ++ resolvConf: "nameserver 10.0.0.1\nnameserver ::fade%3", ++ expectValid: true, ++ }, ++ } { ++ t.Run(tc.name, func(t *testing.T) { ++ if err := os.WriteFile("testdata/resolv.conf", []byte(tc.resolvConf), 0644); err != nil { ++ t.Errorf("failed to write file: %v", err) ++ } ++ isValid := resolvConfFileHasNonLoopbackNameservers("testdata/resolv.conf") ++ if !isValid && tc.expectValid { ++ t.Error("expected resolv.conf to be valid, but it was not") ++ } ++ if isValid && !tc.expectValid { ++ t.Errorf("expected resolv.conf to be invalid, but it was not") ++ } ++ }) ++ } ++} +diff --git a/pkg/kubemark/hollow_kubelet.go b/pkg/kubemark/hollow_kubelet.go +index 523b6fcd65f..0e0a4832d04 100644 +--- a/pkg/kubemark/hollow_kubelet.go ++++ b/pkg/kubemark/hollow_kubelet.go +@@ -200,7 +200,7 @@ func GetHollowKubeletConfig(opt *HollowKubeletOptions) (*options.KubeletFlags, * + c.MaxOpenFiles = 1024 + c.RegistryBurst = 10 + c.RegistryPullQPS = 5.0 +- c.ResolverConfig = kubetypes.ResolvConfDefault ++ c.ResolverConfig = kubetypes.ResolvConfDefault() + c.KubeletCgroups = "/kubelet" + c.SerializeImagePulls = true + c.SystemCgroups = "" diff --git a/build-scripts/components/kubernetes/patches/v1.32.0/0002-Allow-node-role-labels-on-kubelet-registration.patch b/build-scripts/components/kubernetes/patches/v1.32.0/0002-Allow-node-role-labels-on-kubelet-registration.patch new file mode 100644 index 000000000..1047c8cfc --- /dev/null +++ b/build-scripts/components/kubernetes/patches/v1.32.0/0002-Allow-node-role-labels-on-kubelet-registration.patch @@ -0,0 +1,26 @@ +From b3a0ec7ca54f91c006bf36b8d18ea60a2ef44857 Mon Sep 17 00:00:00 2001 +From: Angelos Kolaitis +Date: Mon, 19 Feb 2024 21:13:32 +0200 +Subject: [PATCH] Allow node-role labels on kubelet registration + +--- + .../src/k8s.io/kubelet/pkg/apis/canonical_k8s_labels.go | 8 ++++++++ + 1 file changed, 8 insertions(+) + create mode 100644 staging/src/k8s.io/kubelet/pkg/apis/canonical_k8s_labels.go + +diff --git a/staging/src/k8s.io/kubelet/pkg/apis/canonical_k8s_labels.go b/staging/src/k8s.io/kubelet/pkg/apis/canonical_k8s_labels.go +new file mode 100644 +index 00000000000..fcc6acada75 +--- /dev/null ++++ b/staging/src/k8s.io/kubelet/pkg/apis/canonical_k8s_labels.go +@@ -0,0 +1,8 @@ ++package apis ++ ++func init() { ++ kubeletLabels.Insert( ++ "node-role.kubernetes.io/control-plane", ++ "node-role.kubernetes.io/worker", ++ ) ++} +-- +2.34.1