Skip to content
This repository has been archived by the owner on Jun 14, 2018. It is now read-only.

prepare_proxy: add support for excluding external traffic #573

Merged
merged 15 commits into from
Apr 25, 2017

Conversation

ayj
Copy link
Contributor

@ayj ayj commented Apr 24, 2017

(Note for reviewers: prepare_proxy.sh is ready for review. prepare_proxy_test.sh is functional with some hand edits required for the configuration. It could probably be rewritten in golang to make it more readable.)

Short term solution to #515 for external traffic.

Add generic support for including and excluding outbound traffic based
on CIDR blocks. Default behavior is opt-out where all outbound traffic
is redirected to proxy unless explicitly opted-opt with "-e"
option. When the "-i" option is used the behavior changes to opt-in
and only outbound traffic explicitly specified with "-i" is redirected
to the proxy. The "-i" option takes precedence over "-e" the option if
both are specified.

As part of this change the iptable rules were refactored to make it
easier differentiate redirect from bypass cases, e.g. '-j
ISTIO_REDIRECT' vs. '-j RETURN'.

Add generic support for including and excluding outbound traffic based
on CIDR blocks. Default behavior is opt-out where all outbound traffic
is redirected to proxy unless explicitly opted-opt with "-e"
option. When the "-i" option is used the behavior changes to opt-in
and only outbound traffic explicitly specified with "-i" is redirected
to the proxy. The "-i" option takes precedence over "-e" the option if
both are specified.

As part of this change the iptable rules were refactored to make it
easier differentiate redirect from bypass cases, e.g. '-j
ISTIO_REDIRECT' vs. '-j RETURN'.
@ayj ayj requested review from kyessenov and rshriram April 24, 2017 07:42
@rshriram
Copy link
Member

Can we reduce the confusion on opt-out and opt-in and just have one? Like a set of -i flags. With no -i, all traffic goes through proxy. With -i, operators could restrict traffic capture to specific CIDR blocks.

Copy link
Member

@rshriram rshriram left a comment

Choose a reason for hiding this comment

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

Overall, looks pretty well done. Thanks for the extensive comments. Few minor issues in the PR.

# (i.e. proxy aware) or not from the proxy itself is redirected proxy port.
iptables -t nat -A OUTPUT -p tcp -j REDIRECT ! -s 127.0.0.1/32 \
--to-port ${ISTIO_PROXY_PORT} -m owner '!' --uid-owner ${ISTIO_PROXY_UID}
iptables -t nat -F
Copy link
Member

Choose a reason for hiding this comment

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

Why do we need to flush nat?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We don't. It was useful for unit testing but can be removed since prepare_proxy_test.sh restarts the pods for each test iteration.

# the common Istio proxy port.
iptables -t nat -N ISTIO_REDIRECT -m comment --comment "istio/redirect-common-chain"
iptables -t nat -A ISTIO_REDIRECT -p tcp -j REDIRECT --to-ports ${ISTIO_PROXY_PORT} -m comment --comment "istio/redirect-to-proxy-port"

Copy link
Member

Choose a reason for hiding this comment

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

Nicely done! Thanks for these comments and clean documentation.

Copy link
Member

Choose a reason for hiding this comment

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

Change istio proxy to Envoy everywhere to align with rest of documentation

iptables -t nat -N ISTIO_REDIRECT -m comment --comment "istio/redirect-common-chain"
iptables -t nat -A ISTIO_REDIRECT -p tcp -j REDIRECT --to-ports ${ISTIO_PROXY_PORT} -m comment --comment "istio/redirect-to-proxy-port"

# Redirect all inbound traffic to the proxy.
Copy link
Member

Choose a reason for hiding this comment

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

Inbound traffic into the pod

Copy link
Member

Choose a reason for hiding this comment

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

Can you add -m comment to all commands?

