Kubernetes Services for Egress Traffic

Kubernetes ExternalNameservices and Kubernetes services withEndpointslet you create a local DNS alias to an external service.This DNS alias has the same form as the DNS entries for local services, namely<service name>.<namespace name>.svc.cluster.local. DNS aliases provide location transparency for your workloads:the workloads can call local and external services in the same way. If at some point in time you decide to deploy theexternal service inside your cluster, you can just update its Kubernetes service to reference the local version. The workloads will continue to operate without any change.

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.

Before you begin

Zip

  1. $ kubectl apply -f @samples/sleep/sleep.yaml@

Otherwise, manually inject the sidecar before deploying the sleep application with the following command:

Zip

  1. $ kubectl apply -f <(istioctl kube-inject -f @samples/sleep/sleep.yaml@)

You can use any pod with curl installed as a test source.

  • Set the SOURCE_POD environment variable to the name of your source pod:
  1. $ export SOURCE_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})
  • Create a namespace for a source pod without Istio control:
  1. $ kubectl create namespace without-istio
  • Start the sleep sample in the without-istio namespace.

Zip

  1. $ 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:
  1. $ 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:
  1. $ kubectl get pod $SOURCE_POD_WITHOUT_ISTIO -n without-istio
  2. NAME READY STATUS RESTARTS AGE
  3. sleep-66c8d79ff5-8tqrl 1/1 Running 0 32s

Kubernetes ExternalName service to access an external service

  1. $ kubectl apply -f - <<EOF
  2. kind: Service
  3. apiVersion: v1
  4. metadata:
  5. name: my-httpbin
  6. spec:
  7. type: ExternalName
  8. externalName: httpbin.org
  9. ports:
  10. - name: http
  11. protocol: TCP
  12. port: 80
  13. EOF
  • Observe your service. Note that it does not have a cluster IP.
  1. $ kubectl get svc my-httpbin
  2. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  3. my-httpbin ExternalName <none> httpbin.org 80/TCP 4s
  • Access httpbin.org via the Kubernetes service’s hostname from the source pod without Istio sidecar:
  1. $ kubectl exec -it $SOURCE_POD_WITHOUT_ISTIO -n without-istio -c sleep -- curl my-httpbin.default.svc.cluster.local/headers
  2. {
  3. "headers": {
  4. "Accept": "*/*",
  5. "Host": "my-httpbin.default.svc.cluster.local",
  6. "User-Agent": "curl/7.55.0"
  7. }
  8. }
  • 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 Egress TLS origination by Istio.
  1. $ kubectl apply -f - <<EOF
  2. apiVersion: networking.istio.io/v1alpha3
  3. kind: DestinationRule
  4. metadata:
  5. name: my-httpbin
  6. spec:
  7. host: my-httpbin.default.svc.cluster.local
  8. trafficPolicy:
  9. tls:
  10. mode: DISABLE
  11. 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 and X-Envoy-Decorator-Operation. Also note thatthe Host header equals to your service’s hostname.
  1. $ kubectl exec -it $SOURCE_POD -c sleep -- curl my-httpbin.default.svc.cluster.local/headers
  2. {
  3. "headers": {
  4. "Accept": "*/*",
  5. "Host": "my-httpbin.default.svc.cluster.local",
  6. "User-Agent": "curl/7.55.0",
  7. "X-B3-Sampled": "0",
  8. "X-B3-Spanid": "5b68b3f953945a08",
  9. "X-B3-Traceid": "0847ba2513aa0ffc5b68b3f953945a08",
  10. "X-Envoy-Decorator-Operation": "my-httpbin.default.svc.cluster.local:80/*",
  11. "X-Istio-Attributes": "CigKGGRlc3RpbmF0aW9uLnNlcnZpY2UubmFtZRIMEgpteS1odHRwYmluCioKHWRlc3RpbmF0aW9uLnNlcnZpY2UubmFtZXNwYWNlEgkSB2RlZmF1bHQKOwoKc291cmNlLnVpZBItEitrdWJlcm5ldGVzOi8vc2xlZXAtNjZjOGQ3OWZmNS04aG1neC5kZWZhdWx0CkAKF2Rlc3RpbmF0aW9uLnNlcnZpY2UudWlkEiUSI2lzdGlvOi8vZGVmYXVsdC9zZXJ2aWNlcy9teS1odHRwYmluCkIKGGRlc3RpbmF0aW9uLnNlcnZpY2UuaG9zdBImEiRteS1odHRwYmluLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWw="
  12. }
  13. }

Cleanup of Kubernetes ExternalName service

  1. $ kubectl delete destinationrule my-httpbin
  2. $ kubectl delete service my-httpbin

Use a Kubernetes service with endpoints to access an external service

  • Create a Kubernetes service without selector for Wikipedia:
  1. $ kubectl apply -f - <<EOF
  2. kind: Service
  3. apiVersion: v1
  4. metadata:
  5. name: my-wikipedia
  6. spec:
  7. ports:
  8. - protocol: TCP
  9. port: 443
  10. name: tls
  11. EOF
  1. $ kubectl apply -f - <<EOF
  2. kind: Endpoints
  3. apiVersion: v1
  4. metadata:
  5. name: my-wikipedia
  6. subsets:
  7. - addresses:
  8. - ip: 91.198.174.192
  9. - ip: 198.35.26.96
  10. ports:
  11. - port: 443
  12. name: tls
  13. EOF
  • Observe your service. Note that it has a cluster IP which you can use to access wikipedia.org.
  1. $ kubectl get svc my-wikipedia
  2. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  3. 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 of curl to access wikipedia.org by the cluster IP:
  1. $ kubectl exec -it $SOURCE_POD_WITHOUT_ISTIO -n without-istio -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>"
  2. <title>Wikipedia, the free encyclopedia</title>
  • 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:
  1. $ kubectl apply -f - <<EOF
  2. apiVersion: networking.istio.io/v1alpha3
  3. kind: DestinationRule
  4. metadata:
  5. name: my-wikipedia
  6. spec:
  7. host: my-wikipedia.default.svc.cluster.local
  8. trafficPolicy:
  9. tls:
  10. mode: DISABLE
  11. EOF
  • Access wikipedia.org by your Kubernetes service’s cluster IP from the source pod with Istio sidecar:
  1. $ 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>"
  2. <title>Wikipedia, the free encyclopedia</title>
  • Check that the access is indeed performed by the cluster IP. Notice the sentenceConnected to en.wikipedia.org (172.21.156.230) in the output of curl -v, it mentions the IP that was printedin the output of your service as the cluster IP.
  1. $ 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
  2. * Added en.wikipedia.org:443:172.21.156.230 to DNS cache
  3. * Hostname en.wikipedia.org was found in DNS cache
  4. * Trying 172.21.156.230...
  5. * TCP_NODELAY set
  6. * Connected to en.wikipedia.org (172.21.156.230) port 443 (#0)
  7. ...

Cleanup of Kubernetes service with endpoints

  1. $ kubectl delete destinationrule my-wikipedia
  2. $ kubectl delete endpoints my-wikipedia
  3. $ kubectl delete service my-wikipedia

Cleanup

  • Shutdown the sleep service:

Zip

  1. $ kubectl delete -f @samples/sleep/sleep.yaml@
  • Shutdown the sleep service in the without-istio namespace:

Zip

  1. $ kubectl delete -f @samples/sleep/sleep.yaml@ -n without-istio
  • Delete without-istio namespace:
  1. $ kubectl delete namespace without-istio
  • Unset the environment variables:
  1. $ unset SOURCE_POD SOURCE_POD_WITHOUT_ISTIO

See also

Secure Control of Egress Traffic in Istio, part 3

Comparison of alternative solutions to control egress traffic including performance considerations.

Secure Control of Egress Traffic in Istio, part 2

Use Istio Egress Traffic Control to prevent attacks involving egress traffic.

Secure Control of Egress Traffic in Istio, part 1

Attacks involving egress traffic and requirements for egress traffic control.

Egress Gateway Performance Investigation

Verifies the performance impact of adding an egress gateway.

Consuming External MongoDB Services

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.