TCP Traffic

    Before you begin this task, do the following:

    • Read the .

    • Install Istio using the Istio installation guide.

    • Deploy two workloads named and tcp-echo together in a namespace, for example foo. Both workloads run with an Envoy proxy in front of each. The tcp-echo workload listens on port 9000, 9001 and 9002 and echoes back any traffic it received with a prefix hello. For example, if you send “world” to tcp-echo, it will reply with hello world. The tcp-echo Kubernetes service object only declares the ports 9000 and 9001, and omits the port 9002. A pass-through filter chain will handle port 9002 traffic. Deploy the example namespace and workloads using the following command:

      Zip

      1. $ kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- sh -c 'echo "port 9000" | nc tcp-echo 9000' | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
      2. hello port 9000
      3. connection succeeded
      1. $ kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- sh -c 'echo "port 9001" | nc tcp-echo 9001' | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
      2. hello port 9001
      3. connection succeeded
    • Verify that sleep successfully communicates with tcp-echo on port 9002. You need to send the traffic directly to the pod IP of tcp-echo because the port 9002 is not defined in the Kubernetes service object of tcp-echo. Get the pod IP address and send the request with the following command:

      1. $ TCP_ECHO_IP=$(kubectl get pod "$(kubectl get pod -l app=tcp-echo -n foo -o jsonpath={.items..metadata.name})" -n foo -o jsonpath="{.status.podIP}")
      2. $ kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- sh -c "echo \"port 9002\" | nc $TCP_ECHO_IP 9002" | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
      3. hello port 9002
      4. connection succeeded

    If you don’t see the expected output, retry after a few seconds. Caching and propagation can cause a delay.

    1. Create the tcp-policy authorization policy for the tcp-echo workload in the foo namespace. Run the following command to apply the policy to allow requests to port 9000 and 9001:

      1. $ kubectl apply -f - <<EOF
      2. apiVersion: security.istio.io/v1beta1
      3. kind: AuthorizationPolicy
      4. metadata:
      5. name: tcp-policy
      6. spec:
      7. selector:
      8. matchLabels:
      9. app: tcp-echo
      10. action: ALLOW
      11. - to:
      12. - operation:
      13. ports: ["9000", "9001"]
      14. EOF
    2. Verify that requests to port 9000 are allowed using the following command:

    3. Verify that requests to port 9001 are allowed using the following command:

      1. $ kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- sh -c 'echo "port 9001" | nc tcp-echo 9001' | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
      2. hello port 9001
      3. connection succeeded
      1. $ kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- sh -c "echo \"port 9002\" | nc $TCP_ECHO_IP 9002" | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
      2. connection rejected
    4. Update the policy to add an HTTP-only field named methods for port 9000 using the following command:

      1. $ kubectl apply -f - <<EOF
      2. apiVersion: security.istio.io/v1beta1
      3. kind: AuthorizationPolicy
      4. metadata:
      5. name: tcp-policy
      6. namespace: foo
      7. spec:
      8. selector:
      9. matchLabels:
      10. app: tcp-echo
      11. action: ALLOW
      12. rules:
      13. - to:
      14. - operation:
      15. ports: ["9000"]
      16. EOF
    5. Verify that requests to port 9001 are denied. This occurs because the requests do not match any ALLOW rules. Run the following command and verify the output:

    6. Update the policy to a DENY policy using the following command:

      1. $ kubectl apply -f - <<EOF
      2. apiVersion: security.istio.io/v1beta1
      3. kind: AuthorizationPolicy
      4. metadata:
      5. name: tcp-policy
      6. namespace: foo
      7. spec:
      8. selector:
      9. matchLabels:
      10. app: tcp-echo
      11. action: DENY
      12. rules:
      13. - to:
      14. - operation:
      15. methods: ["GET"]
      16. ports: ["9000"]
      17. EOF
    7. Verify that requests to port 9000 are denied. This occurs because Istio ignores the HTTP-only fields in an invalid DENY rule. This is different from an invalid ALLOW rule, which causes Istio to ignore the entire rule. The final result is that only the ports field is used by Istio and the requests are denied because they match with the ports:

      1. $ kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- sh -c 'echo "port 9000" | nc tcp-echo 9000' | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
      2. connection rejected
      1. $ kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- sh -c 'echo "port 9001" | nc tcp-echo 9001' | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
      2. hello port 9001
      3. connection succeeded
    1. Remove the namespace foo:

      1. $ kubectl delete namespace foo