From 4b59d2b05c0b7a07bc812562a20f423bb2252260 Mon Sep 17 00:00:00 2001 From: Lars Ekman Date: Mon, 25 Sep 2023 12:03:45 +0200 Subject: [PATCH] kube-proxy: Optionally do privileged configs only A new --init-only flag is added tha makes kube-proxy perform configuration that requires privileged mode and exit. It is intended to be executed in a privileged initContainer, while the main container may run with a stricter securityContext --- cmd/kube-proxy/app/server.go | 13 +++++++++---- cmd/kube-proxy/app/server_others.go | 6 +++++- cmd/kube-proxy/app/server_windows.go | 5 ++++- pkg/proxy/iptables/proxier.go | 14 ++++++++++++-- pkg/proxy/ipvs/proxier.go | 14 ++++++++++++-- pkg/proxy/kubemark/hollow_proxy.go | 1 + 6 files changed, 43 insertions(+), 10 deletions(-) diff --git a/cmd/kube-proxy/app/server.go b/cmd/kube-proxy/app/server.go index 3b42bf2f20e..529274c57cf 100644 --- a/cmd/kube-proxy/app/server.go +++ b/cmd/kube-proxy/app/server.go @@ -108,6 +108,8 @@ type Options struct { WriteConfigTo string // CleanupAndExit, when true, makes the proxy server clean up iptables and ipvs rules, then exit. CleanupAndExit bool + // InitAndExit, when true, makes the proxy server makes configurations that need privileged access, then exit. + InitAndExit bool // WindowsService should be set to true if kube-proxy is running as a service on Windows. // Its corresponding flag only gets registered in Windows builds WindowsService bool @@ -168,7 +170,7 @@ func (o *Options) AddFlags(fs *pflag.FlagSet) { "The purpose of this format is make sure you have the opportunity to notice if the next release hides additional metrics, "+ "rather than being surprised when they are permanently removed in the release after that. "+ "This parameter is ignored if a config file is specified by --config.") - + fs.BoolVar(&o.InitAndExit, "init-only", o.InitAndExit, "If true, perform any initialization steps that must be done with full root privileges, and then exit. After doing this, you can run kube-proxy again with only the CAP_NET_ADMIN capability.") fs.Var(&o.config.Mode, "proxy-mode", "Which proxy mode to use: on Linux this can be 'iptables' (default) or 'ipvs'. On Windows the only supported value is 'kernelspace'."+ "This parameter is ignored if a config file is specified by --config.") @@ -376,10 +378,13 @@ func (o *Options) Run() error { return cleanupAndExit() } - proxyServer, err := newProxyServer(o.config, o.master) + proxyServer, err := newProxyServer(o.config, o.master, o.InitAndExit) if err != nil { return err } + if o.InitAndExit { + return nil + } o.proxyServer = proxyServer return o.runLoop() @@ -589,7 +594,7 @@ type ProxyServer struct { } // newProxyServer creates a ProxyServer based on the given config -func newProxyServer(config *kubeproxyconfig.KubeProxyConfiguration, master string) (*ProxyServer, error) { +func newProxyServer(config *kubeproxyconfig.KubeProxyConfiguration, master string, initOnly bool) (*ProxyServer, error) { s := &ProxyServer{Config: config} cz, err := configz.New(kubeproxyconfig.GroupName) @@ -653,7 +658,7 @@ func newProxyServer(config *kubeproxyconfig.KubeProxyConfiguration, master strin klog.ErrorS(err, "Kube-proxy configuration may be incomplete or incorrect") } - s.Proxier, err = s.createProxier(config, dualStackSupported) + s.Proxier, err = s.createProxier(config, dualStackSupported, initOnly) if err != nil { return nil, err } diff --git a/cmd/kube-proxy/app/server_others.go b/cmd/kube-proxy/app/server_others.go index 7800b97fb82..ff3fff7e66b 100644 --- a/cmd/kube-proxy/app/server_others.go +++ b/cmd/kube-proxy/app/server_others.go @@ -125,7 +125,7 @@ func (s *ProxyServer) platformCheckSupported() (ipv4Supported, ipv6Supported, du } // createProxier creates the proxy.Provider -func (s *ProxyServer) createProxier(config *proxyconfigapi.KubeProxyConfiguration, dualStack bool) (proxy.Provider, error) { +func (s *ProxyServer) createProxier(config *proxyconfigapi.KubeProxyConfiguration, dualStack, initOnly bool) (proxy.Provider, error) { var proxier proxy.Provider var err error @@ -175,6 +175,7 @@ func (s *ProxyServer) createProxier(config *proxyconfigapi.KubeProxyConfiguratio s.Recorder, s.HealthzServer, config.NodePortAddresses, + initOnly, ) } else { // Create a single-stack proxier if and only if the node does not support dual-stack (i.e, no iptables support). @@ -201,6 +202,7 @@ func (s *ProxyServer) createProxier(config *proxyconfigapi.KubeProxyConfiguratio s.Recorder, s.HealthzServer, config.NodePortAddresses, + initOnly, ) } @@ -247,6 +249,7 @@ func (s *ProxyServer) createProxier(config *proxyconfigapi.KubeProxyConfiguratio config.IPVS.Scheduler, config.NodePortAddresses, kernelHandler, + initOnly, ) } else { var localDetector proxyutiliptables.LocalTrafficDetector @@ -279,6 +282,7 @@ func (s *ProxyServer) createProxier(config *proxyconfigapi.KubeProxyConfiguratio config.IPVS.Scheduler, config.NodePortAddresses, kernelHandler, + initOnly, ) } if err != nil { diff --git a/cmd/kube-proxy/app/server_windows.go b/cmd/kube-proxy/app/server_windows.go index 33a1a15b2b3..90f817c1bad 100644 --- a/cmd/kube-proxy/app/server_windows.go +++ b/cmd/kube-proxy/app/server_windows.go @@ -79,7 +79,10 @@ func (s *ProxyServer) platformCheckSupported() (ipv4Supported, ipv6Supported, du } // createProxier creates the proxy.Provider -func (s *ProxyServer) createProxier(config *proxyconfigapi.KubeProxyConfiguration, dualStackMode bool) (proxy.Provider, error) { +func (s *ProxyServer) createProxier(config *proxyconfigapi.KubeProxyConfiguration, dualStackMode, initOnly bool) (proxy.Provider, error) { + if initOnly { + return nil, fmt.Errorf("--init-only is not implemented on Windows") + } var healthzPort int if len(config.HealthzBindAddress) > 0 { _, port, _ := net.SplitHostPort(config.HealthzBindAddress) diff --git a/pkg/proxy/iptables/proxier.go b/pkg/proxy/iptables/proxier.go index c121687fd7d..9fbb9cdadba 100644 --- a/pkg/proxy/iptables/proxier.go +++ b/pkg/proxy/iptables/proxier.go @@ -233,6 +233,7 @@ func NewProxier(ipFamily v1.IPFamily, recorder events.EventRecorder, healthzServer *healthcheck.ProxierHealthServer, nodePortAddressStrings []string, + initOnly bool, ) (*Proxier, error) { nodePortAddresses := proxyutil.NewNodePortAddresses(ipFamily, nodePortAddressStrings) @@ -257,6 +258,11 @@ func NewProxier(ipFamily v1.IPFamily, klog.InfoS("nf_conntrack_tcp_be_liberal set, not installing DROP rules for INVALID packets") } + if initOnly { + klog.InfoS("System initialized and --init-only specified") + return nil, nil + } + // Generate the masquerade mark to use for SNAT rules. masqueradeValue := 1 << uint(masqueradeBit) masqueradeMark := fmt.Sprintf("%#08x", masqueradeValue) @@ -330,21 +336,25 @@ func NewDualStackProxier( recorder events.EventRecorder, healthzServer *healthcheck.ProxierHealthServer, nodePortAddresses []string, + initOnly bool, ) (proxy.Provider, error) { // Create an ipv4 instance of the single-stack proxier ipv4Proxier, err := NewProxier(v1.IPv4Protocol, ipt[0], sysctl, exec, syncPeriod, minSyncPeriod, masqueradeAll, localhostNodePorts, masqueradeBit, localDetectors[0], hostname, - nodeIPs[v1.IPv4Protocol], recorder, healthzServer, nodePortAddresses) + nodeIPs[v1.IPv4Protocol], recorder, healthzServer, nodePortAddresses, initOnly) if err != nil { return nil, fmt.Errorf("unable to create ipv4 proxier: %v", err) } ipv6Proxier, err := NewProxier(v1.IPv6Protocol, ipt[1], sysctl, exec, syncPeriod, minSyncPeriod, masqueradeAll, false, masqueradeBit, localDetectors[1], hostname, - nodeIPs[v1.IPv6Protocol], recorder, healthzServer, nodePortAddresses) + nodeIPs[v1.IPv6Protocol], recorder, healthzServer, nodePortAddresses, initOnly) if err != nil { return nil, fmt.Errorf("unable to create ipv6 proxier: %v", err) } + if initOnly { + return nil, nil + } return metaproxier.NewMetaProxier(ipv4Proxier, ipv6Proxier), nil } diff --git a/pkg/proxy/ipvs/proxier.go b/pkg/proxy/ipvs/proxier.go index e687926d1a0..9e3dc27df08 100644 --- a/pkg/proxy/ipvs/proxier.go +++ b/pkg/proxy/ipvs/proxier.go @@ -340,6 +340,7 @@ func NewProxier(ipFamily v1.IPFamily, scheduler string, nodePortAddressStrings []string, kernelHandler KernelHandler, + initOnly bool, ) (*Proxier, error) { // Set the conntrack sysctl we need for if err := proxyutil.EnsureSysctl(sysctl, sysctlVSConnTrack, 1); err != nil { @@ -402,6 +403,11 @@ func NewProxier(ipFamily v1.IPFamily, } } + if initOnly { + klog.InfoS("System initialized and --init-only specified") + return nil, nil + } + // Generate the masquerade mark to use for SNAT rules. masqueradeValue := 1 << uint(masqueradeBit) masqueradeMark := fmt.Sprintf("%#08x", masqueradeValue) @@ -490,6 +496,7 @@ func NewDualStackProxier( scheduler string, nodePortAddresses []string, kernelHandler KernelHandler, + initOnly bool, ) (proxy.Provider, error) { safeIpset := newSafeIpset(ipset) @@ -499,7 +506,7 @@ func NewDualStackProxier( exec, syncPeriod, minSyncPeriod, filterCIDRs(false, excludeCIDRs), strictARP, tcpTimeout, tcpFinTimeout, udpTimeout, masqueradeAll, masqueradeBit, localDetectors[0], hostname, nodeIPs[v1.IPv4Protocol], - recorder, healthzServer, scheduler, nodePortAddresses, kernelHandler) + recorder, healthzServer, scheduler, nodePortAddresses, kernelHandler, initOnly) if err != nil { return nil, fmt.Errorf("unable to create ipv4 proxier: %v", err) } @@ -508,10 +515,13 @@ func NewDualStackProxier( exec, syncPeriod, minSyncPeriod, filterCIDRs(true, excludeCIDRs), strictARP, tcpTimeout, tcpFinTimeout, udpTimeout, masqueradeAll, masqueradeBit, localDetectors[1], hostname, nodeIPs[v1.IPv6Protocol], - recorder, healthzServer, scheduler, nodePortAddresses, kernelHandler) + recorder, healthzServer, scheduler, nodePortAddresses, kernelHandler, initOnly) if err != nil { return nil, fmt.Errorf("unable to create ipv6 proxier: %v", err) } + if initOnly { + return nil, nil + } // Return a meta-proxier that dispatch calls between the two // single-stack proxier instances diff --git a/pkg/proxy/kubemark/hollow_proxy.go b/pkg/proxy/kubemark/hollow_proxy.go index 1462c30a84f..fd90ae09188 100644 --- a/pkg/proxy/kubemark/hollow_proxy.go +++ b/pkg/proxy/kubemark/hollow_proxy.go @@ -109,6 +109,7 @@ func NewHollowProxyOrDie( recorder, nil, []string{}, + false, ) if err != nil { return nil, fmt.Errorf("unable to create proxier: %v", err)