NGINX Plus

TCP Upstream 서버에 대한 SSL Termination

이 문서에서는 NGINX Plus 및 TCP 연결을 허용하는 Load Balancing된 서버 그룹에 대한 SSL Termination를 설정하는 방법을 설명합니다.

클라이언트의 SSL/TLS 암호화 트래픽을 Terminate하여 Upstream TCP 서버의 처리 부하를 덜어줍니다.

목차

1. SSL Termination란?
2. 전제 조건
3. SSL 인증서 받기
4. NGINX Plus 구성
4-1. SSL 활성화
4-2. SSL 인증서 추가
5. 보안 TCP 연결 속도 향상

5-1. SSL 세션 캐시 최적화
5-2. 세션 티켓
6. 전체 예제

1. SSL Termination란?

SSL Termination는 클라이언트와의 연결에 대한 서버 측 SSL Endpoint 역할을 하는 것으로, Backend 서버가 수행해야 하는 요청의 암호 해독 및 응답의 암호화를 수행합니다. 이 작업을 Termination라고 부르는데, 그 이유는 NGINX Plus가 클라이언트 연결을 닫고 새로 생성된 암호화되지 않은 연결을 통해 클라이언트 데이터를 Upstream 그룹의 서버로 전달하기 때문입니다. 릴리스 R6 이상에서 NGINX Plus는 HTTP 연결뿐만 아니라 TCP 연결에 대해서도 SSL Termination을 수행합니다.

2. 전제 조건

  • NGINX Plus R6 이상
  • 여러 TCP 서버가 있는 Load Balancing된 Upstream 그룹
  • SSL 인증서 및 Private Key(획득 또는 자체 생성)

3. SSL 인증서 받기

먼저 서버 인증서와 Private Key를 발급받아 서버에 설치해야 합니다. 인증서는 신뢰할 수 있는 인증 기관(CA)에서 받거나 OpenSSL과 같은 SSL 라이브러리를 사용하여 생성할 수 있습니다.

4. NGINX Plus 구성

SSL Termination를 구성하려면 다음 지시문을 NGINX Plus 구성에 추가합니다.

4-1. SSL 활성화

SSL을 사용하려면 Upstream 서버 그룹에 연결을 전달하는 TCP 서버에 대한 listen 지시문의 ssl 매개변수를 지정합니다.

stream {

    server {
        listen     12345 ssl;
        proxy_pass backend;
        #...
    }
}

4-2. SSL 인증서 추가

SSL 인증서를 추가하려면 ssl_certificate 지시문으로 인증서 경로(PEM 형식이어야 합니다)를 지정하고 ssl_certificate_key 지시문으로 Private Key 경로를 지정합니다.

server {
    #...
    ssl_certificate        /etc/ssl/certs/server.crt;
    ssl_certificate_key    /etc/ssl/certs/server.key;
}

또한 ssl_protocolsssl_ciphers 지시문을 사용하여 연결을 제한하고 SSL/TLS의 강력한 버전과 암호만 포함할 수 있습니다.

server {
    #...
    ssl_protocols  TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers    HIGH:!aNULL:!MD5;
}

ssl_ciphers 지시문은 NGINX가 선호하는 암호를 SSL 라이브러리에 알리도록 지시합니다.

5. 보안 TCP 연결 속도 향상

SSL Handshake 작업(클라이언트와 서버가 연결이 신뢰할 수 있는지 확인하기 위해 교환하는 일련의 메시지)은 CPU를 상당히 많이 사용하기 때문에 SSL/TLS를 구현하면 서버 성능에 상당한 영향을 미칠 수 있습니다. SSL Handshake의 기본 시간 제한은 60초이며 ssl_handshake_timeout 지시문을 사용하여 재정의할 수 있습니다. 이 값을 너무 낮거나 높게 설정하면 Handshake가 실패하거나 Handshake가 완료될 때까지 기다리는 시간이 길어질 수 있으므로 너무 낮거나 높게 설정하지 않는 것이 좋습니다.

server {
    #...
    ssl_handshake_timeout 10s;
}

5-1. SSL 세션 캐시 최적화

각 SSL/TLS 연결에 적용되는 세션 매개변수의 캐시를 생성하면 Handshake 횟수가 줄어들어 성능이 크게 향상될 수 있습니다. 캐싱은 ssl_session_cache 지시문으로 설정합니다.

ssl_session_cache;

