캡스톤 디자인 회고 - Nginx 설정 및 Backend 주소 노출 해결

최수환·2023년 6월 19일
1

캡스톤 디자인

목록 보기
4/5
post-thumbnail

Nginx 설정

Frontend를 배포하기 위한 웹 서버로 Nginx를 사용했다.

  • Nginx는 프록시 역할을 수행하는데 프록시에 대한 설명은 해당 블로그 에 포스팅 해두었다.
  • Nginx가 프록시 역할을 수행하기 위해서는 Nginx.conf 파일이라는 환경변수 설정 파일에 동적요청에 대한 api호출을 전달할 Backend 주소를 정의해야 한다.

잘못된 Nginx 설정

<Frontend의 음식사진을 검색하는 api 호출 코드>

const BACKEND_URL =
      "http://k8s-default-backendi-feb8c9a7e2-53368050.ap-northeast-2.elb.amazonaws.com/search/food";
  • Ingress(=ALB)로 노출시킨 Backend 서버의 주소를 그대로 작성해주었다.

<Nginx.conf>

location / {
    proxy_pass http://k8s-default-backendi-feb8c9a7e2-53368050.ap-northeast-2.elb.amazonaws.com/;
    proxy_buffer_size   128k;
    proxy_buffers       4 256k;
    proxy_busy_buffers_size 256k;
  }
  • location에는 루트 경로로 설정해주었고, proxy_pass에는 Ingress로 노출시킨 Backend 서버의 주소를 작성해주었다.

원래 나의 계획은 사용자가 정적 페이지를 보다가 클릭과 같은 동적 요청을 하면, 요청에 해당하는 경로로 Frontend가 api호출을 하고 Nginx가 이 api호출을 받아서 Backend에 전달해주는 것이였다.

하지만 위의 Nginx설정은 프록시 역할을 제데로 수행하는 것일까 라는 의문이 생겼다.

  • 위의 코드대로라면 Frontend가 Backend 서버로 직접 api 호출하게 된다. 즉, Nginx는 어떠한 요청도 받지 못하기 때문에 프록시 역할을 수행하기는 커녕 없는 것과 마찬가지인 것이다.
  • 또한 Backend서버의 주소를 그대로 노출시켜놨기 때문에 보안에도 좋지 않다.

옳은 Nginx 설정

❓ 그렇다면 어떻게 Backend 서버를 노출하지 않으면서 Nginx에 api요청을 보내 Nginx가 프록시 역할을 수행하게 할 수 있을까?

<Frontend 코드 수정>

const BACKEND_URL =
  "/api/search/food";
  • Frontend가 특정 api를 호출할 때 Backend서버 주소 대신 /api/ 라는 경로 로 호출한다.

<Nginx.conf 코드 수정>

location /api/ {
    proxy_pass http://k8s-default-backendi-feb8c9a7e2-53368050.ap-northeast-2.elb.amazonaws.com/;
    proxy_buffer_size   128k;
    proxy_buffers       4 256k;
    proxy_busy_buffers_size 256k;
  }
  • Nginx에서는 /api/ 경로로 온 api호출을 받을 수 있게 location에 /api/ 를 선언해준다.

  • 이때 Nginx에 도착한 api호출은 /api/search/food와 같이 /api/ 경로 뒤에 세부 경로가 존재하기 때문에 /api/로 선언해야 한다.

    	/api # 이런식으로 선언하면 안된다.

Backend 주소 노출 해결

Nginx.conf 파일의 proxy_pass에 Backend 서버 주소를 적어주기 위해 Ingress(=ALB) 로 노출된 Backend 주소를 적어주었다고 하였다.

  • 즉 Nginx는 Frontend로 부터 온 api호출을 해당 Backend Ingress(=ALB) 에 전달하는 것이다.

❓ 여기서 또 하나의 의문점이 생겼다.

  • Backend를 Ingress(=ALB) 로 외부에 노출시키면 /api로 Backend주소를 가린 의미가 없게 되는게 아닐까.

