Kubernetes에서 투명 프록시(transparent proxy) 모드 활성화

Kubernetes에서 투명 프록시(transparent proxy) 모드 활성화

서비스 메시에서 투명 프록시 모드를 사용하는 방법을 설명해 드릴게요. 투명 프록시는 애플리케이션이 구성 변경 없이 서비스 메시를 통해 통신할 수 있게 해주고, 메시를 우회하는 직접 인바운드 연결을 차단하여 애플리케이션 보안을 강화해요.

출처: 문서

본문

이 문서에서는 서비스 메시에서 투명 프록시 모드를 사용하는 방법을 설명해요. 투명 프록시는 애플리케이션이 구성을 수정하지 않고 서비스 메시를 통해 통신할 수 있게 해줘요. 또한 메시를 우회하는 직접 인바운드 연결을 차단하여 애플리케이션 보안을 강화해요. 자세한 내용은 투명 프록시 개요를 참고해 주세요.

요구 사항

투명 프록시를 사용하려면 네트워크가 다음 환경 및 소프트웨어 요구 사항을 충족해야 해요.

  • 투명 프록시는 Kubernetes 환경에서 사용할 수 있어요.

  • Consul 1.10.0 이상

  • Consul Helm chart 0.32.0 이상. Consul CNI 플러그인을 사용하여 트래픽을 리다이렉트하려면 Helm chart 0.48.0 이상이 필요해요. 자세한 내용은 Consul CNI 플러그인 활성화를 참고해 주세요.

  • Consul이 업스트림 연결을 추론하고 사이드카 프록시를 사용하여 메시지를 적절히 라우팅할 수 있도록 의도된 서비스 간 통신을 명시적으로 허용하는 서비스 의도(intentions)를 만들어야 해요.

  • Kubernetes 클러스터 내 모든 워커 노드에서 ip_tables 커널 모듈이 실행되고 있어야 해요. 예를 들어 modprobe Linux 유틸리티를 사용한다면 다음 명령을 실행해 주세요:

$ modprobe ip_tables

지원 버전으로 업그레이드: 지원되는 버전의 Consul, Kubernetes용 Consul(consul-k8s), Consul Helm chart로 업그레이드할 때는 항상 올바른 업그레이드 경로를 따라 주세요.

투명 프록시 활성화

Consul Helm chart를 사용하여 Kubernetes에 Consul을 설치하면 기본적으로 전체 클러스터에 대해 투명 프록시 모드가 활성화돼요. 모든 기본 구성에 대한 정보는 Consul Helm chart 참조를 참고해 주세요.

전체 클러스터, 개별 네임스페이스, 개별 서비스에 대해 투명 프록시를 명시적으로 활성화할 수 있어요.

전체 클러스터

connectInject.transparentProxy.defaultEnabled Helm 값을 사용하여 전체 클러스터에 대해 투명 프록시를 활성화 또는 비활성화해요:

connectInject:
  transparentProxy:
    defaultEnabled: true

Kubernetes 네임스페이스

Kubernetes 네임스페이스에 대해 투명 프록시를 활성화하려면 consul.hashicorp.com/transparent-proxy=true 레이블을 적용해요. 이 레이블은 connectInject.transparentProxy.defaultEnabled Helm 값을 재정의하고 네임스페이스의 Pod 기본 동작을 정의해요. 다음 예시는 my-app 네임스페이스의 Pod에 대해 투명 프록시를 활성화해요:

$ kubectl label namespaces my-app "consul.hashicorp.com/transparent-proxy=true"

개별 서비스

각 서비스의 Pod에 투명 프록시를 활성화하려면 consul.hashicorp.com/transparent-proxy=true 어노테이션을 적용해요. 이 어노테이션은 Helm 값과 네임스페이스 레이블을 재정의해요. 다음 예시는 static-server 서비스에 대해 투명 프록시를 활성화해요:

apiVersion: v1
kind: Service
metadata:
  name: static-server
spec:
  selector:
    app: static-server
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: static-server
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: static-server
spec:
  replicas: 1
  selector:
    matchLabels:
      app: static-server
  template:
    metadata:
      name: static-server
      labels:
        app: static-server
      annotations:
        'consul.hashicorp.com/connect-inject': 'true'
        'consul.hashicorp.com/transparent-proxy': 'true'
    spec:
      containers:
        - name: static-server
          image: hashicorp/http-echo:latest
          args:
            - -text="hello world"
            - -listen=:8080
          ports:
            - containerPort: 8080
              name: http
      serviceAccountName: static-server

