SNI 라우팅을 통한 프록시 지원

SNI 라우팅을 통한 프록시 지원

프록시 서버는 여러 클라이언트의 요청을 인터넷상의 다른 서버로 전달하는 중간 서버예요. Pulsar는 브로커 앞에 게이트웨이를 만들어 주는 리버스 프록시로 프록시를 활용하는데, 여기서 핵심이 되는 기술이 SNI 라우팅이에요. 이 글에서는 ATS(Apache Traffic Server)를 프록시로 구성하고 SNI 라우팅을 활성화해서 Pulsar 클라이언트가 브로커에 연결하는 방법을 살펴볼게요.

출처: 문서

본문

프록시 서버는 여러 클라이언트의 요청을 인터넷상의 서로 다른 서버로 전달하는 중간 서버예요. 프록시 서버는 정방향 및 역방향 프록시 시나리오 모두에서 "트래픽 조정자(traffic cop)" 역할을 하며, 로드 밸런싱, 성능, 보안, 자동 확장 등 시스템에 이점을 제공해요.

Pulsar의 프록시는 리버스 프록시 역할을 하며 브로커 앞에 게이트웨이를 만들어요. Apache Traffic Server (ATS), HAProxy, Nginx, Envoy 같은 프록시는 Pulsar에서 지원돼요. 이 프록시 서버들은 SNI 라우팅을 지원해요. SNI 라우팅은 SSL 연결을 종료하지 않고 트래픽을 대상으로 라우팅하는 데 사용돼요. 레이어 4 라우팅은 클라이언트 TCP 패킷의 대상 주소를 검사해 아웃바운드 연결을 결정하므로 더 큰 투명성을 제공해요.

Pulsar 클라이언트(Java, C++, Python)는 SNI 라우팅 프로토콜을 지원하므로 프록시를 통해 브로커에 연결할 수 있어요. 이 문서는 ATS 프록시를 설정하고 SNI 라우팅을 활성화한 뒤 ATS 프록시를 통해 Pulsar 클라이언트를 브로커에 연결하는 방법을 안내해요.

Pulsar에서의 ATS-SNI 라우팅

ATS로 레이어-4 SNI 라우팅을 지원하려면 인바운드 연결이 TLS 연결이어야 해요. Pulsar 클라이언트는 TLS 연결에서 SNI 라우팅 프로토콜을 지원하므로, Pulsar 클라이언트가 ATS 프록시를 통해 브로커에 연결할 때 Pulsar는 ATS를 리버스 프록시로 사용해요.

Pulsar는 지오레플리케이션을 위한 SNI 라우팅도 지원하므로, 브로커가 ATS 프록시를 통해 다른 클러스터의 브로커에 연결할 수 있어요.

이 섹션은 ATS를 리버스 프록시로 설정하고 사용하는 방법을 설명해요. 그러면 Pulsar 클라이언트가 TLS 연결의 SNI 라우팅 프로토콜을 사용해 ATS 프록시를 통해 브로커에 연결할 수 있어요.

레이어-4 SNI 라우팅용 ATS 프록시 설정

레이어 4 SNI 라우팅을 위한 ATS 프록시를 설정하려면 records.confssl_server_name.conf 파일을 구성해야 해요.

records.config 파일은 기본적으로 /usr/local/etc/trafficserver/ 디렉터리에 있어요. 이 파일은 ATS가 사용하는 구성 가능한 변수들을 나열해요.

records.config 파일을 구성하려면 다음 단계를 완료하세요.

  1. 프록시가 수신 대기하는 TLS 포트(http.server_ports)를 갱신하고, 프록시 인증서(ssl.client.cert.path와 ssl.client.cert.filename)를 갱신해 안전한 TLS 터널링을 확보해요.
  2. 브로커로 터널링하는 데 사용되는 서버 포트(http.connect_ports)를 구성해요. Pulsar 브로커가 4443과 6651 포트에서 수신 대기한다면, 브로커 서비스 포트를 http.connect_ports 구성에 추가해요.

다음은 그 예시예요.

# PROXY TLS PORT
CONFIG proxy.config.http.server_ports STRING 4443:ssl 4080
# PROXY CERTS FILE PATH
CONFIG proxy.config.ssl.client.cert.path STRING /proxy-cert.pem
# PROXY KEY FILE PATH
CONFIG proxy.config.ssl.client.cert.filename STRING /proxy-key.pem
# The range of origin server ports that can be used for tunneling via CONNECT. 
# Traffic Server allows tunnels only to the specified ports. Supports both wildcards (*) and ranges (e.g. 0-1023).
CONFIG proxy.config.http.connect_ports STRING 4443 6651

ssl_server_name 파일은 인바운드 및 아웃바운드 연결의 TLS 연결 처리를 구성하는 데 사용돼요. 구성은 인바운드 연결이 제공하는 SNI 값에 의해 결정돼요. 이 파일은 구성 항목 집합으로 구성되며, 각 항목은 SNI 값(fqdn)으로 식별돼요. 인바운드 TLS 연결이 만들어지면 TLS 협상의 SNI 값이 이 파일에 지정된 항목과 일치되는지 확인돼요. 값이 일치하면 해당 항목에 지정된 값이 기본값을 재정의해요.

다음 예시는 클라이언트에서 오는 인바운드 SNI 호스트명과 요청이 리다이렉트되어야 하는 실제 브로커 서비스 URL의 매핑을 보여줘요. 예를 들어 클라이언트가 SNI 헤더 pulsar-broker1을 보내면, 프록시는 요청을 pulsar-broker1:6651 서비스 URL로 리다이렉트해 TLS 터널을 만들어요.

