Linux,Unix,BSD

LB, Proxy 등에서 전달된 Client IP 처리하기 ; Apache, PHP

채윤아빠 2019. 6. 8. 20:17
728x90
반응형



로드밸런서(LB), 프록시(Proxy) 사용시, Client IP 문제

아파치 웹서버 앞단에 HA 등을 위하여 로드밸런서(LB)나 프록시(Proxy)를 두는 경우 Client IP를 처리할 때 주의할 점이 있습니다.
아파치 웹서버 앞단에 로드밸런서(LB)나 프록시(Proxy)가 있는 경우, 로그 등에 기록되는 Client IP는 로드밸런서(LB)나 프록시(Proxy)의 IP가 됩니다. 이는 클라이언트와 웹서버 중간에서 클라이언트의 역할을 대리하여 처리하기 때문에 당연하다면 당연한 결과입니다. 대신 로드밸런서(LB)나 프록시(Proxy)에서 원래 요청한 Client의 IP를 전달하기 위하여 뒷단 웹 서버에 "X-Forwarded-For"라는 헤더를 이용하여 최초 요청한 Client의 IP를 전달합니다.

하지만, "X-Forwarded-For" 헤더 자체가 RFC 등의 표준이 아니기 때문에, 다른 플랫폼에서는 전혀 다른 헤더를 사용하기도 합니다. (예를 들면, WebLogic Connector(mod_wl)는 WL-Proxy-Client-IP 나 Proxy-Client-IP 같은 헤더를 사용합니다.)

다음은 앞단에 HAProxy가 운영되고 있는 아파치 웹에서 기록되는 로그 예시입니다.

192.168.56.203 - - [05/Jun/2019:11:09:11 +0000] "POST /admin_user_id HTTP/1.1" 500 2052 "http://homeadmin.kernelsbuilder.com/login" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36" 
192.168.56.203 - - [05/Jun/2019:11:09:11 +0000] "POST /admin_user_id HTTP/1.1" 500 2052 "http://homeadmin.kernelsbuilder.com/login" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36" 
192.168.56.203 - - [05/Jun/2019:11:09:12 +0000] "POST /admin_user_id HTTP/1.1" 500 2052 "http://homeadmin.kernelsbuilder.com/login" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36" 
192.168.56.203 - - [05/Jun/2019:11:09:13 +0000] "POST /admin_user_id HTTP/1.1" 500 2052 "http://homeadmin.kernelsbuilder.com/login" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36" 

HAProxy가 운영되고 있는 서버의 IP가 "192.168.56.203"으로, 모든 클라이언트의 요청이 프록시 서버의 IP로 기록되기 때문에, IP를 통한 지역별 통계(Geo-IP) 등은 전혀 활용할 수가 없게 됩니다.


HAProxy + Apache 클라이언트 IP 처리하기

HAProxy를 예를 들면, 로드 밸런싱 처리하는 웹서버들이 있는 백엔드에 "X-Forwarded-For" 헤더를 전달하기 위해서는 "haproxy.cfg"에서 "defualt"에 "option forwardfor"를 추가해 주면 됩니다.

$ vi /etc/haproxy/haproxy.cfg
defaults
    mode                    http
    log                     global
    option                  forwardfor
    option                  httplog

이후 haproxy 서비스를 재시작합니다.

아파치에서는 LogFormat을 다음과 같이 수정합니다.

$ vi /etc/httpd/conf/httpd.conf

LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" proxy
SetEnvIf X-Forwarded-For "^.*\..*\..*\..*" forwarded
CustomLog "|/usr/sbin/rotatelogs /app/weblogs/access_log.%Y%m%d 86400 +540" combined env=!forwarded
CustomLog "|/usr/sbin/rotatelogs /app/weblogs/access_log.%Y%m%d 86400 +540" proxy env=forwarded

combined 포맷은 "X-Forwarded-For" 헤더가 없는 일반적인 클라이언트의 요청을 저장할 로그 포맷이고, proxy는 HAProxy에서 전달받은 요청으로 "X-Forwarded-For" 헤더가 있을 경우, Client IP를 "X-Forwarded-For" 헤더 값으로 입력하도록 하고 있습니다.

아파치 설정을 마무리한 후에 아파치를 재시작하면, 프록시에서 전달되는 요청들은 "X-Forwarded-For" 헤더 값으로 ClientIP가 제대로 저장되는 것을 확인할 수 있습니다.

::ffff:10.103.20.61 - - [05/Jun/2019:00:25:51 +0000] "GET /i.php HTTP/1.1" 200 93705 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/17.17134" 
::ffff:10.103.20.61 - - [05/Jun/2019:01:24:07 +0000] "GET /i.php HTTP/1.1" 200 93509 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/17.17134" 

HAProxy + Apache + PHP에서 클라이언트 IP 처리하기

PHP에서 "X-Forwarded-For" 헤더는 "HTTP_X_FORWARDED_FOR" 환경 변수에 정보가 전달됩니다.
다음과 같이 처리하면, HAProxy에 최초 요청한 클라이언트의 IP를 얻을 수 있습니다.

if (isset($_SERVER["HTTP_X_FORWARDED_FOR"])) {
    $client_ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
}
else {
    $client_ip = $_SERVER["REMOTE_ADDR"];
}

참고자료