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’s . The external services are not part of an Istio service mesh so they cannot perform the mutual TLS of Istio. You must set the TLS mode according to the TLS requirements of the external service and according to the way your workload accesses the external service. If your workload issues plain HTTP requests and the external service requires TLS, you may want to perform TLS origination by Istio. If your workload already uses TLS, the traffic is already encrypted and you can just disable Istio’s mutual TLS.

    This page describes how Istio can integrate with existing Kubernetes configurations. For new deployments, we recommend following Accessing Egress Services.

    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 .

      The egress gateway and access logging will be enabled if you install the demo configuration profile.

    • Deploy the sample app to use as a test source for sending requests. If you have automatic sidecar injection enabled, run the following command to deploy the sample app:

      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.

      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 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 source pod:

      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
    1. Create a Kubernetes service for httpbin.org in the default namespace:

      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
    2. Observe your service. Note that it does not have a cluster IP.

    3. Access httpbin.org via the Kubernetes service’s hostname from the source pod without Istio sidecar. Note that the curl command below uses the Kubernetes DNS format for services: <service name>.<namespace>.svc.cluster.local.

      1. $ kubectl exec "$SOURCE_POD_WITHOUT_ISTIO" -n without-istio -c sleep -- curl -sS 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. }
    4. Access httpbin.org via the Kubernetes service’s hostname from the source pod with Istio sidecar. Notice the headers added by Istio sidecar, for example X-Envoy-Decorator-Operation. Also note that the Host header equals to your service’s hostname.

      1. $ kubectl exec "$SOURCE_POD" -c sleep -- curl -sS my-httpbin.default.svc.cluster.local/headers
      2. {
      3. "headers": {
      4. "Accept": "*/*",
      5. "Content-Length": "0",
      6. "Host": "my-httpbin.default.svc.cluster.local",
      7. "User-Agent": "curl/7.64.0",
      8. "X-B3-Sampled": "0",
      9. "X-B3-Spanid": "5795fab599dca0b8",
      10. "X-B3-Traceid": "5079ad3a4af418915795fab599dca0b8",
      11. "X-Envoy-Decorator-Operation": "my-httpbin.default.svc.cluster.local:80/*",
      12. "X-Envoy-Peer-Metadata": "...",
      13. "X-Envoy-Peer-Metadata-Id": "sidecar~10.28.1.74~sleep-6bdb595bcb-drr45.default~default.svc.cluster.local"
      14. }
      15. }
    1. $ kubectl delete destinationrule my-httpbin
    2. $ kubectl delete service my-httpbin
      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. Create endpoints for your service. Pick a couple of IPs from the .

      1. $ kubectl apply -f - <<EOF
      2. kind: Endpoints
      3. apiVersion: v1
      4. name: my-wikipedia
      5. subsets:
      6. - addresses:
      7. - ip: 91.198.174.192
      8. ports:
      9. - port: 443
      10. name: tls
      11. EOF
    2. 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
    3. Send HTTPS requests to wikipedia.org by your Kubernetes service’s cluster IP from the source pod without Istio sidecar. Use the --resolve option of curl to access wikipedia.org by the cluster IP:

    4. In this case, the workload send HTTPS requests (open TLS connection) to the wikipedia.org. The traffic is already encrypted 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
    5. Access wikipedia.org by your Kubernetes service’s cluster IP from the source pod with Istio sidecar:

      1. $ kubectl exec "$SOURCE_POD" -c sleep -- curl -sS --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>
    6. 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 of curl -v, it mentions the IP that was printed in the output of your service as the cluster IP.

      1. $ kubectl exec "$SOURCE_POD" -c sleep -- curl -sS -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
    1. Shutdown the sleep service:

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

      1. $ kubectl delete -f @samples/sleep/sleep.yaml@ -n without-istio
      1. Unset the environment variables: