반응형

이번에 특정 클라이언트의 요청을 타 도메인을 꺾는 테스트가 필요하여 진행한 내용을 정리한다.

 

환경은 3scale를 사용하기때문에 staging/product 2개의 도메인이 존재한다.

그래서 특정 클라이언트 1.1.1.1 ip가 들어오면 staging도메인으로 강제로 꺾어주는 테스트를 진행한다.

 

네트워크 구간은 대충 아래와 같다.

[데이터요청서버] -> [아웃바운드프록시] -> [L7 Layer] -> [L4 Layer] -> [인바운드프록시] -> [3scale] -> [백엔드서버]

proxy 구간이 존재하기 때문에 remote_ip 가 아닌 x-forwarded-for 를 사용해 클라이언트의 ip를 체크해야한다. 

(remote_ip 는 바로 전 라우터의 ip가 나오기 때문)

 

nginx.conf 설정

map

예전에 map 을 써서 특정 문자를 변수에 담는 작업을 한적이 있어,

이번에도 위에서말한 x-forwarded-for 변수의 값을 체크하도록 설정했다.

(map은 http 블럭안에 작성했다.)

    map $http_x_forwarded_for $client_check {
        default off;
        1.1.1.1 on;
    }

이러면 헤더로 넘어온 x-forwarded-for 값이 1.1.1.1 일때만, $client_check  변수에 on 이라는 데이터를 담게 된다.

 

upstream

이제 proxy pass를 해줄 도메인 서버를 정의하자.

(upstream도 http 블록안에 위치한다.)

  upstream stg {
    server localhost; # 스테이징 url
  }
  upstream prod {
    server localhost; # 프로덕트 url
  }

필자는 개인pc에서 테스트를 하고 있으므로 위와 같이 설정하였다.

각자 스테이징/프로덕트 url을 분리해서 작성하면된다.

 

proxy pass

이제 위에서 정의한 서버정보와 변수를 이용하여 도메인을 구분하자.

/ : 루트패스로 접근할 때를 예를 들어 설정하였고, 

local pc 에서 테스트하기 때문에 /a, /b 로 컨텍스트를 나눠주었다.

    location / {
      if ( $client_check = on ){
        proxy_pass http://stg/b$uri;
      }
      if ( $client_check = off ){
        proxy_pass http://prod/a$uri;
      }
    }

$uri 를 사용하면 최초에 요청한 경로를 보존할 수 있다.

 

컨텍스트 분리(이건 다 아는 걸테니 접은글로)

더보기
        location /a {
            return 200 'a';
        }
        location /b {
            return 200 'b';
        }

 

테스트

자 이제 설정을 기반으로 요청을 해보자.

x-forwarded-for 조건에 걸리지 않은 경우
x-forwarded-for 조건에 걸렸을 경우

위 이미지와 같이 잘 분리가 되었다.

 

access log 도 확인해보면 요청한 url에 정상적으로 요청한 내역이 남아있다.

127.0.0.1 -JH- - [28/Sep/2022:14:01:01 +0900] "GET /b/v1/card/card/12312312 HTTP/1.0" 200 1 "-" - "PostmanRuntime/7.29.2" "1.1.1.1"
127.0.0.1 -JH- - [28/Sep/2022:14:01:01 +0900] "GET /v1/card/card/12312312 HTTP/1.1" 200 1 "-" - "PostmanRuntime/7.29.2" "1.1.1.1"
127.0.0.1 -JH- - [28/Sep/2022:14:01:08 +0900] "GET /a/v1/card/card/12312312 HTTP/1.0" 200 1 "-" - "PostmanRuntime/7.29.2" "1.1.1.2"
127.0.0.1 -JH- - [28/Sep/2022:14:01:08 +0900] "GET /v1/card/card/12312312 HTTP/1.1" 200 1 "-" - "PostmanRuntime/7.29.2" "1.1.1.2"

access log 맨 뒤에 출력된 ip가 x-forwarded-for 값이다.

궁금해할 사람들 위해 아래에 설정을 남겨놓겠다.

    log_format  main  '$remote_addr -JH- $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '$http_code "$http_user_agent" "$http_x_forwarded_for"';

 

만약 프록시패스가 route 서버라면

추가적인 세팅사항이 있어 작성한다.

upstream stg/prod 를 작성하였는데, 만약 back단의 route 서버로 전달한다면

뒤에 route서버가 인식할 수 있는 Host를 지정해주어야한다.

 

Host 값은 기본적으로 클라이언트가 요청한 domain이 들어가는데,

 예를들면 https://test.domain.com/v1/card/card로 호출 했을 경우 Host: test.domain.com

이라는 데이터가 들어가 있게 된다.

 

이상태로 route 서버에 전달을 하면 Header 데이터중 'Host' 를 찾아 또 다른 back 서버로 전달하게 된다. 

그럼 이 Host를 stg url로 교체해주면  라우트에서 인식하게 된다.

 

# route서버에 연결할 경우의 upstream 예시

더보기
    upstream route {
        server route1.apps.com;
        server route2.apps.com;
        server route3.apps.com;
    }

 

conf를 수정해보자.

new_host 라는 변수를 생성해 특정 도메인으로 지정한 뒤 proxy_set_header host 값을 변경하였다.

location / {
   if ( $client_check = on ){
      set $new_host 'joon95.tistory.ccc';
   }
   if ( $client_check = off ){
      set $new_host $host;
   }
   proxy_pass          http://route$uri;
   proxy_set_header    Host            $new_host;
}

호출해보면 Host 데이터가 정상적으로 들어간 걸 볼 수 있다.

127.0.0.1 -JH- - [28/Sep/2022:16:31:00 +0900] "GET /b/v1/card/card/12312312 HTTP/1.0" 200 1 "-" Host: joon95.tistory.ccc - "PostmanRuntime/7.29.2" "1.1.1.1"
127.0.0.1 -JH- - [28/Sep/2022:16:31:00 +0900] "GET /v1/card/card/12312312 HTTP/1.1" 200 1 "-" Host: localhost - "PostmanRuntime/7.29.2" "1.1.1.1"

127.0.0.1 -JH- - [28/Sep/2022:16:31:08 +0900] "GET /a/v1/card/card/12312312 HTTP/1.0" 200 1 "-" Host: localhost - "PostmanRuntime/7.29.2" "1.1.1.2"
127.0.0.1 -JH- - [28/Sep/2022:16:31:08 +0900] "GET /v1/card/card/12312312 HTTP/1.1" 200 1 "-" Host: localhost - "PostmanRuntime/7.29.2" "1.1.1.2"

 

 

긴 글 읽어주셔서 감사합니다.

반응형
복사했습니다!