Change:
Is this a request for help? No What keywords did you search in Kubernetes issues before filing this one? externalIPs kube-proxy connection accepted no pods running. icmp reject rules. Is this a BUG REPORT or FEATURE REQUEST? (choose one): BUG REPORT Kubernetes version (use ): kubectl version Environment: Cloud provider or hardware configuration: Bare Metal. OS (e.g. from /etc/os-release):Kernel (e.g. ):Install tools: Others: What happened: is exposed using externalIP construct. pods are backing the service (using scale deployment 0). The pod is expected to run a TCP based server (non-http) client connects to this service using externalIP as dest-ip; connection gets accepted by kube-proxy. What you expected to happen: When no pods are backing service; the connection should have been rejected and definitely not accepted by kube-proxy. How to reproduce it (as minimally and precisely as possible): a service and expose it using externalIP construct pods are present; bring them down using"kubectl scale deployment my_svc --replicas 0 --namespace xyz initiates the connection to this service using externalIP and connection goes fine but to kube-proxy. Anything else we need to know: Info on iptable rules - When service and pods are present the rules like these - pods are not present; iptables rules look like this - that the reject rule exist only for the destination=ServiceIP=10.100.200.6/32 no pods are present; client gets connected to kube-proxy On VM - Based on and ; I manually installed reject rule on INPUT chain. I do not see the issue happening again - meaning client then cannot connect to the server when no pods are present.
I have a suggestion for installing icmp reject rules. Why cant icmp reject rule always present in INPUT chain? kube-proxy do not really need to check if pods are present or not for installing these rules. For the svcip/externaip to pod-ip translation; kube-proxy anyways install the rule to do DNAT in which case the icmp reject rule from INPUT wont be hit. In case when DNAT fails to happen - e.g. in cases like pods not present - icmp reject rule will anyways kick in to reject such packet. This would be better than accidentally giving the packet to kube-proxy which is always listening on the port and accepting this accidental connection even when it does not intend to. Actually, for now that's how I am putting workaround for this problem in our setup.
That might be a clever answer - I hadn't thought of it that way. Would need good tests and comments.
I can give a shot at testing it. I didnt find a good reference document / todo for testing such changes. If you can help me locate it; I can give it a try.

Discussion:
// Allow traffic bound for external IPs that happen to be recognized as local IPs to stay local. // This covers cases like GCE load-balancers which get added to the local routing table. writeLine(natRules, append(dstLocalOnlyArgs, "-j", string(svcChain))...) <ins> // If the service has no endpoints then reject packets coming via externalIP // Install ICMP Reject rule in filter table for destination=externalIP and dport=svcport if len(proxier.endpointsMap[svcName]) == 0 { writeLine(filterRules, "-A", string(kubeServicesChain), "-m", "comment", "--comment", fmt.Sprintf(`"%s has no endpoints"`, svcNameString), "-m", protocol, "-p", protocol, "-d", fmt.Sprintf("%s/32", externalIP), "--dport", fmt.Sprintf("%d", svcInfo.port), "-j", "REJECT", ) } </ins> } // Capture load-balancer ingress.

} } <ins> func TestExternalIPsReject(t *testing.T) { ipt := iptablestest.NewFake() fp := NewFakeProxier(ipt) svcIP := "10.20.30.41" svcPort := 80 svcExternalIPs := "50.60.70.81" svcPortName := proxy.ServicePortName{ NamespacedName: makeNSN("ns1", "svc1"), Port:           "p80", } makeServiceMap(fp, makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *api.Service) { svc.Spec.Type = "ClusterIP" svc.Spec.ClusterIP = svcIP svc.Spec.ExternalIPs = []string{svcExternalIPs} svc.Spec.Ports = []api.ServicePort{{ Name:       svcPortName.Port, Port:       int32(svcPort), Protocol:   api.ProtocolTCP, TargetPort: intstr.FromInt(svcPort), }} }), ) makeEndpointsMap(fp) fp.syncProxyRules(syncReasonForce) kubeSvcRules := ipt.GetRules(string(kubeServicesChain)) if !hasJump(kubeSvcRules, iptablestest.Reject, svcExternalIPs, svcPort) { errorf(fmt.Sprintf("Failed to a %v rule for externalIP %v with no endpoints", iptablestest.Reject, svcPortName), kubeSvcRules, t) } } </ins> func TestNodePortReject(t *testing.T) { ipt := iptablestest.NewFake() fp := NewFakeProxier(ipt)