Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

kube-proxy treat ExternalIPs as ClusterIPs #96296

Merged
merged 2 commits into from Dec 9, 2020
Merged

Conversation

aojea
Copy link
Member

@aojea aojea commented Nov 6, 2020

/kind cleanup

What this PR does / why we need it:

Currently kube-proxy treat ExternalIPs differently depending on
were the traffic is originated and if the ExternalIP is present
or not in the system. It also depends on the CNI implementation to
discriminate between local and non-local traffic.

Since the ExternalIP belongs to a Service, we can avoid the roundtrip
of sending the traffic originated internally outside, if the ExternalIP
is not present in the host and send it directly to the Service.
Also, we leverage the new LocalTrafficDetector to detect the local
traffic and not rely on the CNI implementations for this.

Fixes #95785

Special notes for your reviewer:

kube-proxy: Traffic from the cluster directed to ExternalIPs is always sent directly to the Service.

@k8s-ci-robot k8s-ci-robot added release-note Denotes a PR that will be considered when it comes time to generate release notes. kind/cleanup Categorizes issue or PR as related to cleaning up code, process, or technical debt. size/M Denotes a PR that changes 30-99 lines, ignoring generated files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. do-not-merge/needs-sig Indicates an issue or PR lacks a `sig/foo` label and requires one. needs-triage Indicates an issue or PR lacks a `triage/foo` label and requires one. labels Nov 6, 2020
@k8s-ci-robot
Copy link
Contributor

@aojea: This issue is currently awaiting triage.

If a SIG or subproject determines this is a relevant issue, they will accept it by applying the triage/accepted label and provide further guidance.

The triage/accepted label can be added by org members by writing /triage accepted in a comment.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@k8s-ci-robot k8s-ci-robot added needs-priority Indicates a PR lacks a `priority/foo` label and requires one. area/e2e-test-framework Issues or PRs related to refactoring the kubernetes e2e test framework area/test sig/network Categorizes an issue or PR as relevant to SIG Network. sig/testing Categorizes an issue or PR as relevant to SIG Testing. and removed do-not-merge/needs-sig Indicates an issue or PR lacks a `sig/foo` label and requires one. labels Nov 6, 2020
@aojea aojea changed the title kube-proxy: kube-proxy treat ExternalIPs as ClusterIPs Nov 6, 2020
@aojea
Copy link
Member Author

aojea commented Nov 6, 2020

/assign @danwinship @thockin
Putting this up for discussion, touching these things in kube-proxy always make me nervous 😅

@aojea
Copy link
Member Author

aojea commented Nov 6, 2020

/test pull-kubernetes-e2e-gce-ubuntu
I think that this job is using kubenet and cni with bridge, so it failed the new test before this change

@aojea
Copy link
Member Author

aojea commented Nov 6, 2020

/test pull-kubernetes-e2e-gce-ubuntu-canary
the other job is not working

@k8s-ci-robot
Copy link
Contributor

