본문 바로가기
개발 및 운영

haproxy transparent 설정

by Joseph.Lee 2019. 7. 9.

하나의 포트를 이용하여 여러개의 서비스를 돌릴 때 haproxy를 이용할 수 있다.

하지만 이런 경우 실제 서비스하는 서버입장에서는 실제 클라이언트 IP를 알 수가 없다.

(HTTP프로토콜에 한해서는 Header에 실제IP를 기입할 수 있다)

그렇게 때문에 필요한 경우 transparent 기능을 이용해야 한다.

보통은...

INTERNET ------- (외부망)haproxy(내부망, default gateway역할) ------ Servers

이런식으로 haproxy가 게이트웨이에서 동작할텐데 나는

INTERNET ----- GATEWAY(내부망) ----------  haproxy + 로컬서버
                                   +----- Servers

이런 식이다.

이런 경우 transparent가 동작하지 않게 된다.

일단 transparent의 원리는 이렇다.. (잘 몰라서 패킷 뜯어보고 별 삽질을..ㅠㅠ)

  1. haproxy가 원하는 포트로 LISTEN을 하고 있다.

  2. 외부클라이언트가 haproxy에 연결된다.

  3. haproxy는 일치하는 backend에 연결한다.

    * 이 때 bind socket의 주소를 외부클라이언트주소로 바꾸고 backend에 연결을 시도한다.

  4. (보통의 경우) 바뀐 source ip 의 패킷이 backend에 전송된다.

  5. backend에서 해당 패킷을 처리 한 후 source ip를 destination ip로 해서 결과를 전송한다. (기본적인 통신구조)

  6. haproxy가 게이트웨이에 있기 때문에 5번의 패킷은 자연스럽게 haproxy가 다시 받을 수 있다.

  7. haproxy는 받은 패킷을 다시 외부클라이언트로 전송한다.

그런데 나는 haproxy와 동일한 서버에 있는 backend에 접속하려고 했더니 netstat에는

haproxy to backend : SYN_SENT
backend to haproxy : SYN_RECV

이 상태로 멈춰있었다. tcpdump로 보니까...

haproxy -> backend : lo (Loopback)으로 통신하고
backend -> haproxy 으로 가야할 것은 : ens32 (default gateway설정된 NIC)로 보내어 외부 인터넷 어디론가로 보내고 있었다. 이러니 안될수밖에...

이러한 상황에서는

iptables -t mangle -N DIVERT # 이건 기본
iptables -t mangle -A PREROUTING -p tcp -m socket -j DIVERT # 이건 기본
iptables -t mangle -A OUTPUT -s 127.0.0.1/32 -p tcp -m tcp --sport 1234 -j DIVERT # 추가된것!
iptables -t mangle -A DIVERT -j MARK --set-xmark 0x1 # 이건 기본
iptables -t mangle -A DIVERT -j ACCEPT # 이건 기본

# 추가로 ip rule 추가해야 하는데 그건 기본 haproxy 메뉴얼에 있음

이렇게 iptables mangle의 OUTPUT필터에서 패킷을 mark해서 밖이 아닌 haproxy으로 되돌아 가도록 하면 된다.

하지만 haproxy -> 같은 내부 네트워크 서버 인 경우에는???

이런 transparent는 불가능하다.. haproxy에 의해 바뀐 src ip를 받은 backend는 그게 haproxy가 준건지 외부에서 온건지 알 수 없기 때문에..

이런 경우는 그냥 http header를 이용해서 client ip를 같이 보내주는 수밖엔 없다.

반응형

댓글