현재 Backend는 Deployment에 의해 파드로 띄워진 상태이고 NodePort 타입 서비스 리소스가 중간에서 프록시 역할을 하고 있다. 이것을 외부에 노출시키기 위해 Ingress를 사용한 것이다.

  • 따라서 내부에서 프록시 역할을 하는 서비스 리소스의 주소에 전달해준다면 보안에 더 좋을 것 같았다.

<Nginx.conf 코드 수정>

location /api/ {
    proxy_pass http://backend-service.default.svc.cluster.local/;
    proxy_buffer_size   128k;
    proxy_buffers       4 256k;
    proxy_busy_buffers_size 256k;
  }
  • 따라서 proxy_pass에 Backend의 Ingress주소가 아닌 Service 리소스의 주소를 선언해주었다.
  • Service 주소는 '서비스이름.default.svc.cluster.local' 이다.

❓ 그렇다면 보안을 위해 아예 Backend는 Ingress(=ALB)로 노출시킬 필요가 없는지 생각이 들었다.

  • 프론트 개발을 담당하는 팀원에게 물어보니 Production모드와 Development모드가 있는데 이것을 환경변수로 관리한다고 했다.
  • Production 모드에서는 Backend 주소가 노출되면 안되니 루트경로를 /api로 설정하고 Nginx가 프록시 역할을 하며 Backend 내부 서비스에 전달 할 수 있게 한다.
  • 이때 npm start한 환경인 Development모드 에서는 Ingress를 통해 노출된 경로를 그대로 사용해서 Nginx를 굳이 거치지 않고 로컬에서도 Backend 서버에 직접 접근할 수 있도록 하는게 테스트하기 더 편하다고 했다. (아래 예시)
const BACKEND_URL =
  "http://k8s-default-backendi-feb8c9a7e2-53368050.ap-northeast-2.elb.amazonaws.com/search/food";
  # Development모드에서 Frontend의 api호출 코드
  • Backend 주소를 적어주어 Frontend가 로컬에서 Backend api를 직접 호출 가능하게 함

📒 결론적으로 외부로 노출된 Backend 주소를 갖고 있어야 개발 단계에서 테스트하기 더 편리할 것 같다.

<Nignx.conf 파일 전체 코드>

server {
  listen 80;
  client_max_body_size 5M;
  server_name _;

  location /api/ {
    proxy_pass http://backend-service.default.svc.cluster.local/;
    proxy_buffer_size   128k;
    proxy_buffers       4 256k;
    proxy_busy_buffers_size 256k;
  }

  location / {
    root /usr/share/nginx/html/;
    index index.html;
    error_page 405 =200 $uri;
    try_files $uri $uri/ /index.html;
  }
}

환경변수로 모드 관리하기

위에서 Production 모드와 Development 모드가 존재한다고 했다.

  • Production 모드에서 /api 경로로 Nginx에 요청을 전달하고, Development 모드에서는 노출된 Backend주소에 직접 요청을 보낸다.
const BACKEND_URL = "주소"
  • 따라서 매번 빌드할 때마다 모드에 따라 위의 코드에 주소를 다르게 입력해주어야 한다는 것은 비효율적이다.

<각 모드에 대한 환경변수 파일 만들기>

  • Dev모드에서 사용할 Backend 주소와 Production모드에서 사용할 /api를 각각 선언해준다.

이후 URL을 불러오는 코드를 아래와 같이 바꿔준다.

process.env.BACKEND_URL

이제 모드에 따라 일일이 코드를 수정할 필요 없이 빌드 명령어로 구분이 가능해진다. (아래 예시)

npm run build # .env.production 파일의 BACKEND_URL 호출

npm run dev # .env.development 파일의 BACKEND_URL 호출 

마치며

  • 이전 프로젝트에서 Nginx를 자세히 알지 못하고 사용한 것 같다. 캡스톤 디자인을 통해 Nginx의 정확한 역할에 대해서 알게 되었다.
  • 또한 단순히 배포하는 것이 중요한 것이 아니라 안전하고 신뢰성 있는 배포 또한 중요하다는 것을 깨달았다.
profile
성실하게 열심히!

0개의 댓글