투명 프록시로서의 NGINX 및 NGINX Plus를 활용한 IP 투명성과 직접 서버 반환

NGINX | 2016년 9월 14일

이 블로그 게시물에서는 업스트림 서버로 향하는 트래픽에 대해 NGINX Open Source와 NGINX Plus를 투명 프록시로 구성하는 방법을 설명합니다. 또한 투명 프록시를 사용해 패킷의 소스 IP 주소를 위조하여 IP 투명성을 구현하는 방법과 UDP 트래픽에 Direct Server Return이라는 부하 분산 모드를 구현하는 방법을 설명합니다.

이 게시물의 정보는 NGINX Open Source와 NGINX Plus 모두에 적용됩니다. 간결하게 설명하기 위해 이하에서는 NGINX Plus로만 지칭하겠습니다.

편집자 주 – NGINX Plus R10의 새로운 기능을 심층적으로 살펴보는 블로그 게시물 시리즈의 다섯 번째 글입니다.

온디맨드 웨비나 NGINX Plus R10의 새로운 기능은?도 꼭 확인해 보세요.

요약

NGINX Plus는 계층 7 역방향 프록시로 작동합니다. 이를 통해 NGINX Plus는 관리하는 네트워크 요청에 다양한 최적화 및 개선 사항을 적용할 수 있습니다.

따라서 업스트림(부하 분산 대상) 서버에서는 모든 트래픽이 NGINX Plus 프록시의 IP 주소에서 시작된 것으로 인식됩니다. 이로 인해 업스트림 서버가 인증이나 로깅 등의 목적으로 실제 원본 IP 주소(원격 클라이언트의 IP 주소)를 확인해야 하는 경우 문제가 발생할 수 있습니다.

HTTP 및 HTTPS 트래픽에는 X-Forwarded-For HTTP 헤더 또는 PROXY 프로토콜을 사용하는 효과적인 해결 방법이 있습니다. 이 문서에서는 TCP 및 UDP 트래픽에 적용되는 두 가지 추가 방법을 설명합니다:

  • IP 투명성은 업스트림 서버가 각 연결이 해당 연결을 시작한 원격 클라이언트에서 비롯된 것으로 인식하도록 합니다. TCP 및 UDP 기반 프로토콜에 적용할 수 있습니다.
  • Direct Server Return(DSR)은 업스트림 서버의 응답이 중간 로드 밸런서를 거치지 않고 원격 클라이언트로 직접 전송되도록 합니다. UDP 기반 프로토콜에 적용할 수 있으며, 오리진 서버 또는 중간 라우터에서 NAT(네트워크 주소 변환)를 수행하는 방식으로 구현할 수 있습니다.

방법 1 – IP 투명성 방법 2a – DSR(라우터 NAT) 방법 2b – DSR(오리진 NAT)지원 프로토콜 TCP 기반 및 UDP 기반 UDP 기반만 지원 UDP 기반만 지원업스트림 서버의 트래픽 라우팅 모든 송신 트래픽이 NGINX Plus 프록시로 라우팅되어 종료됨 모든 송신 트래픽이 중간 NGINX Plus 서버를 통해 라우팅됨 모든 트래픽이 정상적으로 라우팅됨성능 표준: 송신 트래픽이 NGINX Plus 프록시에서 종료됨 향상: 송신 트래픽이 중간 NGINX Plus 서버에서 전달됨 최상: 송신 트래픽이 NGINX Plus를 우회하여 원격 클라이언트로 직접 라우팅됨상태 확인 기본적으로 수동, 능동 지원 능동 방식 필수, 수동 방식 불가 능동 방식 필수, 수동 방식 불가필수 구성NGINX Plus 프록시의 TCP 및 UDP TCP: 기본적으로 작동
UDP: proxy_responses 1 TCP: 지원되지 않음
UDP: proxy_responses 0 TCP: 지원되지 않음
UDP: proxy_responses 0패킷은 어디에서 어떻게 처리되는가? iptables가 NGINX Plus 프록시에서 종료 처리 tc nat가 중간 NGINX Plus 서버에서 재작성 tc nat가 업스트림 서버에서 재작성NGINX Plus 프록시의 네트워크 구성 iptables로 송신 패킷 캡처 IP 포워딩 및 상태 비저장 NAT 없음업스트림 서버의 네트워크 구성 NGINX Plus를 기본 경로로 지정 NGINX Plus를 기본 경로로 지정 상태 비저장 NAT

IP 투명성과 DSR은 배포 및 문제 해결이 복잡합니다. 표준 리버스 프록시 작동 모드로 애플리케이션이나 서비스의 요구 사항을 충족할 수 없는 경우에만 이러한 구성을 구현하십시오.

소개: 표준 계층 7 리버스 프록시의 패킷 흐름

단순히 패킷을 전달하는 스위치나 라우터와 달리 NGINX Plus는 계층 7 리버스 프록시로 작동합니다. 이 작동 모드에서 NGINX Plus는 원격 클라이언트와 선택된 업스트림 서버 간의 통신을 제어하기 위해 클라이언트 측과 업스트림 측의 TCP 연결(HTTP 및 TCP 트래픽용) 또는 UDP 세션을 각각 별도로 관리합니다.

NGINX Plus가 리버스 프록시 서버로 작동할 때 TCP 패킷과 UDP 데이터그램이 처리되는 방식을 보여 주는 다이어그램
표준 리버스 프록시로 작동하는 NGINX Plus의 트래픽 처리

  1. 원격 클라이언트는 공개된 IP 주소와 포트를 통해 NGINX Plus 리버스 프록시에 직접 TCP 연결을 설정하거나 UDP 데이터그램을 전송합니다. NGINX Plus는 TCP 연결 또는 UDP 세션을 종료하고 그 안의 요청 데이터를 읽습니다.
  2. 그런 다음 NGINX Plus는 선택된(부하 분산된) 업스트림 서버에 새 연결을 설정하거나(기존의 유휴 연결을 재사용)합니다.
  3. NGINX Plus가 업스트림 서버에 요청을 전송할 때 연결은 NGINX Plus의 내부 IP 주소에서 시작됩니다.
  4. 업스트림 서버가 요청에 응답할 때 NGINX Plus의 내부 IP 주소로 데이터를 전송합니다.
  5. NGINX Plus는 업스트림 측 연결에서 응답 데이터를 수신합니다. 응답을 처리하거나 수정할 수 있습니다(예: HTTP 응답에 압축 적용).
  6. 그런 다음 NGINX Plus는 클라이언트 측 연결에 응답 데이터를 씁니다.

이 표준 역방향 프록시 작동 방식에서는 업스트림 서버가 TCP 및 UDP 트래픽이 로컬 NGINX Plus 프록시에서 시작된 것으로 인식하게 됩니다.

계층 7 리버스 프록시 모드의 이점과 제한 사항

계층 7 역방향 프록시 작동 모드는 HTTP 및 TCP 트래픽에 상당한 성능 향상과 효율성을 제공합니다(TCP 최적화, 버퍼링, HTTP 연결 유지 재사용 포함). 그러나 인증 및 액세스 제어, 속도 제한, 로깅 등의 목적으로 업스트림 서버가 연결 또는 세션의 실제 원본 IP 주소를 확인해야 하는 경우에는 문제가 될 수 있습니다.

일부 프로토콜의 경우 NGINX Plus는 X-Forwarded-For HTTP 헤더 또는 PROXY 프로토콜을 사용하여 원본 IP 주소를 업스트림 서버에 제공할 수 있습니다. 이 게시물에서는 transparent 매개변수를 proxy_bind 지시문에 사용하여 구현할 수 있는 두 가지 추가 방법을 설명합니다. 이 매개변수는 NGINX Plus 릴리스 10 (R10)<.htmla>에서 도입되었습니다.

방법 1: IP 투명성

IP 투명성의 목적은 리버스 프록시의 존재를 숨겨 오리진 서버가 IP 패킷이 클라이언트의 IP 주소에서 전송된 것으로 인식하도록 하는 것입니다. IP 투명성은 TCP 기반 및 UDP 기반 프로토콜에 사용할 수 있습니다.

NGINX Plus 로드 밸런서에서 HTTP 리버스 프록시 서비스 생성

IP 투명성을 시연하기 위해 먼저 간단한 연결 정보를 반환하는 4대의 웹 서버로 구성된 부하 분산 클러스터를 만듭니다.

  1. 업스트림 서버 그룹에 트래픽을 부하 분산하는 간단한 HTTP 가상 서버를 구성합니다:
# in the 'http' context
server {
    listen 80;

    location / {
        proxy_pass http://http_upstreams;
    }
}

upstream http_upstreams {
    server 172.16.0.11;
    server 172.16.0.12;
    server 172.16.0.13;
    server 172.16.0.14;
}
  1. 업스트림 서버에서 연결이 NGINX Plus 로드 밸런서로부터 시작된 것으로 인식하는지 확인하려면, 네 대의 서버(172.16.0.11~172.16.01.14) 각각에 NGINX Plus 웹 서버를 구성하고 다음과 같이 연결 정보를 반환하는 간단한 가상 서버를 설정합니다:
# in the 'http' context
server {
    listen 80;

    location / {
        return 200 "Hello from $hostname. You connected from $remote_addr:$remote_port to $server_addr:$server_portn";
    }
}

이 구성을 테스트하면 업스트림 서버에서는 연결이 로컬 NGINX Plus IP 주소(172.16.0.1)에서 시작된 것으로 보고합니다:

$ for i in {1..4}; do curl http://192.168.99.10 ; done
Hello from dev1. You connected from 172.16.0.1:42723 to 172.16.0.11:80
Hello from dev2. You connected from 172.16.0.1:39117 to 172.16.0.12:80
Hello from dev3. You connected from 172.16.0.1:54545 to 172.16.0.13:80
Hello from dev4. You connected from 172.16.0.1:57020 to 172.16.0.14:80

IP 투명성을 위한 NGINX Plus 및 업스트림 구성

NGINX Plus R10 이상(및 NGINX Open Source 1.11.0 이상)에서는 업스트림 트래픽의 소스 주소를 스푸핑할 수 있습니다. transparent 매개변수를 proxy_bind 지시문에 포함합니다. 일반적으로 소스 주소는 원격 클라이언트의 주소로 설정합니다:

proxy_bind $remote_addr transparent;

하지만 이 간단한 단계에는 상당한 어려움이 따릅니다. 원격 클라이언트로 전송되는 응답(송신) 트래픽이 올바르게 처리되도록 해야 하기 때문입니다. 응답 트래픽은 NGINX Plus로 라우팅되어야 하며, NGINX Plus는 업스트림 TCP 연결을 종료해야 합니다. 그런 다음 NGINX Plus는 클라이언트 TCP 연결을 통해 원격 클라이언트로 응답 트래픽을 전송합니다.

NGINX Plus 로드 밸런서와 각 업스트림 서버 모두에서 몇 가지 구성을 변경해야 합니다:

  1. NGINX Plus 로드 밸런서에서 워커 프로세스가 root 권한으로 실행되도록 구성하여 업스트림 소켓을 임의의 주소에 바인딩할 수 있게 합니다. /etc/nginx/nginx.conf의 기본(최상위) 컨텍스트에 user 지시어를 포함하여 NGINX Plus 워커 프로세스의 ID를 root로 설정합니다:
# in the 'main' context
# 'user daemon' is the default; change to 'user root' with transparent proxy_bind
user root;
  1. NGINX Plus 로드 밸런서에서 각 연결이 원격 클라이언트 주소에서 시작되도록 합니다. 가상 서버 구성에 proxy_bind 지시문을 transparent 매개변수와 함께 추가합니다:
# in the 'http' context
server {
    listen 80;

    location / {
        proxy_bind $remote_addr transparent;
        proxy_pass http://http_upstreams;
    }
}
  1. NGINX Plus 로드 밸런서에서 업스트림 서버의 반환 패킷을 캡처하여 NGINX Plus로 전달하도록 iptables를 구성합니다. 이 예에서는 IP 범위 172.16.0.0/28로 표시되는 서버에서 포트 80을 통해 전송되는 모든 TCP 트래픽을 캡처하기 위해 iptables 및 ip rule 명령을 실행합니다:
# ip rule add fwmark 1 lookup 100
# ip route add local 0.0.0.0/0 dev lo table 100
# iptables -t mangle -A PREROUTING -p tcp -s 172.16.0.0/28 --sport 80 -j MARK --set-xmark 0x1/0xffffffff
  1. 다음 명령을 실행하여 (-L) iptables mangle 테이블의 현재 구성을 나열합니다:
# iptables -t mangle -L
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
MARK       tcp  --  172.16.0.0/28        anywhere             tcp spt:http MARK set 0x1

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
  1. 업스트림 서버에서 모든 반환 트래픽이 NGINX Plus로 전달되도록 라우팅을 구성합니다. 각 업스트림 서버에서 기존 기본 경로를 모두 제거하고, 기본 경로를 NGINX Plus 로드 밸런서/리버스 프록시의 IP 주소로 설정합니다. 이 IP 주소는 업스트림 서버의 인터페이스 중 하나와 동일한 서브넷에 있어야 합니다.
# route del default gw 10.0.2.2
# route add default gw 172.16.0.1
  1. 라우팅 테이블이 적절한지 확인합니다:
# route -n
Kernel IP routing table
Destination   Gateway     Genmask        Flags Metric Ref Use Iface
0.0.0.0       172.16.0.1  0.0.0.0        UG    0      0     0 eth2
10.0.2.0      0.0.0.0     255.255.255.0  U     0      0     0 eth0
172.16.0.0    0.0.0.0     255.255.255.0  U     0      0     0 eth2
192.168.56.0  0.0.0.0     255.255.255.0  U     0      0     0 eth1
  1. 업스트림 서버가 외부 서버에 연결할 수 있어야 하는 경우, 새 NGINX Plus 게이트웨이에서 트래픽을 전달하고 마스커레이드하도록 구성해야 합니다. 자세한 내용은 아래의 「업스트림에서 외부 서버에 연결할 수 있도록 설정」을 참조하세요.