투명 프록시와 다중 포트 서비스

투명 프록시 모드는 다중 포트 서비스를 지원해요. 다중 포트 통신을 활성화하기 위해 다운스트림 또는 업스트림 서비스 배포를 수정할 필요는 없어요. 서비스 메시를 통한 다중 포트 통신을 활성화하려면 서비스 의도와 파티션 간 통신을 위한 내보낸 서비스 같은 필요한 구성 엔트리를 구성해 주세요.

메시의 애플리케이션은 가상 주소 형식 <port-name>.<service>.virtual.consul을 사용하여 다중 포트 업스트림 서비스의 특정 포트를 지정할 수 있어요.

프로토콜 제한: Consul은 다중 포트 서비스에 대해 프로토콜 조합을 지원하지 않아요. 서비스의 모든 포트는 동일한 프로토콜을 사용해야 해요.

Consul CNI 플러그인 활성화

기본적으로 Consul은 Kubernetes Pod 시작 프로세스의 일부로 connect-inject init 컨테이너를 생성해요. 이 컨테이너는 사이드카 프록시를 통해 서비스 메시에서 트래픽 리다이렉션을 구성해요. 리다이렉션을 구성하려면 컨테이너에 상승된 CAP_NET_ADMIN 권한이 필요한데, 이는 조직의 보안 정책과 호환되지 않을 수 있어요.

대신 트래픽 리다이렉션을 수행하도록 Consul container network interface(CNI) 플러그인을 활성화할 수 있어요. 이 플러그인은 Kubernetes kubelet에 의해 실행되므로 네트워크를 구성하는 데 필요한 상승된 권한을 이미 갖고 있어요. 또한 플러그인이 활성화되면 Kubernetes HTTP 헬스 프로브를 자동으로 덮어쓰는 어노테이션을 지정할 필요가 없어요(Kubernetes HTTP 헬스 프로브 덮어쓰기 참조).

Consul Helm chart는 CNI 플러그인을 설치하지만 기본적으로 비활성화돼 있어요. CNI 플러그인 활성화 지침은 Kubernetes에 Consul 설치 문서를 참고해 주세요.

트래픽 리다이렉션

사이드카 프록시를 통해 트래픽을 리다이렉트하는 메커니즘은 두 가지가 있어요. 기본적으로 Consul은 모든 인바운드 및 아웃바운드 트래픽을 리다이렉트하는 init 컨테이너를 주입해요. 기본 메커니즘은 트래픽을 서비스 메시로 리다이렉트하기 위해 상승된 권한(CAP_NET_ADMIN)을 요구해요.

또는 트래픽 리다이렉션을 처리하도록 Consul CNI 플러그인을 활성화할 수 있어요. Kubernetes kubelet이 CNI 플러그인을 실행하므로 Consul CNI 플러그인은 네트워크에 라우팅 테이블을 적용하는 데 필요한 권한을 갖고 있어요.

두 메커니즘 모두 모든 인바운드 및 아웃바운드 트래픽을 리다이렉트하지만, 특정 Pod 또는 Pod 그룹에 대한 예외를 구성할 수 있어요. 다음 어노테이션은 일부 트래픽이 사이드카 프록시로 리다이렉트되지 않도록 제외할 수 있게 해줘요.

인바운드 포트 제외

consul.hashicorp.com/transparent-proxy-exclude-inbound-ports 어노테이션은 투명 프록시 모드에서 실행할 때 트래픽 리다이렉션에서 제외할 인바운드 포트의 쉼표로 구분된 목록을 정의해요. 포트 번호는 문자열 데이터 값이에요. 다음 예시에서 포트 8200 및 8201의 pod 서비스는 투명 프록시를 통해 리다이렉트되지 않아요:

인바운드 포트 번호를 리다이렉션에서 제외

metadata:
  annotations:
    consul.hashicorp.com/transparent-proxy-exclude-inbound-ports: "8200, 8201"

아웃바운드 포트 제외

consul.hashicorp.com/transparent-proxy-exclude-outbound-ports 어노테이션은 투명 프록시 모드에서 실행할 때 트래픽 리다이렉션에서 제외할 아웃바운드 포트의 쉼표로 구분된 목록을 정의해요. 포트 번호는 문자열 데이터 값이에요. 다음 예시에서 포트 8200 및 8201의 pod 서비스는 투명 프록시를 통해 리다이렉트되지 않아요:

