(컴파일 없이) nginx에서 환경 변수 불러오기

요약

lua 모듈 쓰면 겁나 편하지만, 사정상 사용할 수 없다면 셸 스크립트 방식도 고려해보자.

상황

  1. nginx에서 특정 url에 대해 ip를 제한해야 하는데, ip 설정을 동적으로 하고 싶었다. (하지만 db 설정 없이)
  2. nginx에서 환경 변수를 읽어들이는 방법을 찾아보니 perl 모듈이나 lua 모듈을 사용하라는데, nginx를 직접 컴파일해야 한다는 점이 걸렸다. (컴파일 공포증)

아무것도 컴파일하지 않고, 추가로 설치하는 일도 없이 할 수는 없을까?를 고민하다가 최근 재미 들린 셸 스크립트를 활용해보기로 했다.

서비스는 docker 이미지로 만들어져, aws의 ECS에 올라가 있다.

1. ip로 url 접근 제한하기

/admin/ url에 대해서 특정 ip만 접근하도록 해보자.

먼저 nginx.conf의 /admin 부분에 주석문(# admin_ip_whitelist)을 하나 추가했다.

# nginx.conf
...
# 로드 밸런서를 사용하는 경우 이 부분들이 필요하다.
set_real_ip_from   172.17.0.0/16;  # 로드 밸런서의 ip 대역을 넣어준다.  
real_ip_header     X-Forwarded-For;  
...
# 로드 밸런서가 없다면 아래 부분만 있어도 된다.
location /admin {  
    uwsgi_pass unix:///var/run/default-uwsgi.sock;
    include uwsgi_params;
    # admin_ip_whitelist
}
...

그 다음 docker 이미지의 CMD 부분에 셸 스크립트를 넣는다.

# Dockerfile
...
ADD    ./run.sh /  
CMD    /run.sh  

이제 run.sh 파일을 작성한다.

#!/bin/bash

if [ -n "$IP_WHITELIST_FOR_ADMIN" ]; then  
    IP_WHITELIST="allow ${IP_WHITELIST_FOR_ADMIN};\n"
    IP_WHITELIST+="deny all;"

    sed -i "s@# admin_ip_whitelist@${IP_WHITELIST}@g" /etc/nginx/nginx.conf
fi

supervisord -n  # 이건 원래 Dockerfile의 CMD 부분에서 실행하던 명령어  

이제 ECS의 Task Definition에서 IP_WHITE_LIST_FOR_ADMIN 환경변수를 추가하면 해당 IP만 /admin에 접근할 수 있다.

2. ELB의 vpc 대역으로 특정 url 접근 제한하기

이번에는 /api/special에 대해 같은 vpc 내부의 요청만 허용해보자. (1번 작업을 해두었다고 가정한다.)

nginx.conf의 /api/special 부분에 주석문(# vpc_ip_range)을 추가한다.

location /api/special {  
    uwsgi_pass unix:///var/run/default-uwsgi.sock;
    include uwsgi_params;
    # vpc_ip_range
}

그리고 run.sh에 다음 내용을 추가한다.

# run.sh
...
if [ -n "WRITE_API_ACCESS_ONLY_VPC" ]; then  
    # 서버의 IP 네트워크 내역을 검출하는 방법.
    # 주의! 네트워크가 여럿인 경우엔 결과 값도 여러 개로 나오므로, 이를 배열에 저장하여 사용해야 함
    VPC_SUBNET_MASK=`ip -o -f inet addr show | awk '/scope global/ {print $4}'`

    VPC_IP_RANGE="allow ${VPC_SUBNET_MASK};\n"
    VPC_IP_RANGE="deny all;"

    sed -i "s@# vpc_ip_range@${VPC_IP_RANGE}@g" /etc/nginx/nginx.conf
fi  
...

이제 ECS의 Task Definition에서 WRITE_API_ACCESS_ONLY_VPC 값을 설정하면(어떤 값으로든), /api/special이라는 경로는 VPC 내부에서만 접근할 수 있게 된다.

배운 점

  1. shell script를 좀더 제대로 배워보고 싶어졌다. 알면 알수록 활용성이 올라갈 듯.

  2. sed 같은 유닉스 기본 명령도 많이 알아보자.

  3. docker와 환경 변수 독립이라는 개념이 유닉스나 시스템 엔지니어링에 익숙하지 않은 사람(=나)에게 큰 도움이 되는 듯.