IP 투명성 구성 테스트

이제 NGINX Plus에 요청을 보내 구성을 테스트할 수 있습니다. 업스트림 서버에서 직접 라우팅할 수 없는 원격 IP 주소에서 요청을 보내야 합니다:

$ for i in {1..4}; do curl http://192.168.99.10 ; done
Hello from dev1. You connected from 192.168.99.1:60729 to 172.16.0.11:80
Hello from dev2. You connected from 192.168.99.1:43070 to 172.16.0.12:80
Hello from dev3. You connected from 192.168.99.1:45749 to 172.16.0.13:80
Hello from dev4. You connected from 192.168.99.1:46609 to 172.16.0.14:80

이제 연결이 NGINX Plus 로드 밸런서의 로컬 주소가 아니라 원격 클라이언트의 IP 주소(192.168.99.1)에서 시작된 것으로 표시되는지 확인합니다.

구성이 작동하지 않는 경우 아래의 문제 해결을 참조하세요.

요약: IP 투명성 구성은 어떻게 작동하나요?

  • NGINX Plus가 원격 클라이언트(192.168.99.1)로부터 HTTP 요청을 수신합니다.
  • NGINX Plus는 부하 분산 결정을 내려 연결할 업스트림 서버(예: 172.16.0.11)를 선택합니다. NGINX Plus는 연결하기 전에 업스트림 소켓을 원격 클라이언트의 주소에 바인딩합니다.
  • 업스트림 서버는 원격 클라이언트에서 직접 시작된 것처럼 보이는 연결을 수신합니다.
  • 업스트림 서버는 원격 클라이언트의 주소를 대상으로 패킷을 전송하고 NGINX Plus(기본 라우터)를 통해 라우팅하여 응답합니다.
  • NGINX Plus 로드 밸런서의 iptables 규칙은 이러한 패킷을 표시하고, 라우팅을 통해 로컬로 전달합니다.
  • NGINX Plus가 응답을 읽습니다.
  • 그런 다음 NGINX Plus는 원격 클라이언트에 응답을 전송합니다.

결과적으로 업스트림 서버의 관점에서는 연결이 원격 클라이언트에서 직접 시작된 것처럼 보입니다.

방법 2: 직접 서버 반환

DSR(Direct Server Return)은 IP 투명성 개념을 확장한 방식입니다. IP 투명성에서는 업스트림 서버가 원격 클라이언트에서 전송된 것처럼 보이는 패킷을 수신합니다. DSR에서는 이에 더해 업스트림 서버가 원격 클라이언트에 직접 응답하므로, 반환 패킷이 로드 밸런서를 완전히 우회합니다.

DSR은 부하 분산 장치의 부하를 줄여 약간의 성능 향상을 제공할 수 있지만, 다음과 같은 여러 제약 사항이 있습니다:

  • 로드 밸런서는 반환 패킷을 전혀 확인할 수 없으므로 업스트림 서버가 응답 중인지 아니면 장애가 발생했는지 감지할 수 없습니다.
  • 로드 밸런서는 업스트림을 선택하기 전에 첫 번째 패킷 이후의 요청 내용을 검사할 수 없으므로, 로드 밸런싱 결정(콘텐츠 기반 라우팅) 기능이 매우 제한적입니다.
  • 로드 밸런서는 SSL/TLS와 같은 어떠한 형태의 협상이나 상태 저장 처리에도 관여할 수 없습니다.
  • 캐싱, HTTP 멀티플렉싱, 로깅 등 대부분의 다른 애플리케이션 전송 컨트롤러(ADC) 기능은 DSR에서 사용할 수 없습니다.

DSR은 TCP 프로토콜에서 활용이 제한적이며, 어떤 경우에도 NGINX Plus의 역방향 프록시 아키텍처를 DSR/TCP에 적용할 수 없습니다.

UDP 프로토콜은 훨씬 단순하며 TCP의 연결 관련 의미 체계가 없습니다. DNS와 같은 UDP 프로토콜에 DSR을 지원하도록 NGINX Plus를 구성하면 성능을 향상할 수 있습니다. 구체적으로 DSR을 사용하면 NGINX Plus가 응답 패킷을 기다리기 위해 UDP 소켓을 열린 상태로 유지할 필요가 없으므로 확장성이 향상되며, 응답 패킷이 NGINX Plus의 계층 7 처리를 완전히 우회할 수 있으므로 지연 시간이 단축됩니다.

DSR 구성은 IP 투명성과 어떻게 다릅니까?