@aojea: The specified target(s) for /test were not found.
The following commands are available to trigger jobs:

  • /test pull-kubernetes-bazel-build
  • /test pull-kubernetes-bazel-test
  • /test pull-kubernetes-conformance-image-test
  • /test pull-kubernetes-conformance-kind-ipv6-parallel
  • /test pull-kubernetes-dependencies
  • /test pull-kubernetes-dependencies-canary
  • /test pull-kubernetes-e2e-ipvs-azure-dualstack
  • /test pull-kubernetes-e2e-iptables-azure-dualstack
  • /test pull-kubernetes-e2e-aws-eks-1-13-correctness
  • /test pull-kubernetes-files-remake
  • /test pull-kubernetes-e2e-gce
  • /test pull-kubernetes-e2e-gce-no-stage
  • /test pull-kubernetes-e2e-gce-kubetest2
  • /test pull-kubernetes-e2e-gce-canary
  • /test pull-kubernetes-e2e-gce-ubuntu
  • /test pull-kubernetes-e2e-gce-ubuntu-containerd
  • /test pull-kubernetes-e2e-gce-ubuntu-containerd-canary
  • /test pull-kubernetes-e2e-gce-rbe
  • /test pull-kubernetes-e2e-gce-alpha-features
  • /test pull-kubernetes-e2e-gce-device-plugin-gpu
  • /test pull-kubernetes-integration
  • /test pull-kubernetes-cross
  • /test pull-kubernetes-e2e-kind
  • /test pull-kubernetes-e2e-kind-canary
  • /test pull-kubernetes-e2e-kind-ipv6
  • /test pull-kubernetes-e2e-kind-ipv6-canary
  • /test pull-kubernetes-conformance-kind-ga-only
  • /test pull-kubernetes-conformance-kind-ga-only-parallel
  • /test pull-kubernetes-e2e-kops-aws
  • /test pull-kubernetes-bazel-build-canary
  • /test pull-kubernetes-bazel-test-canary
  • /test pull-kubernetes-bazel-test-integration-canary
  • /test pull-kubernetes-local-e2e
  • /test pull-publishing-bot-validate
  • /test pull-kubernetes-e2e-gce-network-proxy-http-connect
  • /test pull-kubernetes-e2e-gce-network-proxy-grpc
  • /test pull-kubernetes-e2e-gci-gce-autoscaling
  • /test pull-kubernetes-e2e-aks-engine-azure
  • /test pull-kubernetes-e2e-azure-disk
  • /test pull-kubernetes-e2e-azure-disk-vmss
  • /test pull-kubernetes-e2e-azure-file
  • /test pull-kubernetes-e2e-kind-dual-canary
  • /test pull-kubernetes-e2e-kind-ipvs-dual-canary
  • /test pull-kubernetes-e2e-gci-gce-ipvs
  • /test pull-kubernetes-node-e2e
  • /test pull-kubernetes-e2e-containerd-gce
  • /test pull-kubernetes-node-e2e-containerd
  • /test pull-kubernetes-node-e2e-alpha
  • /test pull-kubernetes-node-kubelet-serial-cpu-manager
  • /test pull-kubernetes-node-kubelet-serial-topology-manager
  • /test pull-kubernetes-node-kubelet-serial-hugepages
  • /test pull-kubernetes-node-crio-cgrpv2-e2e
  • /test pull-kubernetes-node-crio-e2e
  • /test pull-kubernetes-node-kubelet-serial-memory-manager
  • /test pull-kubernetes-e2e-gce-100-performance
  • /test pull-kubernetes-e2e-gce-big-performance
  • /test pull-kubernetes-e2e-gce-correctness
  • /test pull-kubernetes-e2e-gce-large-performance
  • /test pull-kubernetes-kubemark-e2e-gce-big
  • /test pull-kubernetes-kubemark-e2e-gce-scale
  • /test pull-kubernetes-e2e-gce-storage-slow
  • /test pull-kubernetes-e2e-gce-storage-snapshot
  • /test pull-kubernetes-e2e-gce-storage-slow-rbe
  • /test pull-kubernetes-e2e-gce-csi-serial
  • /test pull-kubernetes-e2e-gce-iscsi
  • /test pull-kubernetes-e2e-gce-iscsi-serial
  • /test pull-kubernetes-e2e-gce-storage-disruptive
  • /test pull-kubernetes-e2e-aks-engine-azure-windows
  • /test pull-kubernetes-e2e-azure-disk-windows
  • /test pull-kubernetes-e2e-azure-file-windows
  • /test pull-kubernetes-e2e-aks-engine-windows-gpu
  • /test pull-kubernetes-typecheck
  • /test pull-kubernetes-verify
  • /test pull-kubernetes-e2e-windows-gce

Use /test all to run the following jobs:

  • pull-kubernetes-bazel-build
  • pull-kubernetes-bazel-test
  • pull-kubernetes-conformance-kind-ipv6-parallel
  • pull-kubernetes-dependencies
  • pull-kubernetes-e2e-gce-ubuntu-containerd
  • pull-kubernetes-integration
  • pull-kubernetes-e2e-kind
  • pull-kubernetes-e2e-kind-ipv6
  • pull-kubernetes-conformance-kind-ga-only-parallel
  • pull-kubernetes-node-e2e
  • pull-kubernetes-e2e-gce-100-performance
  • pull-kubernetes-typecheck
  • pull-kubernetes-verify

In response to this:

/test pull-kubernetes-e2e-gce-ubuntu-canary
the other job is not working

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@aojea
Copy link
Member Author

aojea commented Nov 6, 2020

/test pull-kubernetes-e2e-gce-canary
/test pull-kubernetes-e2e-gce
/test pull-kubernetes-e2e-gce-kubetest2
/test pull-kubernetes-e2e-iptables-azure-dualstack

@k8s-ci-robot
Copy link
Contributor

k8s-ci-robot commented Nov 6, 2020

@aojea: The following tests failed, say /retest to rerun all failed tests:

Test name Commit Details Rerun command
pull-kubernetes-e2e-gce-ubuntu 80bd24db36c7b03c3181787b18c6dff66552c3dc link /test pull-kubernetes-e2e-gce-ubuntu
pull-kubernetes-e2e-gce-kubetest2 80bd24db36c7b03c3181787b18c6dff66552c3dc link /test pull-kubernetes-e2e-gce-kubetest2
pull-kubernetes-e2e-gce 80bd24db36c7b03c3181787b18c6dff66552c3dc link /test pull-kubernetes-e2e-gce
pull-kubernetes-e2e-iptables-azure-dualstack 80bd24db36c7b03c3181787b18c6dff66552c3dc link /test pull-kubernetes-e2e-iptables-azure-dualstack

Full PR test history. Your PR dashboard. Please help us cut down on flakes by linking to an open issue when you hit one in your PR.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here.

pkg/proxy/iptables/proxier.go Outdated Show resolved Hide resolved
// This is imperfect in the face of network plugins that might not use a bridge, but we can revisit that later.
externalTrafficOnlyArgs := append(args,
"-m", "physdev", "!", "--physdev-is-in",
"-m", "addrtype", "!", "--src-type", "LOCAL")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switching to the local traffic detector is probably not currently a compatible replacement for this rule, since we don't currently have the physdev-based local traffic detector, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that the discussion is if this rule is correct, that it seems it is not, because CNIs not using bridges are not affected ...
what we want to do is to SNAT all the non-local traffic that is what the local detector should do, independently of the implementation

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure this is quite correct.

Before this change, we try to:

  1. always MASQ
  2. send all from-off-node traffic to the service chain
  3. send from-on-node traffic to the service chain IFF the dst is "local"
  4. send any other from-on-node traffic to the network

(4) matters because the IP presumably might do some processing/telemtry/whatever and we don't want to short-circuit that
(3) matters because the result of (4) will be wrong if the IP is local

Now, most CNIs, including kubenet (I think) don't use the bridge any more so we effectively do:

  1. always MASQ
  2. send all traffic to the service chain

What you do after this change is:

  1. MASQ from-off-node traffic if policy is not local-only (seems ok)
  2. send all traffic to the service chain

Your (1) seems like an improvement.
Your (2) seems like not worse than what has ACTUALLY been happening.

This field is rather under-specified and, in thinking about it, it was probably wrong before. So OK. I think I am in. I have a nit above, but I am happy to see physdev go away

@@ -1179,6 +1179,37 @@ var _ = SIGDescribe("Services", func() {
framework.ExpectNoError(err)
})