아웃바운드 포트 번호를 리다이렉션에서 제외

metadata:
  annotations":
    consul.hashicorp.com/transparent-proxy-exclude-outbound-ports: "8200, 8201"

아웃바운드 CIDR 블록 제외

consul.hashicorp.com/transparent-proxy-exclude-outbound-cidrs 어노테이션은 투명 프록시 모드에서 실행할 때 트래픽 리다이렉션에서 제외할 아웃바운드 CIDR 블록의 쉼표로 구분된 목록을 정의해요. CIDR 블록은 문자열 데이터 값이에요. 다음 예시에서 3.3.3.3/24 IP 범위의 서비스는 투명 프록시를 통해 리다이렉트되지 않아요:

아웃바운드 CIDR 블록을 리다이렉션에서 제외

metadata:
  annotations:
    consul.hashicorp.com/transparent-proxy-exclude-outbound-cidrs: "3.3.3.3,3.3.3.3/24"

사용자 ID 제외

consul.hashicorp.com/transparent-proxy-exclude-uids 어노테이션은 투명 프록시 모드에서 실행할 때 트래픽 리다이렉션에서 제외할 추가 사용자 ID의 쉼표로 구분된 목록을 정의해요. 사용자 ID는 문자열 데이터 값이에요. 다음 예시에서 ID 4444 및 44444의 서비스는 투명 프록시를 통해 리다이렉트되지 않아요:

사용자 ID를 리다이렉션에서 제외

metadata:
  annotations:
    consul.hashicorp.com/transparent-proxy-exclude-uids: "4444,44444"
  }
}

Kubernetes HTTP 헬스 프로브 구성

기본적으로 connect-inject는 비활성화돼 있어요. 결과적으로 Kubernetes의 Consul은 Kubernetes HTTP 헬스 프로브를 방해하는 트래픽 리다이렉션 메커니즘을 사용해요. 이는 프로브가 kubelet이 프로브의 엔드포인트에 있는 애플리케이션 컨테이너에 도달할 것을 기대하기 때문이에요. 대신 트래픽이 사이드카 프록시를 통해 리다이렉트돼요. 결과적으로 kubelet이 메시 프록시로 해당 트래픽을 암호화하지 않으므로 헬스 프로브가 오류를 반환해요.

이 문제를 해결하는 두 가지 방법이 있어요. 첫 번째 방법은 connectInject.transparentProxy.defaultOverwriteProbes 어노테이션을 설정하여 Kubernetes HTTP 헬스 프로브가 프록시를 가리키도록 덮어쓰는 거예요. 두 번째 방법은 트래픽 리다이렉션을 수행하도록 Consul container network interface(CNI) 플러그인을 활성화하는 거예요. 자세한 내용은 Kubernetes에 Consul 설치 지침을 참고해 주세요.

Kubernetes HTTP 헬스 프로브 덮어쓰기

헬스 프로브를 덮어쓰려면 connectInject.transparentProxy.defaultOverwriteProbes Helm 값을 명령에 포함하거나 consul.hashicorp.com/transparent-proxy-overwrite-probes Kubernetes 어노테이션을 pod 구성에 추가할 수 있어요.

자세한 내용은 Kubernetes의 Consul에서 Kubernetes 헬스 체크를 참고해 주세요.

Kubernetes 클러스터 간 서비스 다이얼

Consul 서버가 Kubernetes 클러스터 간에 연합되어 있다면 consul.hashicorp.com/connect-service-upstreams 어노테이션을 사용하여 한 Kubernetes 클러스터의 서비스가 다른 Kubernetes 클러스터의 데이터센터에 있는 서비스를 명시적으로 다이얼하도록 구성해야 해요. 다음 예시는 dc2 데이터센터의 my-service라는 업스트림 서비스를 포트 1234에서 다이얼하도록 서비스를 구성해요:

consul.hashicorp.com/connect-service-upstreams: "my-service:1234:dc2"

Consul 클러스터가 여러 Kubernetes 클러스터에 걸쳐 있는 단일 데이터센터에 배포된 경우 consul.hashicorp.com/connect-service-upstreams 어노테이션을 사용하여 한 Kubernetes 클러스터의 서비스가 다른 Kubernetes 클러스터의 서비스를 명시적으로 다이얼하도록 구성해야 해요. 다음 예시는 다른 Kubernetes 클러스터의 my-service라는 업스트림 서비스를 포트 1234에서 다이얼하도록 서비스를 구성해요:

