클라이언트 IP 정보가 필요한 이유
오늘날 많은 기업들이 클라우드 환경으로 자신의 인프라 환경을 이전하거나 이전을 고민하고 있다.
오늘은 인프라 환경 이전에 고려할 만한 내용인 로드밸런서와 사용자 IP 확인에 대한 이야기를 해본다.
온프레미스 환경에서 로드밸런서의 역할은 매우 중요했다.
로드밸런서는 서버의 트래픽 분산을 통해 많은 사용자들의 접속을 가능케 했으며, 다양한 분산 기능과 분산 알고리즘을 통해 보안 제품들을 인프라에 효과적으로 적용하였다.
클라우드 환경에서 역시 로드밸런서의 역할은 중요한 기능 중의 하나이며, 대부분의 CSP (Cloud Service Provider) 는 이를 기본 서비스로 제공한다.
하지만 클라우드 환경에서 제공하는 로드밸런서는 온프레미스 환경의 로드밸런서와 약간 차이가 있다. 프록시 기술을 기반으로 제공하다 보니 로드밸런서를 통해 서버로 유입되는 트래픽에서 사용자의 IP 나 포트 정보를 추출하기가 힘들어졌다.
로드밸런서를 거치면 사용자 IP 가 로드밸런서 자체 IP로 변경되기 때문이다.
애플리케이션 서버, 그리고 서버로 전달되기 전 경유하는 보안 제품들 입장에서 사용자 IP 정보는 중요하다.
클라이언트 IP 정보를 추출하는 방법
이제 클라우드 환경에서 사용자 정보를 얻는 방법에 대해 본격적으로 이야기 해 보자.
사용자 IP 정보 추출의 어려움이 클라우드 환경에서 가지는 특징이라고 하지만, 그렇다면 사용자 정보를 얻을 수 있는 방법은 없을까?
당연히 이런 고민들을 많은 사람들이 했고 이에 대한 방안 역시 준비가 되어 있다.
방법부터 말하자면 아래와 같이 3 가지가 있다.
X-Forwarded-For
Forwarded
Proxy Protocol
참고로 아래 테스트 환경은 다음과 그림과 같다.
X-Frowarded-For
먼저 X-Forwarded-For 부터 알아보자.
XFF 라고 불리는 이 방법은 HTTP 요청 헤더에 사용자 정보를 담아 보내는 방법이다.
Squid 라고 하는 오픈 소스 프록시 제품에서 먼저 사용한 방법인데 이 무료 제품이 너무 유명해 지다 보니 자연스레 XFF가 널리 사용된 케이스 이다.
하지만, 표준처럼 인식되고 있는 이 XFF 헤더는 공교롭게도 표준이 아니다.
필자는 2000년 중반 직장 생활의 시작을 INKTOMI(잉크토미) 라고 하는 프록시 서버의 일종인 캐시서버 제품을 지원하는 엔지니어였다보니 XFF 를 아주 잘 알고 있었으나 표준으로 알고 있는 분들이 의외로 많이 있는 것 같다.
XFF 는 프록시가 실제 애플리케이션 서버와 TCP 세션 수립 이후 HTTP 요청을 보낼 때 X-Forwarded-For 라는 헤더에 실제 사용자 IP 정보를 담아 전달한다.
헤더는 아래와 같이 다중 값을 가질 수 있다.
X-Forwarded-For: client, proxy1, proxy2
프록시 서버를 거치는 순서대로 Value 가 추가되니 제일 처음의 IP 정보를 실제 사용자 정보로 보면 된다. 다른 의미로는 제일 마지막 Value 는 애플리케이션 서버와 가장 가까운 위치에 있는 프록시로 해석할 수도 있겠다.
[ Wireshark 패킷 내용을 Stream 조합한 내용 ]
애플리케이션 서버에서는 IP 헤더의 소스 IP 정보 대신 XFF 헤더 정보를 파싱하여 접속 내용을 기록하면 된다.
Forwarded
Forwarded 헤더는 위에서 설명한 XFF 의 Standard 버젼으로 보면 된다.
XFF 와 같이 콤마(,) 로 분리된 다중 값을 가질수 있다.
Forwarded: for=client, for=proxy1, for=proxy2
헤더의 구조는 XFF 와 거의 비슷하기 때문에 따로 설명을 자세히 하진 않는다.
XFF와 비슷해서이기도 하지만, 실제 현장에서 XFF 가 99.9% 로 사용되기 때문이다.
Proxy Protocol
위에서 설명했던 XFF 와 Fowraded 헤더는 HTTP 헤더의 한 종류이다. 다시 말해서 HTTP 기반의 서비스여야만 프록시를 통한 접속에서 사용자 정보를 확인할 수 있다.
그럼 HTTP 서비스가 아니라면 사용자 정보를 확인 할 수 있는 방법이 없을까?
이를 해결해 줄 수 있는 것이 바로 Proxy Protocol 이다.
프록시 프로토콜은 TCP 기반에서 사용되는 옵션이라 TCP 기반의 어느 서비스에서나 이를 이용하여 사용자 정보를 확인 할 수 있다.
Proxy Protocol 의 포맷은 아래와 같다.
PROXY <protocol> <srcip> <dstip> <srcport> <dstport>\r\n
실제 패킷에서 내용을 확인하면 아래와 같은데, HTTP 요청헤더가 전달되기 전에 Proxy Protocol 이 선행 됨을 확인할 수 있다.
[ Wireshark 패킷 내용을 Stream 조합한 내용 ]
상황별 웹서버 Access 로그 내용
아래는 nginx 웹서버의 접근로그(access.log) 포맷이다.
사용자 IP($remote_addr), XFF 정보 ($http_x_forwarded_for), Proxy Protocol 정보 ($proxy_protocol_addr) 정보 순으로 IP 정보를 남기게 로그 포맷을 수정하였다.
상황 1. 클라이언트가 직접 웹서버로 접속한 경우
- 사용자 IP : 192.168.212.180
[ 웹서버의 Access 로그 ]
상황 2. 클라이언트 정보 전달 관련련 어떤 설정도 하지 않은 경우
- 프록시 IP : 172.16.1.115
[ 웹서버의 Access 로그 ]
상황 3. XFF 설정을 한 경우
- 사용자 IP : 192.168.212.180,
- 프록시 IP : ;172.16.1.115
[ 웹서버의 Access 로그 ]
상황 4. XFF 와 Proxy Protocol 설정을 한 경우
- 사용자 IP : 192.168.212.180,
- 프록시 IP : ;172.16.1.115
프록시가 XFF 와 Proxy Protocol 을 모두 제공하는 경우이다. 웹서버의 접근로그에서 설정한 것과 같이 IP 헤더의 소스 IP, XFF 정보, Proxy Protocol 정보 순으로 기록되어 있는 것을 확인할 수 있다.
[ 웹서버의 Access 로그 ]
끝~