TCP 流量

该任务向您展示了在 Istio 网格中如何为 TCP 流量设置 Istio 授权策略。

开始之前

在您开始之前,请先完成以下内容:

  • 阅读 Istio 授权概念

  • 根据 Istio 安装指南安装 Istio。

  • 在命名空间例如 foo 中部署两个工作负载:curltcp-echo。 这两个工作负载每个前面都会运行一个 Envoy 代理。 tcp-echo 工作负载会监听 9000、9001 和 9002 端口,并以 hello 为前缀输出它收到的所有流量。 例如,如果您发送 worldtcp-echo,那么它将会回复 hello worldtcp-echo 的 Kubernetes Service 对象只声明了 9000 和 9001 端口,并省略了 9002 端口。 透传过滤器链将处理 9002 端口的流量。使用以下命令部署示例命名空间和工作负载:

    ZipZip

    1. $ kubectl create ns foo
    2. $ kubectl apply -f <(istioctl kube-inject -f @samples/tcp-echo/tcp-echo.yaml@) -n foo
    3. $ kubectl apply -f <(istioctl kube-inject -f @samples/curl/curl.yaml@) -n foo
  • 使用以下命令验证 curl 可以成功与 tcp-echo 的 9000 和 9001 端口通信:

    1. $ kubectl exec "$(kubectl get pod -l app=curl -n foo -o jsonpath={.items..metadata.name})" \
    2. -c curl -n foo -- sh -c \
    3. 'echo "port 9000" | nc tcp-echo 9000' | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
    4. hello port 9000
    5. connection succeeded
    1. $ kubectl exec "$(kubectl get pod -l app=curl -n foo -o jsonpath={.items..metadata.name})" \
    2. -c curl -n foo -- sh -c \
    3. 'echo "port 9001" | nc tcp-echo 9001' | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
    4. hello port 9001
    5. connection succeeded
  • 确认 curl 可以成功与 tcp-echo 的 9002 端口通信。 您需要将流量直接发送到 tcp-echo 的 Pod IP,因为在 tcp-echo 的 Kubernetes Service 对象中未定义端口 9002。 获取 Pod IP 地址,并使用以下命令发送请求:

    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=curl -n foo -o jsonpath={.items..metadata.name})" \
    3. -c curl -n foo -- sh -c \
    4. "echo \"port 9002\" | nc $TCP_ECHO_IP 9002" | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
    5. hello port 9002
    6. connection succeeded

如果看不到预期的输出,请在几秒钟后重试,因为缓存和其他传播开销可能会导致有些延迟。

为 TCP 工作负载配置 ALLOW 授权策略

  1. foo 命名空间中为 tcp-echo 工作负载创建 tcp-policy 授权策略。 运行以下命令来应用策略以允许请求到 9000 和 9001 端口:

    1. $ kubectl apply -f - <<EOF
    2. apiVersion: security.istio.io/v1
    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", "9001"]
    16. EOF
  2. 使用以下命令验证是否允许请求 9000 端口:

    1. $ kubectl exec "$(kubectl get pod -l app=curl -n foo -o jsonpath={.items..metadata.name})" \
    2. -c curl -n foo -- sh -c \
    3. 'echo "port 9000" | nc tcp-echo 9000' | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
    4. hello port 9000
    5. connection succeeded
  3. 使用以下命令验证是否允许请求 9001 端口:

    1. $ kubectl exec "$(kubectl get pod -l app=curl -n foo -o jsonpath={.items..metadata.name})" \
    2. -c curl -n foo -- sh -c \
    3. 'echo "port 9001" | nc tcp-echo 9001' | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
    4. hello port 9001
    5. connection succeeded
  4. 验证对 9002 端口的请求是否被拒绝。即使未在 tcp-echo Kubernetes Service 对象中显式声明的端口, 授权策略也会将其应用于透传过滤器链。运行以下命令并验证输出:

    1. $ kubectl exec "$(kubectl get pod -l app=curl -n foo -o jsonpath={.items..metadata.name})" \
    2. -c curl -n foo -- sh -c \
    3. "echo \"port 9002\" | nc $TCP_ECHO_IP 9002" | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
    4. connection rejected
  5. 使用以下命令为 9000 端口添加一个名为 methods 的 HTTP-only 字段来更新策略:

    1. $ kubectl apply -f - <<EOF
    2. apiVersion: security.istio.io/v1
    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. methods: ["GET"]
    16. ports: ["9000"]
    17. EOF
  6. 验证对 9000 端口的请求是否被拒绝。发生这种情况是因为该规则在对 TCP 流量使用了 HTTP-only 字段(methods), 这会导致规则无效。Istio 会忽略无效的 ALLOW 规则。最终结果是该请求被拒绝,因为它与任何 ALLOW 规则都不匹配。 运行以下命令并验证输出:

    1. $ kubectl exec "$(kubectl get pod -l app=curl -n foo -o jsonpath={.items..metadata.name})" \
    2. -c curl -n foo -- sh -c \
    3. 'echo "port 9000" | nc tcp-echo 9000' | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
    4. connection rejected
  7. 验证对 9001 端口的请求是否被拒绝。发生这种情况是因为请求与任何 ALLOW 规则都不匹配。运行以下命令并验证输出:

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

为 TCP 工作负载配置 DENY 授权策略

  1. 使用以下命令添加具有 HTTP-only 字段的 DENY 策略:

    1. $ kubectl apply -f - <<EOF
    2. apiVersion: security.istio.io/v1
    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. EOF
  2. 验证到 9000 端口的请求是否被拒绝。发生这种情况是因为 Istio 在为 tcp 端口创建 DENY 规则时不理解 HTTP-only 字段,并且由于这个规则的限制性质,将拒绝所有到 tcp 端口的流量:

    1. $ kubectl exec "$(kubectl get pod -l app=curl -n foo -o jsonpath={.items..metadata.name})" \
    2. -c curl -n foo -- sh -c \
    3. 'echo "port 9000" | nc tcp-echo 9000' | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
    4. connection rejected
  3. 验证到 9001 端口的请求是否被拒绝。原因同上。

    1. $ kubectl exec "$(kubectl get pod -l app=curl -n foo -o jsonpath={.items..metadata.name})" \
    2. -c curl -n foo -- sh -c \
    3. 'echo "port 9001" | nc tcp-echo 9001' | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
    4. connection rejected
  4. 使用以下命令添加同时具有 TCP 和 HTTP 字段的 DENY 策略:

    1. $ kubectl apply -f - <<EOF
    2. apiVersion: security.istio.io/v1
    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
  5. 验证对 9000 端口的请求是否被拒绝。发生这种情况是因为此类请求与上述 DENY 策略中的 ports 匹配:

    1. $ kubectl exec "$(kubectl get pod -l app=curl -n foo -o jsonpath={.items..metadata.name})" \
    2. -c curl -n foo -- sh -c \
    3. 'echo "port 9000" | nc tcp-echo 9000' | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
    4. connection rejected
  6. 验证是否允许对 9001 端口的请求。发生这种情况是因为请求与 DENY 策略中的 ports 不匹配:

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

清理

删除 foo 命名空间:

  1. $ kubectl delete namespace foo