Code change:
<!-- Please use this template while reporting a bug and provide as much info as possible. Not doing so may result in your bug not being addressed in a timely manner. Thanks! If the matter is security related, please disclose it privately via --What happened: The apiserver, controller-manager and scheduler are configured to use IPv4 addresses however, are serving on all addresses IPv4 and IPv6 What you expected to happen: To listen only on the IP family specified How to reproduce it (as minimally and precisely as possible): or checking in one of the gce presubmits jobs Anything else we need to know?: it seems that the apiserver, controller-manager and kube-scheduler listen on all IP families by default despite the IP family address configured Environment: Kubernetes version (use ): Cloud provider or hardware configuration: OS (e.g: ): Kernel (e.g. ): Install tools: Network plugin and version (if this is a network-related bug): Others:
/assign /cc
binding 0.0.0.0 to all interfaces is the documented behavior of net.Listen:
The unspecified ip (0.0.0.0) is a special case that means "bind to all interfaces". This is currently working as intended. Is there a specific problem this causes?
/triage unresolved Comment when the issue is assessed and confirmed. I am a bot run by vllry. ‍
If (0.0.0.0) means "bind to all interfaces on all IP families", then is a misconfiguration problem and not a bug . I was worried because this causes that some components use IPv6 for their communications on dual-stack hosts despite the cluster is IPv4 single family (and viceversa), as we can see in this snippet from one of the gce presubmits job and I don't know if this can impact on some services or from a security point of view
From the listen godoc: That means binding to or or will bind to all interfaces
I would expect anyone using network interfaces as security boundaries to be binding to a specific interface, not binding to all and hoping "all" is family-partitioned
Clarifying the handling of unspecified addresses like that in the flag/config help seems reasonable, but as far as I can tell, this is working as intended.
yeah, thanks for the clarification, I totally misinterpreted the net.Listen function
/triage unresolved Comment when the issue is assessed and confirmed. I am a bot run by vllry. ‍
/remove-triage unresolved
So, is there any way to listen on IPv4 addresses only (all of them)?
hmm, that will requires to expose this setting just curious, what is the use case for having IPv6 on the host and not in the apiserver, is not possible to disable ipv6 in the host?
I'm considering options to have a load balancer (HAProxy static pod in hostNetwork) for api-server on control plane nodes listening on the same port as api-server. Then I would point api-server VIP to via hosts file on the control plane nodes. This is a workaround for the absence of hairpin in AWS NLB (with instances by id) or Azure LB. I'm looking for a generic solution that will work for AWS/Azure/on-prem with nodes in the same/different subnets. If you have other suggestions, feel free to share, I would appreciate that. For now, my solution is to call , then patch the generated static manifest with set to the node's default ip, and then bootstrap with . Binding the load balancer to IPv6 and and api-server to IPv4, then using in kubeadm's config will be a dirty, but cleaner from the code perspective, approach. Btw, is there any reason behind having set to by default, but not the node's default ip, just like ?
I can't understand how do you solve the hairpin problem that way, is not the traffic been directed to the LB vip too? or do you mean that you don't use the AWS NLB and use the haproxy instead? what VIP do you use then? I don't remember the details, but the apiserver should be available to the pods too, that don't reach it through the node, they use the the kubernetes.default Service
External clients use AWS load balancer, while requests from control plane nodes go to haproxy on localhost thanks to trick, thus do not reach AWS LB.

Related discussion:
text: fs.IPVar(&s.BindAddress, "bind-address", s.BindAddress, ""+ "The IP address on which to listen for the --secure-port port. The "+ "associated interface(s) must be reachable by the rest of the cluster, and by CLI/web "+ <del> "clients. If blank, all interfaces will be used (0.0.0.0 for all IPv4 interfaces and :: for all IPv6 interfaces).") </del> <ins> "clients. If blank or an unspecified address (0.0.0.0 or ::), all interfaces will be used.") </ins> desc := "The port on which to serve HTTPS with authentication and authorization." if s.Required {