From ac7c026ee7d1313b5a4ccac085e859c51a042ef7 Mon Sep 17 00:00:00 2001 From: Ketan Kulkarni Date: Mon, 17 Apr 2017 02:10:54 -0700 Subject: [PATCH] Reject Rules for ExternalIP and svc port if no ep - Install ICMP Reject Rules for externalIP and svc port if no endpoints are present - Includes Unit Test case - Fixes #44516 --- pkg/proxy/iptables/proxier.go | 13 ++++++++++++ pkg/proxy/iptables/proxier_test.go | 34 ++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/pkg/proxy/iptables/proxier.go b/pkg/proxy/iptables/proxier.go index 8d133e33006..202901a24cb 100644 --- a/pkg/proxy/iptables/proxier.go +++ b/pkg/proxy/iptables/proxier.go @@ -1169,6 +1169,19 @@ func (proxier *Proxier) syncProxyRules(reason syncReason) { // 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))...) + + // 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", + ) + } } // Capture load-balancer ingress. diff --git a/pkg/proxy/iptables/proxier_test.go b/pkg/proxy/iptables/proxier_test.go index 5d15de681ee..b599d523759 100644 --- a/pkg/proxy/iptables/proxier_test.go +++ b/pkg/proxy/iptables/proxier_test.go @@ -760,6 +760,40 @@ func TestNodePort(t *testing.T) { } } +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) + } +} + func TestNodePortReject(t *testing.T) { ipt := iptablestest.NewFake() fp := NewFakeProxier(ipt)