UDP 트래픽에 대한 IP 투명성 구성과 DSR 구성에는 다음과 같은 세 가지 차이점이 있습니다:

  • NGINX Plus는 업스트림 서버로 데이터그램을 전송할 때 원격 클라이언트의 IP 주소와 포트를 모두 스푸핑해야 합니다(proxy_bind 포트 구성).
  • NGINX Plus가 업스트림 서버의 응답 데이터그램을 기다리도록 구성해서는 안 됩니다(proxy_responses 0 지시어).
  • 반환 데이터그램의 소스 주소가 로드 밸런서의 공용 주소와 일치하도록 다시 쓰려면 추가 단계가 필요합니다.

또한 NGINX Plus가 업스트림 서버에 대해 능동 상태 검사를 수행하도록 구성해야 합니다. NGINX Plus는 서버가 전송한 응답 패킷을 관찰하지 않으므로, 서버의 정상 작동 여부를 확인할 때 일반적인 수동 검사에 의존할 수 없습니다.

표준 UDP 리버스 프록시 서비스 만들기

DSR을 시연하려면 먼저 www.example.com 이름 조회에 서로 다른 IP 주소로 응답하는 4개의 DNS 서버로 구성된 부하 분산 클러스터를 만듭니다.

DNS 서버 간에 부하를 분산하도록 간단한 리버스 프록시 구성을 설정합니다:

# in the 'stream' context
server {
    listen 53 udp;

    proxy_responses 1;
    proxy_timeout 1s;
    proxy_pass dns_upstreams;
}

upstream dns_upstreams {
    server 172.16.0.11:53;
    server 172.16.0.12:53;
    server 172.16.0.13:53;
    server 172.16.0.14:53;
}

The proxy_responses 및 proxy_timeout 지시문은 기본적인 상태 확인을 수행합니다. 업스트림 서버가 1초 이내에 응답을 하나도 보내지 않으면 NGINX Plus는 해당 서버에 장애가 발생한 것으로 간주하고 DNS 요청을 다시 시도합니다.

각 DNS 서버가 www.example.com 조회에 자체 IP 주소로 응답하도록 구성합니다:

$TTL   	604800
@           IN          SOA         ns1.example.com. admin.example.com. (
                              2           ; Serial
                         604800           ; Refresh
                          86400           ; Retry
                        2419200           ; Expire
                         604800 )         ; Negative Cache TTL

example.com.    IN      NS      ns1.example.com.

ns1             IN      A       172.16.0.11
www             IN      A       172.16.0.11

테스트를 통해 NGINX Plus가 DNS 서버 간에 요청을 부하 분산하고 있음을 명확히 확인할 수 있습니다:

$ for i in {1..4} ; do dig +short @192.168.99.10 www.example.com ; done
172.16.0.11
172.16.0.12
172.16.0.13
172.16.0.14

DSR을 위한 NGINX Plus 및 UDP 업스트림 구성

NGINX Plus R10 이상(및 NGINX Open Source 1.11.2 이상)에서는 업스트림 트래픽의 소스 주소와 포트를 모두 스푸핑할 수 있습니다. transparent 매개변수를 proxy_bind 지시문에 포함하세요:

proxy_bind $remote_addr:$remote_port transparent;

이렇게 하면 업스트림 서버가 전체 소스 IP 주소를 확인할 수 있으므로 원격 클라이언트로 직접 전송되는 응답 데이터그램을 생성할 수 있습니다.

업스트림 서버는 올바른 대상 IP가 지정된 응답(“송신”) 패킷을 생성하지만, 소스 주소로는 자체 로컬 IP 주소를 사용합니다. 이 소스 주소를 클라이언트가 처음 연결한 NGINX Plus 로드 밸런서의 IP 주소와 포트로 다시 작성해야 합니다.

다음 두 가지 방법을 사용할 수 있습니다:

  1. 라우터 NAT – 중간 라우터(예: NGINX Plus 프록시)에서 송신 패킷을 다시 작성합니다.
  2. 오리진 NAT – 각 업스트림 DNS 서버에서 나가는 송신 패킷을 다시 작성합니다

두 방법 모두 tc 명령으로 구성하는 상태 비저장 NAT 기능을 사용합니다. 업스트림 서버가 인터넷에 직접 연결되어 있다면(즉, 네트워크 토폴로지상 반환 패킷이 사용자가 제어할 수 있는 중간 라우터를 통과하지 않는 경우) 오리진 NAT 방식을 선택해야 합니다.

DSR을 위한 NGINX Plus 구성

응답 패킷은 NGINX Plus로 전달되지 않으므로 표준 UDP 리버스 프록시 서비스 생성에서 구성한 상태 확인을 비활성화해야 합니다. 이를 위해 proxy_responses 지시문을 수정하고 proxy_timeout 지시문을 비활성화합니다. 이제 NGINX Plus는 응답을 기다리지 않으며, 응답을 받지 못하더라도 업스트림 서버에 장애가 발생한 것으로 판단하지 않습니다. 또한 이 확인을 비활성화하면 NGINX Plus가 소켓 리소스를 즉시 재사용할 수 있습니다.

또한 $remote_addr 및 $remote_port 변수를 proxy_bind 지시문의 첫 번째 매개변수에 모두 포함하여 NGINX Plus가 업스트림 서버로 전송되는 데이터그램에서 원래 소스 주소와 소스 포트를 모두 유지하도록 합니다:

# in the 'stream' context
server {
    listen 53 udp;

    proxy_bind $remote_addr:$remote_port transparent;
    proxy_responses 0;
    #proxy_timeout 1s;
}

라우터 NAT – 중간 라우터에서 송신 패킷 재작성

단일 중간 라우터에서 송신 패킷을 다시 작성할 수 있습니다. 예를 들어 업스트림 서버가 NGINX Plus 로드 밸런서 뒤의 사설 네트워크에 있는 경우, 로드 밸런서를 기본 경로로 사용하고 패킷이 전달될 때 다시 작성할 수 있습니다.

  1. 각 업스트림 서버가 모든 아웃바운드 트래픽을 NGINX Plus 서버를 통해 라우팅하도록 구성합니다:
# route add default gw nginx-ip-address
  1. IP 트래픽을 전달하도록 NGINX Plus 서버를 구성합니다:
# sysctl -w net.ipv4.ip_forward=1
  1. NGINX Plus 서버가 상태 비저장 NAT 재작성을 수행하도록 구성합니다:
# tc qdisc add dev eth0 root handle 10: htb
# tc filter add dev eth0 parent 10: protocol ip prio 10 u32 match ip src 172.16.0.11 match ip sport 53 action nat egress 172.16.0.11 192.168.99.10
# tc filter add dev eth0 parent 10: protocol ip prio 10 u32 match ip src 172.16.0.12 match ip sport 53 action nat egress 172.16.0.12 192.168.99.10
# tc filter add dev eth0 parent 10: protocol ip prio 10 u32 match ip src 172.16.0.13 match ip sport 53 action nat egress 172.16.0.13 192.168.99.10
# tc filter add dev eth0 parent 10: protocol ip prio 10 u32 match ip src 172.16.0.14 match ip sport 53 action nat egress 172.16.0.14 192.168.99.10
  1. 적절한 송신 인터페이스와 각 업스트림 서버의 올바른 IP 주소를 선택했는지 확인합니다.

상태 비저장 NAT에 대한 자세한 내용은 tc nat 매뉴얼 페이지를 참조하십시오. 구성에 따라 tc filter 명령에서 src 및 egress old 매개변수에 CIDR 마스크를 사용하여 명령 수를 하나로 줄일 수 있습니다.

현재 tc filter 구성을 표시하려면 다음 명령을 실행합니다:

# tc filter show dev eth0

오리진 NAT – 각 업스트림 서버에서 송신 패킷 재작성

업스트림 서버의 네트워크를 구성할 수 있다면, 특히 해당 서버가 인터넷에 직접 연결되어 있는 경우 다음 구성을 사용할 수 있습니다. 이 구성은 각 업스트림 서버에 적용해야 합니다.

각 업스트림 서버가 상태 비저장 NAT 재작성을 수행하도록 구성합니다:

# tc qdisc add dev eth0 root handle 10: htb
# tc filter add dev eth0 parent 10: protocol ip prio 10 u32 match ip src 172.16.0.11 match ip sport 53 action nat egress 172.16.0.11 192.168.99.10

각 업스트림에서 적절한 인터페이스와 IP 주소를 선택해야 합니다.

DSR 구성 테스트

구성을 테스트하려면 NGINX Plus 로드 밸런서로 DNS 요청을 보내고, 해당 요청이 업스트림 서버 간에 부하 분산되는지 확인합니다.

DSR은 직접적으로 눈에 보이는 효과가 없습니다. proxy_responses 0 지시문을 사용하여 NGINX Plus가 응답 패킷을 기다리지 않도록 구성했는데도 DNS 클라이언트가 부하 분산된 응답을 수신한다면 DSR이 작동하고 있다고 확신할 수 있습니다. 아래의 tcpdump를 사용하여 패킷 흐름을 추가로 관찰할 수도 있습니다. 자세한 내용은 문제 해결을 참조하세요.

요약: DSR 구성은 어떻게 작동하나요?

  • NGINX Plus는 원격 클라이언트(192.168.99.1:포트)로부터 UDP 데이터그램을 수신합니다.
  • NGINX Plus는 부하 분산 결정을 내려 데이터그램 콘텐츠를 쓸 업스트림 서버(예: 172.16.0.11)를 선택합니다. NGINX Plus는 연결하기 전에 업스트림 소켓의 로컬 측을 원격 클라이언트의 IP 주소와 포트에 바인딩합니다.
  • 업스트림 서버는 NGINX Plus가 전송한 데이터그램을 수신합니다. 이 데이터그램은 원격 클라이언트의 주소와 포트에서 직접 전송된 것처럼 보입니다.
  • 업스트림 서버는 원격 클라이언트로 데이터그램을 다시 전송하여 응답합니다. 업스트림 서버는 응답 데이터그램의 소스 IP 주소와 포트를 자체 로컬 IP 주소와 포트로 설정합니다.
  • 소스 IP 주소(필요한 경우 포트 포함)는 업스트림 서버(오리진 NAT 구성) 또는 중간 라우터(라우터 NAT 구성)에 의해 다시 작성됩니다.
  • 원격 클라이언트는 올바른 4-튜플(출발지 및 목적지 IP 주소와 포트)로 주소가 지정된 데이터그램을 수신합니다.
  • NGINX Plus는 응답 데이터그램이 수신될 것으로 예상하지 않으며 업스트림 소켓을 즉시 닫습니다.

결과적으로 응답 패킷은 NGINX Plus의 계층 7 처리를 우회하여 원격 클라이언트로 직접 전송됩니다.

문제 해결

IP 투명성 또는 DSR이 예상대로 작동하지 않는 경우 다음 제안 사항을 참고하여 가능한 원인을 조사하세요:

다음 사용자로 실행: root

NGINX Plus 워커 프로세스가 root 권한으로 실행되도록 구성되어 있는지 확인합니다. 그렇지 않은 경우 NGINX Plus가 소켓을 로컬이 아닌 주소에 바인딩하려고 할 때 오류 로그에 다음과 유사한 오류 메시지가 표시됩니다:

setsockopt(IP_TRANSPARENT) failed (1: Operation not permitted) while connecting to upstream, client: 192.168.99.1, server: , request: "GET / HTTP/1.1", upstream: "http://172.16.0.11:80/", host: "192.168.99.10"

테스트: ping

NGINX Plus 프록시에서 클라이언트와 서버에 ping을 보낼 수 있는지 확인합니다. 필요한 라우팅 구성을 먼저 생성하고 NGINX Plus 중개자가 패킷을 전달하도록 구성하지 않으면 업스트림 서버에서 원격 클라이언트 IP 주소로 ping을 보낼 수 없습니다.

중복되는 IP 범위 없음

원격 클라이언트가 사용하는 IP 서브넷이 업스트림 서버에 직접 연결되어 있지 않은지 확인하세요. 직접 연결되어 있으면 다음 두 가지 문제가 발생할 수 있습니다:

  • 소스 IP 주소가 다른 인터페이스의 서브넷에 연결되어 있기 때문에 Linux의 ‘역방향 경로 필터링’ 보호 기능이 NGINX Plus에서 전송된 패킷을 아무런 알림 없이 거부할 수 있습니다.
  • 반환 패킷은 기본 경로를 사용하지 않고 로컬로 연결된 원격 클라이언트로 직접 전송됩니다.

어디서나 tcpdump 사용하기

구성을 완성해 나가면서 각 중간 단계를 테스트할 때, 모든 서버에서 tcpdump를 계속 실행하여 각 단계에서 패킷이 올바른 엔드포인트로 전송되고 해당 엔드포인트에서 수신되는지 확인하세요:

$ sudo tcpdump -i any -n tcp port 80

아래에 나열된 점검 항목을 사용하여 비정상적인 동작이 있는지 조사하세요.

라우팅 테이블 확인

각 서버의 라우팅 테이블을 주의 깊게 확인하되, 특히 업스트림 서버를 중점적으로 살펴보세요:

# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.16.0.1      0.0.0.0         UG    0      0        0 eth2
10.0.2.0        0.0.0.0         255.255.255.0   U     0      0        0 eth0
172.16.0.0      0.0.0.0         255.255.255.0   U     0      0        0 eth2
192.168.56.0    0.0.0.0         255.255.255.0   U     0      0        0 eth1

예상치 못한 경로가 있나요? 흐름의 모든 패킷이 올바른 대상으로 라우팅되는지 확인할 수 있나요? iptables 및 라우터 NAT 구성에서는 모든 송신 패킷이 중간 NGINX Plus 프록시를 통해 라우팅되어야 한다는 점을 기억하세요.

누락된 패킷

패킷이 예기치 않게 손실되는 경우(tcpdump에서 한 시스템이 패킷을 전송했지만 다른 시스템이 수신하지 못한 것으로 나타나는 경우), 역방향 경로 필터링이 드러나지 않는 원인일 수 있습니다. 역방향 경로 필터링을 일시적으로 비활성화하려면 다음 명령을 실행하세요:

# for f in /proc/sys/net/ipv4/conf/*/rp_filter; do echo 0 > $f ; done

업스트림 서버가 외부 서버에 연결할 수 있도록 설정

업스트림 서버가 사설 네트워크에 있고 NGINX Plus(또는 다른 서버)를 기본 게이트웨이로 사용하는 경우, 업스트림 서버가 외부(인터넷) 호스트에 연결할 수 있도록 게이트웨이를 구성할 수 있습니다.

게이트웨이가 업스트림 서버의 패킷을 전달할 수 있도록 IP 포워딩을 활성화해야 합니다. IP 포워딩은 일반적으로 기본적으로 비활성화되어 있습니다. 서버에 라우팅 가능한 IP 주소가 없는 경우(172.16.0.0/24와 같은 사설 주소를 사용하는 경우) 게이트웨이 서버의 외부 인터페이스에 IP 마스커레이딩도 구성해야 합니다:

# sysctl -w net.ipv4.ip_forward=1
# iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

내부 업스트림 서버에서 외부 서버로 ping을 보낼 수 있는지 확인합니다:

root@dev1:~# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=61 time=6.72 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=61 time=5.49 ms
^C

현재 포워딩, 라우팅 및 iptables nat 구성을 표시하려면 다음 세 가지 명령을 실행하세요:

# sysctl net.ipv4.ip_forward
# route -n
# iptables -t nat -L

NGINX의 지원 받기

IP 투명성 또는 DSR(Direct Server Return) 구성은 복잡하며, 중간에 있는 다른 네트워크 장치가 패킷을 삭제하거나 다른 방식으로 다시 작성하여 배포에 영향을 줄 수 있습니다. 도움이 필요하시면 NGINX의 전문 서비스 팀이 지원해 드립니다.

NGINX Plus의 IP 투명성과 DSR을 직접 경험해 보세요. 지금 30일 무료 체험을 시작하거나 문의하여 사용 사례를 상담해 보세요.


공유
태그: F5 NGINX, Tech, 2016

작성자 소개

관련 블로그 게시물

시청하기: KubeCon North America 2023에서의 NGINX Gateway Fabric
NGINX | 2023. 11. 30.

시청하기: KubeCon North America 2023에서의 NGINX Gateway Fabric

이 영상에서는 KubeCon의 NGINX 부스를 찾아가, 저희가 공개한 Kubernetes Gateway API 구현을 살펴봅니다.

F5 NGINX로 대규모 WAF 플릿을 확인하고 관리하는 2가지 방법
NGINX | 2023. 03. 23.

F5 NGINX로 대규모 WAF 플릿을 확인하고 관리하는 2가지 방법

앱 보안을 강화하는 두 가지 방법을 소개합니다. NGINX Management Suite를 통해 WAF 운영에 대한 가시성을 높이고, NGINX App Protect WAF를 활용해 코드형 보안을 구현하는 것입니다.

Ingress 컨트롤러 선택 가이드, 4부: NGINX Ingress Controller 옵션
NGINX | 2021. 09. 27.

Ingress 컨트롤러 선택 가이드, 4부: NGINX Ingress Controller 옵션

개발 주체, 개발 철학, 프로덕션 환경 준비도, 보안 및 지원을 기준으로 어떤 NGINX Ingress 컨트롤러가 가장 적합한지 알아보세요.

진화하는 공격 환경에 NGINX App Protect Denial of Service가 적응하는 방법
NGINX | 2021. 07. 06.

진화하는 공격 환경에 NGINX App Protect Denial of Service가 적응하는 방법

NGINX App Protect Denial of Service(DoS)가 계층 7 DoS 공격을 방어하기 위해 완화 방법을 실시간으로 조정하는 방식을 설명합니다. 정상적인 사용자 행동과 서버 상태에 대한 모델을 생성하여 공격을 나타내는 이상 징후를 감지하고 맞춤형 완화 시그니처를 적용할 수 있습니다.

NGINX Instance Manager를 활용한 대규모 구성 업데이트 및 인증서 관리
NGINX | 2021. 06. 30.

NGINX Instance Manager를 활용한 대규모 구성 업데이트 및 인증서 관리

NGINX Instance Manager 버전 1.0에는 두 가지 새로운 기능이 도입되었습니다. NGINX 인스턴스에 태그와 사용자 역할을 지정하면 전체 그룹에 구성을 한 번에 적용할 수 있습니다. 인증서 검사는 만료 예정인 인증서를 감지하여 서비스 중단을 방지할 수 있도록 인증서를 교체할 수 있게 해줍니다.

Netflix가 자사 CDN의 핵심으로 NGINX를 선택한 이유
NGINX | 2015. 03. 25.

Netflix가 자사 CDN의 핵심으로 NGINX를 선택한 이유

Netflix가 글로벌 콘텐츠 전송 네트워크인 Open Connect의 스트리밍 미디어 기술로 NGINX를 선택한 이유를 NGINX 개발자 Gleb Smirnoff에게서 알아보세요.