# istio and attach it the OUTPUT rule for all tcp traffic. '-j RETURN'
# bypasses the proxy port; '-j ISTIO_REDIRECT' redirects to the proxy
# port.
iptables -t nat -N ISTIO_OUTPUT
Copy link
Member

Choose a reason for hiding this comment

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

And what is -j ISTIO_OUTPUT ? (Missing comments).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The preceding comment was intended to cover lines 68 and 69 (i.e. create chain and attach to OUTPUT rule). I'll split this up to make it more clear.

# Locally routed traffic is not captured by PREROUTING chain. Redirect
# loopback back traffic when the DST_IP is not explicitly the loopback
# address to handles appN => proxy (client) => proxy (server) => appN.
iptables -t nat -A ISTIO_OUTPUT -o lo ! -d 127.0.0.1/32 -j ISTIO_REDIRECT -m comment --comment "istio/implicit-loopback"
Copy link
Member

Choose a reason for hiding this comment

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

Probably best to describe the use case instead of the data flow. E.g., when kubelet accesses the app for health checks (??), or app calls itself via http://podIP/..

Copy link
Member

Choose a reason for hiding this comment

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

And shouldn't this be restricted to tcp?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We only jump to ISTIO_OUTPUT for tcp protocol traffic (line 69) so the -p tcp seemed redundant. I can add it back if that makes things more clear though.

# container-to-container traffic which explicitly use localhost.
iptables -t nat -A ISTIO_OUTPUT -d 127.0.0.1/32 -j RETURN -m comment --comment "istio/explicit-loopback"

# The default outobund redirection policy is opt-out. IP ranges may be
Copy link
Member

Choose a reason for hiding this comment

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

Typo. Outbound

for cidr in ${ISTIO_IP_RANGES_INCLUDE}; do
iptables -t nat -A ISTIO_OUTPUT -d ${cidr} -j ISTIO_REDIRECT -m comment --comment "istio/include-cidr-block-${cidr}"
done
iptables -t nat -A ISTIO_OUTPUT -j RETURN -m comment --comment "istio/default-opt-out-redirect"
Copy link
Member

Choose a reason for hiding this comment

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

If we follow the suggestion I made earlier (just have -i cidr), then this else block moves to the top doesn't it? We would no longer require the default catch all policy either.


if false; then
# exclude specific external traffic (opt-out)
EXCLUDE_CIDR=$(host httpbin.org | cut -f4 -d' ' | sed -e 's|$|/32|' | paste -sd ",")
Copy link
Member

Choose a reason for hiding this comment

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

What's the point of this if block ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It creates a comma-separated list of IP ranges for httpbin.org to be excluded from redirection.