/*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this? C? 🙂

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cherry picked the previous test, learning something new every day :)

https://golang.org/doc/effective_go.html#commentary

@danwinship
Copy link
Contributor

sorry, catching up on #95785 out of order...

pkg/proxy/iptables/proxier.go Outdated Show resolved Hide resolved
pkg/proxy/iptables/proxier.go Show resolved Hide resolved
// This is imperfect in the face of network plugins that might not use a bridge, but we can revisit that later.
externalTrafficOnlyArgs := append(args,
"-m", "physdev", "!", "--physdev-is-in",
"-m", "addrtype", "!", "--src-type", "LOCAL")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure this is quite correct.

Before this change, we try to:

  1. always MASQ
  2. send all from-off-node traffic to the service chain
  3. send from-on-node traffic to the service chain IFF the dst is "local"
  4. send any other from-on-node traffic to the network

(4) matters because the IP presumably might do some processing/telemtry/whatever and we don't want to short-circuit that
(3) matters because the result of (4) will be wrong if the IP is local

Now, most CNIs, including kubenet (I think) don't use the bridge any more so we effectively do:

  1. always MASQ
  2. send all traffic to the service chain

What you do after this change is:

  1. MASQ from-off-node traffic if policy is not local-only (seems ok)
  2. send all traffic to the service chain

Your (1) seems like an improvement.
Your (2) seems like not worse than what has ACTUALLY been happening.

This field is rather under-specified and, in thinking about it, it was probably wrong before. So OK. I think I am in. I have a nit above, but I am happy to see physdev go away

Antonio Ojea and others added 2 commits November 22, 2020 00:54
Currently kube-proxy treat ExternalIPs differently depending on:
- the traffic origin
- if the ExternalIP is present or not in the system.

It also depends on the CNI implementation to
discriminate between local and non-local traffic.

Since the ExternalIP belongs to a Service, we can avoid the roundtrip
of sending outside the traffic originated in the cluster.

Also, we leverage the new LocalTrafficDetector to detect the local
traffic and not rely on the CNI implementations for this.
Copy link
Member

@thockin thockin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

/lgtm
/approve

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Nov 22, 2020
@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: aojea, thockin

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Nov 22, 2020
writeLine(proxier.natRules, append(args, "-j", string(KubeMarkMasqChain))...)
// This masquerades off-cluster traffic to a External IP.
if proxier.localDetector.IsImplemented() {
writeLine(proxier.natRules, proxier.localDetector.JumpIfNotLocal(args, string(KubeMarkMasqChain))...)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's been a while since I've read the local detector code, but does this also account for traffic that would be caught with --src-type LOCAL?

Can we assume that externalIP should bind locally in the same way status.ingress[i].ip (a.k.a loadbalancerIP) would? Loadbalancer IP has a check for --src-type LOCAL which accounts for host network traffic to external IPs. Should we add the same here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah nvm, this would end up jumping to svcXLBChain anyways which would have the --src-type LOCAL check if traffic was local.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this also account for traffic that would be caught with --src-type LOCAL?

Curiously, NO. It does not. The "by CIDR" implementation will not catch hostNetwork pods. Looking at how it is used today, it seems like we handle it specially ("// Next, redirect all src-type=LOCAL -> LB IP to the service chain") or is moot (MARK_MASQ does nothing).

I wonder if we should fix that more completely. Awkward because there are some other rules with the same predicates (MARK_MASQ on the above case).

@aojea
Copy link
Member Author

aojea commented Dec 7, 2020

/hold
this may not be appropiate due to the CVE opened to ExternalIPs
#97110

@k8s-ci-robot k8s-ci-robot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Dec 7, 2020
@thockin
Copy link
Member

thockin commented Dec 7, 2020 via email

@aojea
Copy link
Member Author

aojea commented Dec 7, 2020

I don't think the CVE makes any difference here. It's still a bad feature that should be disabled on most clusters.

/hold cancel

😅 👍

@k8s-ci-robot k8s-ci-robot removed the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Dec 7, 2020
@k8s-ci-robot k8s-ci-robot merged commit 9d81c4e into kubernetes:master Dec 9, 2020
@k8s-ci-robot k8s-ci-robot added this to the v1.21 milestone Dec 9, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. area/e2e-test-framework Issues or PRs related to refactoring the kubernetes e2e test framework area/test cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. kind/cleanup Categorizes issue or PR as related to cleaning up code, process, or technical debt. lgtm "Looks good to me", indicates that a PR is ready to be merged. needs-priority Indicates a PR lacks a `priority/foo` label and requires one. needs-triage Indicates an issue or PR lacks a `triage/foo` label and requires one. release-note Denotes a PR that will be considered when it comes time to generate release notes. sig/network Categorizes an issue or PR as relevant to SIG Network. sig/testing Categorizes an issue or PR as relevant to SIG Testing. size/M Denotes a PR that changes 30-99 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add e2e test for Service ExternalIPs
6 participants