TCP 트래픽

TCP 트래픽 (TCP Traffic)

이 작업은 Istio 메시에서 TCP 트래픽에 대한 접근 제어를 설정하는 Istio 인가 정책을 다뤄요. ALLOW와 DENY 정책이 TCP 워크로드에 어떻게 적용되는지 예시로 배워요.

출처: Istio 문서

본문

이 작업은 Istio 메시에서 TCP 트래픽에 대한 Istio 인가 정책을 설정하는 방법을 보여드려요.

시작하기 전에 (Before you begin)

이 작업을 시작하기 전에 다음을 수행하세요.

  • Istio 인가 개념을 읽으세요.
  • Istio 설치 가이드를 사용해서 Istio를 설치하세요.
  • foo 같은 네임스페이스에 curl과 tcp-echo라는 두 워크로드를 함께 배포하세요. 두 워크로드 모두 앞에 Envoy 프록시가 있어요. tcp-echo 워크로드는 포트 9000, 9001, 9002에서 수신하고 hello 접두어와 함께 받은 트래픽을 그대로 에코백해요. 예를 들어 tcp-echo에 "world"를 보내면 hello world로 응답해요. tcp-echo Kubernetes 서비스 객체는 포트 9000과 9001만 선언하고 포트 9002는 생략해요. 패스스루 필터 체인이 포트 9002 트래픽을 처리할 거예요. 다음 명령으로 예시 네임스페이스와 워크로드를 배포하세요.
$ kubectl create ns foo
$ kubectl apply -f <(istioctl kube-inject -f @samples/tcp-echo/tcp-echo.yaml@) -n foo
$ kubectl apply -f <(istioctl kube-inject -f @samples/curl/curl.yaml@) -n foo
  • 다음 명령으로 curl이 포트 9000과 9001에서 tcp-echo와 성공적으로 통신하는지 확인하세요.
$ kubectl exec "$(kubectl get pod -l app=curl -n foo -o jsonpath={.items..metadata.name})" \
    -c curl -n foo -- sh -c \
    'echo "port 9000" | nc tcp-echo 9000' | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
hello port 9000
connection succeeded
$ kubectl exec "$(kubectl get pod -l app=curl -n foo -o jsonpath={.items..metadata.name})" \
    -c curl -n foo -- sh -c \
    'echo "port 9001" | nc tcp-echo 9001' | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
hello port 9001
connection succeeded
  • 포트 9002에서 curl이 tcp-echo와 성공적으로 통신하는지 확인하세요. 포트 9002는 tcp-echo의 Kubernetes 서비스 객체에 정의되어 있지 않으므로 tcp-echo의 파드 IP로 직접 트래픽을 보내야 해요. 파드 IP 주소를 가져와 다음 명령으로 요청을 보내세요.
$ 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}")
$ kubectl exec "$(kubectl get pod -l app=curl -n foo -o jsonpath={.items..metadata.name})" \
    -c curl -n foo -- sh -c \
    "echo \"port 9002\" | nc $TCP_ECHO_IP 9002" | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
hello port 9002
connection succeeded

[!note] 예상 출력이 안 보이면 몇 초 후에 다시 시도하세요. 캐싱과 전파로 인해 지연이 발생할 수 있어요.

TCP 워크로드에 ALLOW 인가 정책 구성하기

  1. foo 네임스페이스의 tcp-echo 워크로드에 대한 tcp-policy 인가 정책을 만드세요. 포트 9000과 9001에 대한 요청을 허용하는 정책을 적용하려면 다음 명령을 실행하세요.
$ kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: tcp-policy
  namespace: foo
spec:
  selector:
    matchLabels:
      app: tcp-echo
  action: ALLOW
  rules:
  - to:
    - operation:
        ports: ["9000", "9001"]
EOF
  1. 포트 9000에 대한 요청이 허용되는지 다음 명령으로 확인하세요.
$ kubectl exec "$(kubectl get pod -l app=curl -n foo -o jsonpath={.items..metadata.name})" \
    -c curl -n foo -- sh -c \
    'echo "port 9000" | nc tcp-echo 9000' | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
hello port 9000
connection succeeded
  1. 포트 9001에 대한 요청이 허용되는지 다음 명령으로 확인하세요.
$ kubectl exec "$(kubectl get pod -l app=curl -n foo -o jsonpath={.items..metadata.name})" \
    -c curl -n foo -- sh -c \
    'echo "port 9001" | nc tcp-echo 9001' | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
hello port 9001
connection succeeded
  1. 포트 9002에 대한 요청이 거부되는지 확인하세요. 포트가 tcp-echo Kubernetes 서비스 객체에 명시적으로 선언되지 않았더라도, 인가 정책은 패스스루 필터 체인에도 적용되므로 거부돼요. 다음 명령을 실행하고 출력을 확인하세요.
$ kubectl exec "$(kubectl get pod -l app=curl -n foo -o jsonpath={.items..metadata.name})" \
    -c curl -n foo -- sh -c \
    "echo \"port 9002\" | nc $TCP_ECHO_IP 9002" | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
connection rejected
  1. 포트 9000에 methods라는 HTTP 전용 필드를 추가하도록 정책을 업데이트하세요.
$ kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: tcp-policy
  namespace: foo
spec:
  selector:
    matchLabels:
      app: tcp-echo
  action: ALLOW
  rules:
  - to:
    - operation:
        methods: ["GET"]
        ports: ["9000"]
EOF
  1. 포트 9000에 대한 요청이 거부되는지 확인하세요. 이는 규칙이 TCP 트래픽에 HTTP 전용 필드(methods)를 사용하면 무효가 되기 때문이에요. Istio는 무효한 ALLOW 규칙을 무시해요. 최종 결과는 요청이 어떤 ALLOW 규칙과도 일치하지 않으므로 거부되는 거예요. 다음 명령을 실행하고 출력을 확인하세요.
$ kubectl exec "$(kubectl get pod -l app=curl -n foo -o jsonpath={.items..metadata.name})" \
    -c curl -n foo -- sh -c \
    'echo "port 9000" | nc tcp-echo 9000' | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
connection rejected
  1. 포트 9001에 대한 요청이 거부되는지 확인하세요. 이는 요청이 어떤 ALLOW 규칙과도 일치하지 않기 때문이에요. 다음 명령을 실행하고 출력을 확인하세요.
$ kubectl exec "$(kubectl get pod -l app=curl -n foo -o jsonpath={.items..metadata.name})" \
    -c curl -n foo -- sh -c \
    'echo "port 9001" | nc tcp-echo 9001' | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
connection rejected

TCP 워크로드에 DENY 인가 정책 구성하기

  1. HTTP 전용 필드가 있는 DENY 정책을 다음 명령으로 추가하세요.
$ kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: tcp-policy
  namespace: foo
spec:
  selector:
    matchLabels:
      app: tcp-echo
  action: DENY
  rules:
  - to:
    - operation:
        methods: ["GET"]
EOF
  1. 포트 9000에 대한 요청이 거부되는지 확인하세요. 이는 Istio가 tcp 포트에 대한 DENY 규칙을 만들 때 HTTP 전용 필드를 이해하지 못하고, 그 제한적인 특성 때문에 tcp 포트로의 모든 트래픽을 거부하기 때문이에요.
$ kubectl exec "$(kubectl get pod -l app=curl -n foo -o jsonpath={.items..metadata.name})" \
    -c curl -n foo -- sh -c \
    'echo "port 9000" | nc tcp-echo 9000' | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
connection rejected
  1. 포트 9001에 대한 요청이 거부되는지 확인하세요. 위와 같은 이유예요.
$ kubectl exec "$(kubectl get pod -l app=curl -n foo -o jsonpath={.items..metadata.name})" \
    -c curl -n foo -- sh -c \
    'echo "port 9001" | nc tcp-echo 9001' | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
connection rejected
  1. TCP와 HTTP 필드가 모두 있는 DENY 정책을 다음 명령으로 추가하세요.
$ kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: tcp-policy
  namespace: foo
spec:
  selector:
    matchLabels:
      app: tcp-echo
  action: DENY
  rules:
  - to:
    - operation:
        methods: ["GET"]
        ports: ["9000"]
EOF
  1. 포트 9000에 대한 요청이 거부되는지 확인하세요. 이는 요청이 위 DENY 정책의 ports와 일치하기 때문이에요.
$ kubectl exec "$(kubectl get pod -l app=curl -n foo -o jsonpath={.items..metadata.name})" \
    -c curl -n foo -- sh -c \
    'echo "port 9000" | nc tcp-echo 9000' | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
connection rejected
  1. 포트 9001에 대한 요청이 허용되는지 확인하세요. 이는 요청이 DENY 정책의 ports와 일치하지 않기 때문이에요.
$ kubectl exec "$(kubectl get pod -l app=curl -n foo -o jsonpath={.items..metadata.name})" \
    -c curl -n foo -- sh -c \
    'echo "port 9001" | nc tcp-echo 9001' | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
hello port 9001
connection succeeded

정리 (Clean up)

네임스페이스 foo를 제거하세요.

$ kubectl delete namespace foo

더 알아보기 (Learn more)

  • TCP 트래픽에 대한 인가 정책 세부 동작은 인가 개념 문서를 참고하세요.
  • ALLOW/DENY 규칙의 우선순위에 대해서는 인가 정책 개요를 참고하세요.