Kubernetes Services for Egress Traffic
This task shows that these Kubernetes mechanisms for accessing external services continue to work with Istio.The only configuration step you must perform is to use a TLS mode other than Istio’smutual TLS. The external services are not part of an Istio servicemesh so they cannot perform the mutual TLS of Istio. You must set the TLS mode according to the TLS requirements of theexternal service and according to the way your workload accesses the external service. If your workload issues plainHTTP requests and the external service requires TLS, you may want to perform TLS origination by Istio. If your workloadalready uses TLS, the traffic is already encrypted and you can just disable Istio’s mutual TLS.
While the examples in this task use HTTP protocols,Kubernetes Services for egress traffic work with other protocols as well.
Setup Istio by following the instructions in the .
Deploy the sleep sample app to use as a test source for sending requests.If you haveenabled, run the following command to deploy the sample app:
Otherwise, manually inject the sidecar before deploying the sleep
application with the following command:
$ kubectl apply -f <(istioctl kube-inject -f @samples/sleep/sleep.yaml@)
- Set the
SOURCE_POD
environment variable to the name of your source pod:
$ export SOURCE_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})
- Create a namespace for a source pod without Istio control:
$ kubectl create namespace without-istio
- Start the sleep sample in the
without-istio
namespace.
$ kubectl apply -f @samples/sleep/sleep.yaml@ -n without-istio
- To send requests, create the
SOURCE_POD_WITHOUT_ISTIO
environment variable to store the name of the sourcepod:
$ export SOURCE_POD_WITHOUT_ISTIO=$(kubectl get pod -n without-istio -l app=sleep -o jsonpath={.items..metadata.name})
- Verify that the Istio sidecar was not injected, that is the pod has one container:
$ kubectl get pod $SOURCE_POD_WITHOUT_ISTIO -n without-istio
NAME READY STATUS RESTARTS AGE
sleep-66c8d79ff5-8tqrl 1/1 Running 0 32s
- Create a KubernetesExternalName servicefor
httpbin.org
:
$ kubectl apply -f - <<EOF
kind: Service
apiVersion: v1
metadata:
name: my-httpbin
spec:
type: ExternalName
externalName: httpbin.org
ports:
- name: http
protocol: TCP
port: 80
EOF
- Observe your service. Note that it does not have a cluster IP.
- Access
httpbin.org
via the Kubernetes service’s hostname from the source pod without Istio sidecar:
$ kubectl exec -it $SOURCE_POD_WITHOUT_ISTIO -n without-istio -c sleep -- curl my-httpbin.default.svc.cluster.local/headers
{
"headers": {
"Accept": "*/*",
"Host": "my-httpbin.default.svc.cluster.local",
"User-Agent": "curl/7.55.0"
}
- In this example, unencrypted HTTP requests are sent to
httpbin.org
. For the sake of the example only, you disablethe TLS mode and allow the unencrypted traffic to the external service. In the real life scenarios, we recommendto perform by Istio.
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: my-httpbin
spec:
trafficPolicy:
tls:
mode: DISABLE
EOF
- Access
httpbin.org
via the Kubernetes service’s hostname from the source pod with Istio sidecar. Notice theheaders added by Istio sidecar, for example,X-Istio-Attributes
andX-Envoy-Decorator-Operation
. Also note thattheHost
header equals to your service’s hostname.
$ kubectl exec -it $SOURCE_POD -c sleep -- curl my-httpbin.default.svc.cluster.local/headers
{
"headers": {
"Accept": "*/*",
"Host": "my-httpbin.default.svc.cluster.local",
"User-Agent": "curl/7.55.0",
"X-B3-Sampled": "0",
"X-B3-Spanid": "5b68b3f953945a08",
"X-B3-Traceid": "0847ba2513aa0ffc5b68b3f953945a08",
"X-Envoy-Decorator-Operation": "my-httpbin.default.svc.cluster.local:80/*",
"X-Istio-Attributes": "CigKGGRlc3RpbmF0aW9uLnNlcnZpY2UubmFtZRIMEgpteS1odHRwYmluCioKHWRlc3RpbmF0aW9uLnNlcnZpY2UubmFtZXNwYWNlEgkSB2RlZmF1bHQKOwoKc291cmNlLnVpZBItEitrdWJlcm5ldGVzOi8vc2xlZXAtNjZjOGQ3OWZmNS04aG1neC5kZWZhdWx0CkAKF2Rlc3RpbmF0aW9uLnNlcnZpY2UudWlkEiUSI2lzdGlvOi8vZGVmYXVsdC9zZXJ2aWNlcy9teS1odHRwYmluCkIKGGRlc3RpbmF0aW9uLnNlcnZpY2UuaG9zdBImEiRteS1odHRwYmluLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWw="
}
}
$ kubectl delete destinationrule my-httpbin
$ kubectl delete service my-httpbin
- Create a Kubernetes service without selector for Wikipedia:
$ kubectl apply -f - <<EOF
kind: Service
apiVersion: v1
metadata:
name: my-wikipedia
spec:
ports:
- protocol: TCP
port: 443
name: tls
EOF
- Create endpoints for your service. Pick a couple of IPs from the Wikipedia ranges list.
$ kubectl apply -f - <<EOF
kind: Endpoints
apiVersion: v1
metadata:
subsets:
- addresses:
- ip: 91.198.174.192
- ip: 198.35.26.96
- port: 443
name: tls
EOF
- Observe your service. Note that it has a cluster IP which you can use to access
wikipedia.org
.
$ kubectl get svc my-wikipedia
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-wikipedia ClusterIP 172.21.156.230 <none> 443/TCP 21h
- Send HTTPS requests to
wikipedia.org
by your Kubernetes service’s cluster IP from the source pod without Istiosidecar.Use the—resolve
option ofcurl
to accesswikipedia.org
by the cluster IP:
- In this case, the workload send HTTPS requests (open TLS connection) to the
wikipedia.org
. The traffic is alreadyencrypted by the workload so you can safely disable Istio’s mutual TLS:
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: my-wikipedia
spec:
host: my-wikipedia.default.svc.cluster.local
trafficPolicy:
tls:
mode: DISABLE
EOF
- Access
wikipedia.org
by your Kubernetes service’s cluster IP from the source pod with Istio sidecar:
$ kubectl exec -it $SOURCE_POD -c sleep -- curl -s --resolve en.wikipedia.org:443:$(kubectl get service my-wikipedia -o jsonpath='{.spec.clusterIP}') https://en.wikipedia.org/wiki/Main_Page | grep -o "<title>.*</title>"
<title>Wikipedia, the free encyclopedia</title>
- Check that the access is indeed performed by the cluster IP. Notice the sentence
Connected to en.wikipedia.org (172.21.156.230)
in the output ofcurl -v
, it mentions the IP that was printedin the output of your service as the cluster IP.
$ kubectl exec -it $SOURCE_POD -c sleep -- curl -v --resolve en.wikipedia.org:443:$(kubectl get service my-wikipedia -o jsonpath='{.spec.clusterIP}') https://en.wikipedia.org/wiki/Main_Page -o /dev/null
* Added en.wikipedia.org:443:172.21.156.230 to DNS cache
* Hostname en.wikipedia.org was found in DNS cache
* Trying 172.21.156.230...
* TCP_NODELAY set
* Connected to en.wikipedia.org (172.21.156.230) port 443 (#0)
...
Cleanup of Kubernetes service with endpoints
$ kubectl delete destinationrule my-wikipedia
$ kubectl delete endpoints my-wikipedia
$ kubectl delete service my-wikipedia
- Shutdown the sleep service:
$ kubectl delete -f @samples/sleep/sleep.yaml@
- Shutdown the sleep service in the
without-istio
namespace:
$ kubectl delete -f @samples/sleep/sleep.yaml@ -n without-istio
- Delete
without-istio
namespace:
$ kubectl delete namespace without-istio
Secure Control of Egress Traffic in Istio, part 3
Comparison of alternative solutions to control egress traffic including performance considerations.
Use Istio Egress Traffic Control to prevent attacks involving egress traffic.
Attacks involving egress traffic and requirements for egress traffic control.
Egress Gateway Performance Investigation
Verifies the performance impact of adding an egress gateway.
Describes a simple scenario based on Istio's Bookinfo example.
Monitoring and Access Policies for HTTP Egress Traffic
Describes how to configure Istio for monitoring and access policies of HTTP egress traffic.