server_config = {
  {
    fqdn = 'pulsar-broker-vip',
    # Forward to Pulsar broker which is listening on 6651
    tunnel_route = 'pulsar-broker-vip:6651'
  },
  {
    fqdn = 'pulsar-broker1',
    # Forward to Pulsar broker-1 which is listening on 6651
    tunnel_route = 'pulsar-broker1:6651'
  },
  {
    fqdn = 'pulsar-broker2',
    # Forward to Pulsar broker-2 which is listening on 6651
    tunnel_route = 'pulsar-broker2:6651'
  },
}

ssl_server_name.configrecords.config 파일을 구성한 후에는 ATS 프록시 서버가 SNI 라우팅을 처리하고 클라이언트와 브로커 사이에 TCP 터널을 만들어요.

SNI 라우팅으로 Pulsar 클라이언트 구성

ATS SNI 라우팅은 TLS에서만 동작해요. 먼저 ATS 프록시와 브로커에 대해 TLS를 활성화하고, SNI 라우팅 프로토콜을 구성한 다음, ATS 프록시를 통해 Pulsar 클라이언트를 브로커에 연결해야 해요. Pulsar 클라이언트는 프록시에 연결하고 대상 브로커 URL을 SNI 헤더로 보내 SNI 라우팅을 지원해요. 이 과정은 내부적으로 처리돼요. SNI 라우팅 프로토콜을 사용하기 위해 Pulsar 클라이언트를 만들 때 다음 프록시 구성만 처음에 설정하면 돼요.

String brokerServiceUrl = "pulsar+ssl://pulsar-broker-vip:6651/";
String proxyUrl = "pulsar+ssl://ats-proxy:443";
ClientBuilder clientBuilder = PulsarClient.builder()
		.serviceUrl(brokerServiceUrl)
        .tlsTrustCertsFilePath(TLS_TRUST_CERT_FILE_PATH)
        .enableTls(true)
        .allowTlsInsecureConnection(false)
        .proxyServiceUrl(proxyUrl, ProxyProtocol.SNI)
        .operationTimeout(1000, TimeUnit.MILLISECONDS);
Map<String, String> authParams = new HashMap();
authParams.put("tlsCertFile", TLS_CLIENT_CERT_FILE_PATH);
authParams.put("tlsKeyFile", TLS_CLIENT_KEY_FILE_PATH);
clientBuilder.authentication(AuthenticationTls.class.getName(), authParams);
PulsarClient pulsarClient = clientBuilder.build();
ClientConfiguration config = ClientConfiguration();
config.setUseTls(true);
config.setTlsTrustCertsFilePath("/path/to/cacert.pem");
config.setTlsAllowInsecureConnection(false);
config.setAuth(pulsar::AuthTls::create(
            "/path/to/client-cert.pem", "/path/to/client-key.pem");
);
Client client("pulsar+ssl://ats-proxy:443", config);
from pulsar import Client, AuthenticationTLS
auth = AuthenticationTLS("/path/to/my-role.cert.pem", "/path/to/my-role.key-pk8.pem")
client = Client("pulsar+ssl://ats-proxy:443",
                tls_trust_certs_file_path="/path/to/ca.cert.pem",
                tls_allow_insecure_connection=False,
                authentication=auth)

SNI 라우팅을 통한 Pulsar 지오레플리케이션

지오레플리케이션에 ATS 프록시를 사용할 수 있어요. Pulsar 브로커는 SNI 라우팅을 사용해 지오레플리케이션의 브로커에 연결할 수 있어요. 클러스터 간 브로커 연결에 SNI 라우팅을 활성화하려면 클러스터 메타데이터에 SNI 프록시 URL을 구성해야 해요. 클러스터 메타데이터에 SNI 프록시 URL을 구성했다면, SNI 라우팅을 통해 프록시를 거쳐 클러스터 간 브로커에 연결할 수 있어요.

이 예시에서 Pulsar 클러스터는 us-westus-east라는 두 개의 별도 리전에 배포돼 있어요. 두 리전 모두 ATS 프록시로 구성되고, 각 리전의 브로커는 ATS 프록시 뒤에서 실행돼요. 두 클러스터에 대해 클러스터 메타데이터를 구성해서, 한 클러스터의 브로커가 SNI 라우팅을 사용하고 ATS 프록시를 통해 다른 클러스터의 브로커에 연결할 수 있게 해요.

(a) us-east 클러스터 메타데이터를 us-east 브로커 서비스 URL과 SNI 프록시 프로토콜을 가진 us-east ATS 프록시 URL로 구성해요.

./pulsar-admin clusters update \
    --broker-url-secure pulsar+ssl://east-broker-vip:6651 \
    --url http://east-broker-vip:8080 \
    --proxy-protocol SNI \
    --proxy-url pulsar+ssl://east-ats-proxy:443

(b) us-west 클러스터 메타데이터를 us-west 브로커 서비스 URL과 SNI 프록시 프로토콜을 가진 us-west ATS 프록시 URL로 구성해요.

./pulsar-admin clusters update \
    --broker-url-secure pulsar+ssl://west-broker-vip:6651 \
    --url http://west-broker-vip:8080 \
    --proxy-protocol SNI \
    --proxy-url pulsar+ssl://west-ats-proxy:443

더 알아보기 (Learn more)