consul.hashicorp.com/connect-service-upstreams: "my-service:1234"

Consul 클러스터가 피어링(peering) 연결로 연결되어 있다면 서비스가 업스트림 서비스를 명시적으로 다이얼하도록 구성할 필요는 없어요.

서비스 선택자(selector) 구성

투명 프록시가 활성화되면 KubeDNS 또는 Pod IP 주소로 전송된 트래픽이 프록시를 통해 리다이렉트돼요. 메시에서 Kubernetes Service를 정의할 때 선택자를 사용하여 Kubernetes Service를 Pod에 바인딩해야 해요. KubeDNS를 사용하려면 Kubernetes Service 이름이 Consul 서비스 이름과 일치해야 해요. 서비스 pod에 consul.hashicorp.com/connect-service Kubernetes 어노테이션을 적용하지 않은 한 이것이 기본 동작이에요. 이 어노테이션은 Consul 서비스 이름을 재정의해요.

Consul은 iptables 규칙을 사용하여 Kubernetes Service에 바인딩된 각 Pod에 대한 리다이렉션을 구성해요. 규칙은 모든 인바운드 및 아웃바운드 트래픽을 사이드카 프록시의 인바운드 및 아웃바운드 리스너를 통해 리다이렉트해요. Consul은 KubeDNS를 사용하여 업스트림 서비스를 지정하는 서비스 의도를 기반으로 적절한 업스트림 서비스로 트래픽을 라우팅하도록 프록시를 구성해요.

구성 엔트리를 사용하여 호출 경로를 정의할 때는 다운스트림 및 업스트림 서비스 모두에서 투명 프록시를 활성화해야 해요. 업스트림이 메시를 우회해야 한다면 구성 엔트리를 적용하지 마세요. 대신 투명 프록시에서 제외하거나 직접 다이얼링을 사용해 주세요.

다음 예시에서 Kubernetes 서비스는 sample-app 애플리케이션 Pod를 선택하여 메시 내에서 도달할 수 있게 해요.

예시 서비스 선택자

apiVersion: v1
kind: Service
metadata:
  name: sample-app
  namespace: default
spec:
  selector:
    app: sample-app
  ports:
    - protocol: TCP
      port: 80

추가 서비스는 sample-app.default.svc.cluster.local의 KubeDNS를 쿼리하여 sample-app에 도달할 수 있어요. ACL이 활성화되고 기본 deny 정책으로 구성된 경우, 구성은 sample-app과의 통신을 허용하려면 ServiceIntention도 필요해요.

sample-app.virtual.group-name.sg.consul에서 sameness group에 속하는 서비스에 대해 KubeDNS를 쿼리할 수 있어요. 이 구문은 장애 조치가 필요하고 sameness group CRD에서 spec.defaultForFailover가 false로 설정된 경우에 필요해요. 자세한 내용은 sameness group 구성 엔트리 참조를 참고해 주세요.

헤드리스 서비스

가상 클러스터 IP로 지정되지 않은 서비스의 경우 DialedDirectly 옵션을 사용하여 업스트림 서비스를 구성해야 해요. 그런 다음 DNS를 사용하여 개별 인스턴스 주소를 검색하고 투명 프록시를 통해 다이얼해요. 업스트림에서 이 모드를 활성화하면 서비스가 mTLS용 서비스 메시 인증서를 제시하고 대상에서 의도가 적용돼요.

개별 인스턴스를 다이얼할 때 Consul이 구성 엔트리로 구성된 HTTP 라우팅 규칙을 무시한다는 점에 주의해 주세요. 투명 프록시는 원래 대상 IP 주소에 대한 TCP 프록시 역할을 해요.

알려진 제한 사항

  • 여러 클러스터에 걸친 연합 또는 여러 클러스터에 걸친 단일 데이터센터가 있는 배포 구성은 어노테이션을 사용하여 다른 데이터센터 또는 클러스터의 서비스를 명시적으로 다이얼해야 해요.

  • 헤드리스 서비스 다이얼 시 요청은 일반 TCP 프록시를 사용하여 프록시 처리돼요. Consul은 업스트림의 프로토콜을 고려하지 않아요.

더 알아보기 (Learn more)