$ host httpbin.org | cut -f4 -d' ' | sed -e 's|$|/32|' | paste -sd ","
107.21.206.81/32,50.19.93.247/32,54.225.109.133/32,54.243.85.55/32,23.23.128.123/32,23.23.223.197/32,23.21.77.86/32,23.23.117.228/32
```

Copy link
Member

Choose a reason for hiding this comment

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

No, I meant the if false block. This is never going to be executed is it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, this was for manual testing. I'll added a flag at the top of control this as part of the refactoring to remove the EXCLUDE option.

INCLUDE_CIDR=$(gcloud container clusters describe ${GCLOUD_CLUSTER_NAME} --zone=${GCLOUD_CLUSTER_ZONE} |
grep -e clusterIpv4Cidr -e servicesIpv4Cidr |
cut -f2 -d' ' | paste -sd ",")

Copy link
Member

Choose a reason for hiding this comment

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

Could you perhaps abstract this function out so that people could test this on say minikube or their local k8s clusters?

# redirection with ISTIO_IP_RANGES_INCLUDE.
# Only redirect outbound traffic to selective IP ranges when
# ISTIO_IP_RANGES_INCLUDE is non-empty. Otherwise redirect all
# outbound traffic not already handled by the previous rules to Envoy.
Copy link
Member

Choose a reason for hiding this comment

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

I would reuse a previous version of this comment as it looked better.
All outbound traffic will be redirected to Envoy by default. If ISTIO_IP_RANGES_INCLUDE is non-empty, only traffic bound for the destinations specified in this list will be captured.

@ayj
Copy link
Contributor Author

ayj commented Apr 24, 2017

Fixes #515 for alpha.

CLIENT_PORT=81
OTHER_PORT=82
TEST_IP_RANGE_INCLUDE=0

Copy link
Member

Choose a reason for hiding this comment

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

add a variable: PLATFORM="gcloud"

# list, e.g. 10.0.0.1/32,10.2.0.1/16. This function is GKE specific
# and must modified for other providers, e.g. minikube.
function k8sClusterAndServiceIPRange() {
echo $(gcloud container clusters describe ${GCLOUD_CLUSTER_NAME} --zone=${GCLOUD_CLUSTER_ZONE} |
Copy link
Member

Choose a reason for hiding this comment

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

case $platform in
gcloud)
echo..
*)
echo ""
esac

Copy link
Member

@rshriram rshriram left a comment

Choose a reason for hiding this comment

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

couple of comments in the test script

echo ' -u: Specify the UID of the user for which the redirection is not'
echo ' applied. Typically, this is the UID of the proxy container'
echo ' -i: Comma separated list of IP ranges in CIDR form to redirection to envoy (optional)'
Copy link
Contributor

Choose a reason for hiding this comment

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

"for redirection"?

;;
h)
usage
usagey
Copy link
Contributor

Choose a reason for hiding this comment

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

typo?

ENVOY_UID=${OPTARG}
;;
i)
ISTIO_IP_RANGES_INCLUDE=${OPTARG}
Copy link
Contributor

Choose a reason for hiding this comment

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

why rename ISTIO_PROXY_PORT but keep this ISTIO_?

Copy link
Contributor

Choose a reason for hiding this comment

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

there's not much specific to envoy in this script btw

# Create a new chain for redirecting inbound and outbound traffic to
# the common Envoy port.
iptables -t nat -N ISTIO_REDIRECT -m comment --comment "istio/redirect-common-chain"
iptables -t nat -A ISTIO_REDIRECT -p tcp -j REDIRECT --to-ports ${ENVOY_PORT} -m comment --comment "istio/redirect-to-envoy-port"
Copy link
Contributor

Choose a reason for hiding this comment

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

"to-ports"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Either will work, but changed to "to-port" to avoid confusion.

@@ -0,0 +1,238 @@
#!/bin/sh
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd really prefer not have these long bash test scripts. They are close to unmaintainable...

# Skip redirection for Envoy-aware applications and
# container-to-container traffic both of which explicitly use
# localhost.
iptables -t nat -A ISTIO_OUTPUT -d 127.0.0.1/32 -j RETURN -m comment --comment "istio/bypass-explicit-loopback"
Copy link
Contributor

Choose a reason for hiding this comment

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

I have difficulty understanding all implications of these rules, so I trust @rshriram carefully reviewed these

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed. Most of the setup/teardown code can be shared with the other integration tests. Maybe after release we can split that out into its own test package and have individual tests consume that that?

@istio-testing
Copy link
Contributor

Jenkins job manager/presubmit passed

@istio-testing
Copy link
Contributor

Jenkins job manager/e2e-smoketest passed

@istio-testing
Copy link
Contributor

Jenkins job manager/presubmit passed

@istio-testing
Copy link
Contributor

Jenkins job manager/e2e-smoketest passed

@ayj ayj merged commit 204a14f into istio:master Apr 25, 2017
docker_build(
name = "init",
base = "@docker_ubuntu//:xenial",
manager_docker_build(
Copy link
Contributor

Choose a reason for hiding this comment

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

please put those back in jenkinsfile if you need them.

@ayj ayj deleted the add-outbound-traffic-bypass-flag branch April 28, 2017 16:37
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants