리버스 프록시로 Quack 보안 설정하기

리버스 프록시로 Quack 보안 설정하기

Quack 서버는 기본적으로 plain HTTP만 다루고, 기본 설정으로 localhost에만 바인딩돼요. 로컬을 넘어서는 어떤 배포에서든 권장 패턴은 다른 HTTP 기반 데이터베이스/애플리케이션 서버와 동일해요. 검증된 HTTP 리버스 프록시를 앞에 두고, 프록시가 TLS를 종료하게 하면 돼요. 이 가이드에서 그 설정 방법을 단계별로 살펴볼게요.

출처: 문서

본문

Quack 클라이언트는 이와 잘 협력해요. 로컬이 아닌 URI에 대해서는 기본적으로 HTTPS를 가정하죠. 그래서 제대로 프록시를 앞에 둔 서버는 클라이언트 쪽에서도 별다른 설정 없이 "그냥 동작"해요.

이 가이드는 유용할 것 같은 순서대로 세 가지 설정을 다룹니다.

  1. Caddy를 이용한 로컬 TLS 테스트 설정 — 여러분의 머신에서 전체 HTTPS 경로를 실습할 수 있어요.
  2. 프로덕션에서의 nginx + Let's Encrypt.
  3. 프로덕션에서의 Caddy + Let's Encrypt.

두 프로덕션 설정은 서로 바꿔 쓸 수 있어요. 운영 스택에 맞는 것을 고르면 됩니다.

Caddy를 이용한 로컬 테스트 설정

Caddy를 사용해 여러분의 머신에서 전체 HTTPS 경로를 실습할 수 있어요. Caddy는 로컬 CA에서 localhost용 인증서를 자체 발급하고, 그 CA 루트를 시스템 신뢰 저장소에 설치하므로 DuckDB의 HTTPS 클라이언트가 추가 설정 없이 인증서를 신뢰하게 됩니다.

1. Caddy 실행

Caddyfile을 저장하세요.

localhost:8443 {
    reverse_proxy 127.0.0.1:9494 {
        flush_interval -1
    }

    request_body {
        max_size 256MB
    }
}

그다음 Caddy를 시작합니다.

brew install caddy # macOS, 다른 플랫폼은 https://caddyserver.com/docs/install 참고
caddy run --config Caddyfile

첫 실행 시 Caddy의 로컬 CA를 시스템 신뢰 저장소에 설치하기 위해 권한 상승을 요청할 거예요. 그 이후로 Caddy가 localhost에 대해 발급한 인증서는 시스템 전체에서 신뢰됩니다.

2. Quack을 시작하고 프록시를 통해 연결

한 DuckDB 세션에서 서버를 시작합니다 (인증 토큰이 출력돼요).

CALL quack_serve('quack:localhost');

클라이언트 세션에서는 :8443의 Caddy를 통해 연결해요. 로컬 URI는 기본적으로 plain HTTP를 쓰므로, SSL을 명시적으로 켜야 합니다.

ATTACH 'quack:localhost:8443' AS quack (
    TOKEN '⟨authentication_token-from-quack_serve⟩',
    DISABLE_SSL false
);

FROM quack.query('SELECT 42');

왕복이 성공하면 여러분의 트래픽은 TLS로 Caddy에 나갔다가, 종료된 뒤 plain HTTP로 :9494의 Quack에 전달된 거예요.

Nginx + Let's Encrypt

가장 흔한 선택이 될 것 같아요. 루프백 인터페이스에서 수신하는 Quack 서버를 위한 최소한의 사이트 설정은 다음과 같습니다.

# /etc/nginx/sites-enabled/quack.example.com
server {
    listen 443 ssl http2;
    server_name quack.example.com;

    ssl_certificate     /etc/letsencrypt/live/quack.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/quack.example.com/privkey.pem;

    # Quack RPC 바디는 클 수 있어요: PREPARE는 SQL을, APPEND는 삽입된
    # DataChunk를 실어 나릅니다. nginx 기본값 1 MiB면 INSERT 도중 실패해요.
    client_max_body_size 256M;

    # 오래 실행되는 쿼리는 FETCH 사이를 몇 분씩 걸려 와이어 위에
    # 머무를 수 있어요. nginx 기본 60초보다 타임아웃을 올려 주세요.
    proxy_read_timeout 600s;
    proxy_send_timeout 600s;

    location / {
        proxy_pass http://127.0.0.1:9494;

        # 업스트림에 대한 keep-alive. Quack은 서버 쪽
        # `quack_connection_id` 상태를 유지하기 위해 지속 연결에 의존해요.
        proxy_http_version 1.1;
        proxy_set_header Connection "";

        # Quack은 반복되는 FETCH 응답으로 결과를 스트리밍해요.
        # nginx의 버퍼링은 스트리밍을 무력화하고 메모리를 부풀려요.
        proxy_buffering off;
    }
}

Quack 쪽에서는 localhost에 바인딩된 서버를 시작합니다 (기본값이에요).

CALL quack_serve('quack:localhost');

certbot --nginx -d quack.example.com으로 인증서를 발급하세요.

클라이언트는 HTTPS로 자동 연결됩니다.

ATTACH 'quack:quack.example.com' AS quack;   -- HTTPS 자동 선택

Caddy + Let's Encrypt

Caddy는 Let's Encrypt에서 인증서를 자동 프로비저닝하며 설정이 거의 필요 없어요. 공개 지향 Quack 프록시의 완전한 설정은 다음과 같습니다.

# /etc/caddy/Caddyfile
quack.example.com {
    reverse_proxy 127.0.0.1:9494 {
        # nginx `proxy_buffering off`와 동일한 역할. Quack의 스트리밍된
        # FETCH 응답이 Caddy에 버퍼링되지 않고 즉시 통과하도록 필수예요.
        flush_interval -1
    }

    # nginx `client_max_body_size`와 동일. PREPARE / APPEND 바디는
    # 기본 요청 본문 상한보다 훨씬 클 수 있어요.
    request_body {
        max_size 256MB
    }
}

Caddy가 인증서 발급과 갱신을 자동으로 처리해요. certbot 단계가 필요 없답니다.

Quack 쪽에서는 localhost에 바인딩된 서버를 시작합니다 (기본값).

CALL quack_serve('quack:localhost');

클라이언트는 HTTPS로 자동 연결됩니다.

ATTACH 'quack:quack.example.com' AS quack;   -- HTTPS 자동 선택

더 알아보기 (Learn more)

  • Quack 서버가 왜 이렇게 기본 설정을 갖는지에 대한 배경은 quack/security 문서를 참고해 주세요.