기본적으로 NGINX Plus는 SSL 라이브러리에 내장된 캐시를 의미하는 built-in type 세션 캐시를 사용합니다. 이러한 캐시는 하나의 Worker Process에서만 사용할 수 있고 메모리 조각화를 일으킬 수 있으므로 최적이 아닙니다. 모든 Worker Process에서 캐시를 공유하려면 ssl_session_cache 지시문을 shared로 설정하면 연결 설정 정보를 이미 알고 있기 때문에 나중에 연결 속도가 빨라집니다.

ssl_session_cache shared:SSL:1m;

참고로 1MB 공유 캐시는 약 4,000개의 세션을 저장할 수 있습니다.

기본적으로 NGINX Plus는 캐시된 세션 매개변수를 5분 동안 유지합니다. 캐시된 세션 매개변수를 재사용하면 시간이 많이 걸리는 Handshake 횟수가 줄어들기 때문에 ssl_session_timeout의 값을 몇 시간으로 늘리면 성능이 향상될 수 있습니다. 시간 제한을 늘리면 캐시된 매개 변수의 수를 수용하기 위해 캐시가 더 커져야 합니다. 다음 예제의 4시간 timeout의 경우 20MB 캐시가 적합합니다.

ssl_session_timeout 4h;

시간 초과 길이가 길어지면 세션을 저장하는 데 더 큰 캐시(예: 20MB)가 필요합니다.

server {
    #...
    ssl_session_cache   shared:SSL:20m;
    ssl_session_timeout 4h;
}

이 줄은 세션 정보를 저장하기 위해 20MB의 인메모리 캐시를 생성하고, 세션 매개변수가 추가된 순간부터 4시간 동안 캐시에서 세션 매개변수를 재사용하도록 NGINX Plus에 지시합니다.

5-2. 세션 티켓

세션 티켓은 세션 캐시의 대안입니다. 세션 정보는 클라이언트 측에 저장되므로 세션 정보를 저장하기 위해 서버 측 캐시가 필요하지 않습니다. 클라이언트가 Backend 서버와의 상호 작용을 재개할 때 세션 티켓을 제시하므로 재협상이 필요하지 않습니다. ssl_session_tickets 지시문을 on으로 설정합니다.

server {
    #...
    ssl_session_tickets on;
}

Upstream 그룹에 세션 티켓을 사용할 때는 각 Upstream 서버를 동일한 세션 키로 초기화해야 합니다. 세션 키를 자주 변경하는 것이 가장 좋은 방법이며, 모든 Upstream 서버에서 공유 키를 순환하는 메커니즘을 구현하는 것이 좋습니다.

server {
    #...
    ssl_session_tickets on;
    ssl_session_ticket_key /etc/ssl/session_ticket_keys/current.key;
    ssl_session_ticket_key /etc/ssl/session_ticket_keys/previous.key;
}

6. 전체 예제

stream {
    upstream stream_backend {
         server backend1.example.com:12345;
         server backend2.example.com:12345;
         server backend3.example.com:12345;
    }

    server {
        listen                12345 ssl;
        proxy_pass            stream_backend;

        ssl_certificate       /etc/ssl/certs/server.crt;
        ssl_certificate_key   /etc/ssl/certs/server.key;
        ssl_protocols         SSLv3 TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers           HIGH:!aNULL:!MD5;
        ssl_session_cache     shared:SSL:20m;
        ssl_session_timeout   4h;
        ssl_handshake_timeout 30s;
        #...
     }
}

이 예제에서 server 블록의 지시문은 클라이언트에서 보안 TCP 트래픽을 Terminate하고 암호를 해독하여 암호화되지 않은 상태로 3개의 서버로 구성된 Upstream 그룹 stream_backend로 전달하도록 NGINX Plus에 지시합니다.

listen 지시문의 ssl 매개변수는 NGINX Plus가 SSL 연결을 수락하도록 지시합니다. 클라이언트가 보안 TCP 연결을 요청하면 NGINX Plus는 Handshake 프로세스를 시작하며, 이 프로세스는 ssl_certificate 지시문으로 지정된 PEM 형식 인증서, ssl_certificate_key 지시문으로 지정된 인증서의 Private Key, ssl_protocolsssl_ciphers 지시문에 나열된 프로토콜 및 Cyper를 사용합니다.

보안 TCP 연결이 설정되는 즉시 NGINX Plus는 ssl_session_cache 지시문에 따라 세션 매개변수를 캐시합니다. 이 예제에서 세션 캐시는 모든 Worker Process 간에 공유되고(shared 매개변수), 크기는 20MB이며(20m 매개변수), 재사용을 위해 각 SSL 세션을 4시간 동안 유지합니다(ssl_session_timeout 지시문).