블로그 | NGINX

API 게이트웨이로 NGINX 배포, 1부

NGINX-F5-수평-검정-유형-RGB의 일부
리엄 크릴리 썸네일
리암 크릴리
2021년 1월 20일 게시

이는 NGINX 오픈 소스 및 NGINX Plus를 API 게이트웨이로 배포하는 방법에 대한 시리즈의 첫 번째 블로그 게시물입니다.

  • 이 게시물에서는 여러 사용 사례에 대한 자세한 구성 지침을 제공합니다. 원래 2018년에 출판되었으며 중첩된 API 구성을 사용하여 최신 모범 사례를 반영하도록 업데이트되었습니다. 위치 규칙을 다시 작성하는 대신 요청을 라우팅하는 블록을 사용합니다.
  • 2부에서는 이러한 사용 사례를 확장하여 프로덕션 환경에서 백엔드 API 서비스를 보호하고 보안하는 데 적용할 수 있는 다양한 보안 장치를 살펴봅니다.
  • 3부에서는 NGINX 오픈 소스와 NGINX Plus를 gRPC 서비스에 대한 API 게이트웨이로 배포하는 방법을 설명합니다.

메모 : 별도로 명시된 경우를 제외하고 이 게시물의 모든 정보는 NGINX 오픈 소스와 NGINX Plus에 모두 적용됩니다. 읽기 편하도록 블로그의 나머지 부분에서는 간단히 "NGINX"라고 언급합니다.

현대적 애플리케이션 아키텍처의 핵심은 HTTP API입니다. HTTP는 애플리케이션을 빠르게 빌드하고 쉽게 유지 관리할 수 있게 해줍니다. HTTP API는 단일 목적의 마이크로서비스에서 모든 것을 포괄하는 모놀리스에 이르기까지 애플리케이션의 규모에 관계없이 공통적인 인터페이스를 제공합니다. HTTP를 사용하면 하이퍼스케일 인터넷 속성을 지원하는 웹 애플리케이션 전송의 발전을 활용하여 안정적이고 고성능 API 전송을 제공할 수도 있습니다.

마이크로서비스 애플리케이션을 위한 API 게이트웨이의 중요성에 대한 훌륭한 소개는 마이크로서비스 구축을 참조하세요. API 게이트웨이 사용 우리의 블로그에서.

NGINX는 업계를 선도하는 고성능, 경량 역방향 프록시 및 부하 분산 장치로서 API 트래픽을 처리하는 데 필요한 고급 HTTP 처리 기능을 갖추고 있습니다. 이로 인해 NGINX는 API 게이트웨이를 구축하는 데 이상적인 플랫폼이 됩니다. 이 블로그 게시물에서는 여러 가지 일반적인 API 게이트웨이 사용 사례를 설명하고, 이를 효율적이고 확장 가능하며 유지 관리가 쉬운 방식으로 처리하도록 NGINX를 구성하는 방법을 보여줍니다. 우리는 프로덕션 배포의 기반을 형성할 수 있는 완전한 구성을 설명합니다.

창고 API 소개

API 게이트웨이의 주요 기능은 백엔드에서 구현 또는 배포되는 방식에 관계없이 여러 API에 대한 단일하고 일관된 진입점을 제공하는 것입니다. 모든 API가 마이크로서비스 애플리케이션은 아닙니다. API 게이트웨이는 기존 API, 모놀리스, 부분적으로 마이크로서비스로 전환되는 애플리케이션을 관리해야 합니다.

이 블로그 게시물에서는 재고 관리를 위한 가상 API인 "창고 API"에 대해 언급합니다. 다양한 사용 사례를 설명하기 위해 샘플 구성 코드를 사용합니다. Warehouse API는 JSON 요청을 사용하고 JSON 응답을 생성하는 RESTful API입니다. 그러나 API 게이트웨이로 배포할 때 JSON을 사용하는 것은 NGINX의 제한이나 요구 사항이 아닙니다. NGINX는 API 자체에서 사용하는 아키텍처 스타일과 데이터 형식에 구애받지 않습니다.

Warehouse API는 개별 마이크로서비스의 컬렉션으로 구현되고 단일 API로 게시됩니다. 인벤토리 및 가격 책정 리소스는 별도의 서비스로 구현되고 다른 백엔드에 배포됩니다. 따라서 API의 경로 구조는 다음과 같습니다.    

api
└── 창고
├── 재고
└── 가격

예를 들어, 현재 창고 재고를 쿼리하려면 클라이언트 애플리케이션이 /api/warehouse/inventory 에 HTTP GET 요청을 만듭니다.

다중 애플리케이션을 위한 API 게이트웨이 아키텍처

NGINX 구성 구성

NGINX를 API 게이트웨이로 사용하는 한 가지 장점은 기존 HTTP 트래픽에 대한 역방향 프록시, 부하 분산 장치 및 웹 서버 역할을 동시에 수행하면서 해당 역할을 수행할 수 있다는 것입니다. NGINX가 이미 애플리케이션 전송 스택의 일부인 경우 일반적으로 별도의 API 게이트웨이를 배포할 필요가 없습니다. 그러나 API 게이트웨이에서 기대되는 기본 동작 중 일부는 브라우저 기반 트래픽에서 기대되는 동작과 다릅니다. 이러한 이유로 브라우저 기반 트래픽에 대한 기존(또는 향후) 구성과 API 게이트웨이 구성을 분리합니다.

이러한 분리를 달성하기 위해 다목적 NGINX 인스턴스를 지원하고 CI/CD 파이프라인을 통해 구성 배포를 자동화하기 위한 편리한 구조를 제공하는 구성 레이아웃을 만듭니다. /etc/nginx 의 디렉토리 구조는 다음과 같습니다.

etc/
└── nginx/
├── api_conf.d/ ………………………………… API별 구성을 위한 하위 디렉토리
│ └── warehouse_api.conf …… Warehouse API의 정의 및 정책
├── api_backends.conf ………………… 백엔드 서비스(업스트림)
├── api_gateway.conf …………………… API 게이트웨이 서버를 위한 최상위 구성
├── api_json_errors.conf ………… JSON 형식의 HTTP 오류 응답
├── conf.d/
│ ├── ...
│ └── existing_apps.conf
└── nginx.conf

모든 API 게이트웨이 구성에 대한 디렉토리와 파일 이름에는 api_ 접두사가 붙습니다. 이러한 각 파일과 디렉토리는 아래에서 자세히 설명하는 대로 API 게이트웨이의 다양한 기능이나 성능을 활성화합니다. warehouse_api.conf 파일은 아래에서 설명하는 구성 파일을 대신하는 일반적인 파일로, Warehouse API를 다양한 방식으로 정의합니다.

최상위 API 게이트웨이 정의

모든 NGINX 구성은 기본 구성 파일인 nginx.conf 부터 시작됩니다. API 게이트웨이 구성을 읽으려면 nginx.confhttp 블록에 include 지시문을 추가하여 게이트웨이 구성이 포함된 파일인 api_gateway.conf (바로 아래 28번째 줄)를 참조합니다. 기본 nginx.conf 파일은 include 지시문을 사용하여 conf.d 하위 디렉토리(29번째 줄)에서 브라우저 기반 HTTP 구성을 가져옵니다. 이 블로그 게시물에서는 가독성을 높이고 구성의 일부를 자동화하기 위해 include 지시문을 광범위하게 사용합니다.

 

api_gateway.conf 파일은 NGINX를 클라이언트에 API 게이트웨이로 노출하는 가상 서버를 정의합니다. 이 구성은 API 게이트웨이에서 게시된 모든 API를 단일 진입점 https://api.example.com/(9 번째 줄)에서 노출하고 12~17번째 줄에 구성된 대로 TLS로 보호합니다. 이 구성은 순수하게 HTTPS라는 점에 유의하세요. 일반 텍스트 HTTP 리스너는 없습니다. API 클라이언트는 올바른 진입점을 알고 기본적으로 HTTPS 연결을 설정하기를 기대합니다.

이 구성은 정적으로 의도되었습니다. 즉, 개별 API와 백엔드 서비스의 세부 정보는 20번째 줄의 include 지시문에서 참조하는 파일에 지정됩니다. 23~26번째 줄은 오류 처리를 다루며, 아래의 오류 대응 에서 논의됩니다.

 

단일 서비스 대 마이크로서비스 API 백엔드

일부 API는 단일 백엔드에서 구현될 수 있지만 일반적으로 복원성이나 부하 분산 이유로 두 개 이상이 있을 것으로 예상합니다. 마이크로서비스 API를 사용하면 각 서비스에 대한 개별 백엔드를 정의합니다. 이들은 함께 완전한 API로 기능합니다. 여기에서 Warehouse API는 각각 여러 백엔드가 있는 두 개의 별도 서비스로 배포됩니다.

 

API 게이트웨이가 게시한 모든 API에 대한 모든 백엔드 API 서비스는 api_backends.conf 에 정의되어 있습니다. 여기서는 각 업스트림 블록에서 여러 개의 IP 주소-포트 쌍을 사용하여 API 코드가 배포된 위치를 나타내지만 호스트 이름도 사용할 수 있습니다. NGINX Plus 구독자는 동적 DNS 부하 분산을 활용하여 런타임 구성에 새로운 백엔드가 자동으로 추가되도록 할 수도 있습니다.

창고 API 정의

Warehouse API는 다음 예에서 볼 수 있듯이 중첩된 구성의 여러 위치 블록으로 정의됩니다. 외부 위치 블록( /api/warehouse )은 기본 경로를 식별하며, 이 기본 경로 아래에 중첩된 위치는 백엔드 API 서비스로 라우팅되는 유효한 URI를 지정합니다. 외부 블록을 사용하면 전체 API에 적용되는 공통 정책을 정의할 수 있습니다(이 예에서는 6번째 줄의 로깅 구성).

 

NGINX는 요청 URI를 구성 섹션에 일치시키는 매우 효율적이고 유연한 시스템을 갖추고 있습니다. 위치 지침의 순서는 중요하지 않습니다. 가장 구체적으로 일치하는 항목이 선택됩니다. 여기서 10번째 줄과 14번째 줄의 중첩된 위치는 바깥쪽 위치 블록보다 더 구체적인 두 개의 URI를 정의합니다. 각 중첩된 블록의 proxy_pass 지시문은 요청을 적절한 업스트림 그룹으로 라우팅합니다. 특정 URI에 대해 보다 구체적인 정책을 제공할 필요가 없는 한, 정책 구성은 외부 위치에서 상속됩니다.

중첩된 위치 중 하나와 일치하지 않는 모든 URI는 응답을 반환하는 catch‑all 지시문(18번째 줄)을 포함하는 외부 위치에서 처리됩니다. 404( 찾을 수 없음) 모든 잘못된 URI에 대해.

광범위 vs. API에 대한 정확한 정의

API 정의에는 광범위함과 정밀함의 두 가지 접근 방식이 있습니다. 각 API에 가장 적합한 접근 방식은 API의 보안 요구 사항과 백엔드 서비스에서 잘못된 URI를 처리하는 것이 바람직한지 여부에 따라 달라집니다.

위의 warehouse_api_simple.conf 에서 우리는 Warehouse API에 대한 광범위한 접근 방식을 사용하여 10번째 줄과 14번째 줄에서 URI 접두사를 정의합니다. 이를 통해 접두사 중 하나로 시작하는 URI가 해당 백엔드 서비스로 프록시됩니다. 이 광범위한 접두사 기반 위치 매칭을 통해 다음 URI에 대한 API 요청은 모두 유효합니다.

/api/창고/재고
/api/창고/재고/
/api/창고/재고/foo
/api/창고/인벤토리foo
/api/창고/재고/바/

각 요청을 올바른 백엔드 서비스로 프록시하는 것만 고려하는 경우, 광범위한 접근 방식이 가장 빠른 처리와 가장 컴팩트한 구성을 제공합니다. 반면, 보다 정확한 접근 방식을 사용하면 API 게이트웨이가 사용 가능한 각 API 리소스에 대한 URI 경로를 명시적으로 정의하여 API의 전체 URI 공간을 이해할 수 있습니다. 정확한 접근 방식을 취하면 Warehouse API의 URI 라우팅을 위한 다음 구성은 정확한 일치( = )와 정규 표현식( ~ )을 조합하여 모든 유효한 URI를 정의합니다.

 

이 구성은 더 자세하지만 백엔드 서비스에서 구현하는 리소스를 더 정확하게 설명합니다. 이 방법은 정규 표현식 매칭에 약간의 추가 오버헤드가 발생하는 대신 잘못된 클라이언트 요청으로부터 백엔드 서비스를 보호하는 장점이 있습니다. 이 구성을 적용하면 NGINX는 일부 URI를 허용하고 다른 URI는 유효하지 않은 것으로 거부합니다.

유효한 URI   잘못된 URI
/api/창고/재고   /api/창고/재고/
/api/창고/재고/선반/foo   /api/창고/인벤토리foo
/api/창고/재고/선반/foo/박스/바   /api/창고/재고/선반
/api/창고/재고/선반/-/상자/-   /api/창고/재고/선반/foo/bar
/api/창고/가격/baz   /api/창고/가격
    /api/창고/가격/baz/pub

정확한 API 정의를 사용하면 기존 API 문서 형식을 사용하여 API 게이트웨이 구성을 추진할 수 있습니다. OpenAPI 사양 (이전에는 Swagger라고 함)에서 NGINX API 정의를 자동화하는 것이 가능합니다. 이러한 목적을 위한 샘플 스크립트는 이 블로그 게시물의 Gist에 제공됩니다.

중단 변경을 처리하기 위한 클라이언트 요청 다시 작성

API가 발전함에 따라 엄격한 이전 버전과의 호환성을 깨고 클라이언트를 업데이트해야 하는 변경이 필요할 때가 있습니다. 이러한 예 중 하나는 API 리소스의 이름이 변경되거나 이동되는 경우입니다. 웹 브라우저와 달리 API 게이트웨이는 클라이언트에게 리디렉션을 보낼 수 없습니다. (코드 301 (움직이는 영구적으로)) 새로운 위치의 이름을 지정합니다. 다행히도 API 클라이언트를 수정하는 것이 비현실적인 경우, 우리는 즉시 클라이언트 요청을 다시 작성할 수 있습니다.

다음 예에서는 위의 warehouse_api_simple.conf 와 동일한 광범위한 접근 방식을 사용하지만, 이 경우 구성은 가격 책정 서비스가 재고 서비스의 일부로 구현된 이전 버전의 Warehouse API를 대체합니다. 3번째 줄의 다시 쓰기 지시문은 기존 가격 책정 리소스에 대한 요청을 새 가격 책정 서비스에 대한 요청으로 변환합니다.

 

오류에 대한 대응

HTTP API와 브라우저 기반 트래픽의 주요 차이점 중 하나는 오류가 클라이언트에 전달되는 방식입니다. NGINX를 API 게이트웨이로 배포하는 경우 API 클라이언트에 가장 적합한 방식으로 오류를 반환하도록 구성합니다.

최상위 API 게이트웨이 구성에는 오류 응답을 처리하는 방법을 정의하는 섹션이 포함되어 있습니다.

 

23번째 줄의 error_page 지시문은 요청이 API 정의와 일치하지 않을 때 NGINX가 다음을 반환한다는 것을 지정합니다. 400( 잘못된 요청 ) 기본값 대신 오류 404( 찾을 수 없음 ) 오류. 이 (선택 사항) 동작은 API 클라이언트가 API 문서에 포함된 유효한 URI에만 요청을 해야 하며, 승인되지 않은 클라이언트가 API 게이트웨이를 통해 게시된 API의 URI 구조를 발견하는 것을 방지합니다.

24번째 줄은 백엔드 서비스 자체에서 생성된 오류 를 참조합니다. 처리되지 않은 예외에는 클라이언트로 전송하고 싶지 않은 스택 추적이나 기타 민감한 데이터가 포함될 수 있습니다. 이 구성은 클라이언트에 표준화된 오류 응답을 전송하여 추가 수준의 보호를 추가합니다.

표준화된 오류 응답의 전체 목록은 25번째 줄에 있는 include 지시문에서 참조하는 별도의 구성 파일에 정의되어 있습니다. 그 중 처음 몇 줄은 아래에 나와 있습니다. JSON 이외의 오류 형식을 선호하는 경우 api_gateway.conf 의 26번째 줄에 있는 default_type 값을 일치하도록 변경하여 이 파일을 수정할 수 있습니다. 각 API의 정책 섹션에 별도의 include 지시문을 넣어 전역 응답을 재정의하는 다른 오류 응답 파일을 참조할 수도 있습니다.

이 구성을 적용하면 잘못된 URI에 대한 클라이언트 요청은 다음 응답을 받습니다. [터미널]$ curl -i https://api.example.com/foo HTTP/1.1 400 잘못된 요청 서버: nginx/1.19.5 콘텐츠 유형: application/json 콘텐츠 길이: 39 연결: keep-alive {"status":400,"message":"잘못된 요청"}[/terminal]

인증 구현

API를 보호하기 위한 어떤 형태의 인증도 없이 API를 게시하는 것은 드뭅니다. NGINX는 API를 보호하고 API 클라이언트를 인증하기 위한 여러 가지 접근 방식을 제공합니다. 일반 HTTP 요청에도 적용되는 접근 방식에 대한 자세한 내용은 IP 주소 기반 액세스 제어 목록 (ACL), 디지털 인증서 인증HTTP 기본 인증 에 대한 설명서를 참조하세요. 여기에서는 API별 인증 방법에 대해 중점적으로 살펴보겠습니다.

API 키 인증

API 키는 클라이언트와 API 게이트웨이가 공유하는 비밀입니다. API 키는 본질적으로 API 클라이언트에 장기 자격 증명으로 발급된 길고 복잡한 비밀번호입니다. API 키를 만드는 것은 간단합니다. 이 예에서처럼 무작위 숫자를 인코딩하기만 하면 됩니다.

$ openssl 랜드 -base64 18 7B5zIqmRGXmrJTFmKa99vcit

최상위 API 게이트웨이 구성 파일인 api_gateway.conf 의 2번째 줄에 api_keys.conf 라는 파일을 포함합니다. 이 파일에는 각 API 클라이언트의 API 키가 들어 있으며, 클라이언트 이름이나 기타 설명으로 식별됩니다. 해당 파일의 내용은 다음과 같습니다.

API 키는 블록 내에서 정의됩니다. map 지시문은 두 개의 매개변수를 취합니다. 첫 번째는 API 키를 찾을 위치를 정의하는데, 이 경우 $http_apikey 변수에 캡처된 클라이언트 요청의 apikey HTTP 헤더에서 찾을 수 있습니다. 두 번째 매개변수는 새 변수( $api_client_name )를 생성하고 첫 번째 매개변수가 키와 일치하는 줄의 두 번째 매개변수 값으로 설정합니다.

예를 들어, 클라이언트가 API 키 7B5zIqmRGXmrJTFmKa99vcit 를 제시하면 $api_client_name 변수가 client_one 으로 설정됩니다. 이 변수는 인증된 클라이언트를 확인하는 데 사용할 수 있으며, 더욱 자세한 감사를 위해 로그 항목에 포함될 수 있습니다. 블록의 형식은 간단하고 기존 자격 증명 저장소에서 api_keys.conf 파일을 생성하는 자동화 워크플로에 쉽게 통합할 수 있습니다.

여기서는 "광범위한" 구성( warehouse_api_simple.conf )을 수정하여 정책 섹션에 auth_request 지시문을 포함시켜 인증 결정을 지정된 위치로 위임하여 API 키 인증을 활성화합니다.

 

auth_request 지시문(7번째 줄)을 사용하면 OAuth 2.0 토큰 검사 와 같은 외부 인증 서버에서 인증을 처리하도록 할 수 있습니다. 이 예제에서는 대신 /_validate_apikey 라는 위치 블록의 형태로 최상위 API 게이트웨이 구성 파일 에 API 키 검증 논리를 추가합니다.

 

30번째 줄의 내부 지침은 이 위치에 외부 클라이언트가 직접 접근할 수 없음을 의미합니다( auth_request를 통해서만 접근 가능). 클라이언트는 apikey HTTP 헤더에 API 키를 제시해야 합니다. 이 헤더가 누락되었거나 비어 있는 경우(32번째 줄) 다음을 보냅니다.401 (권한이 없는) 클라이언트에게 인증이 필요하다는 것을 알려주는 응답입니다. 라인 35는 API 키가 블록의 키와 일치하지 않는 경우를 처리합니다. 이 경우 api_keys.conf 의 라인 2에 있는 기본 매개변수는 $api_client_name을 빈 문자열로 설정하고 다음을 보냅니다.403 (금지됨) 클라이언트에게 인증이 실패했음을 알리는 응답입니다. 해당 조건 중 어느 것도 일치하지 않으면 API 키는 유효하고 위치는 다음을 반환합니다. 204( 내용 없음) 응답.

이 구성을 적용하면 Warehouse API는 이제 API 키 인증을 구현합니다.

$ curl https://api.example.com/api/warehouse/pricing/item001 {"상태":401,"메시지":"권한 없음"} $ curl -H "apikey: thisIsInvalid" https://api.example.com/api/warehouse/pricing/item001 {"상태":403,"메시지":"금지됨"} $ curl -H "apikey: 7B5zIqmRGXmrJTFmKa99vcit" https://api.example.com/api/warehouse/pricing/item001 {"sku":"item001","price":179.99}

JWT 인증

JSON 웹 토큰(JWT)은 API 인증에 점점 더 많이 사용되고 있습니다. 기본 JWT 지원은 NGINX Plus에서만 제공되며, 블로그의 'JWT 및 NGINX Plus를 사용하여 API 클라이언트 인증' 에서 설명한 대로 JWT 검증을 활성화합니다. 샘플 구현은 2부의 특정 메서드에 대한 액세스 제어를 참조하세요.

요약

이 시리즈의 첫 번째 블로그에서는 NGINX 오픈 소스와 NGINX Plus를 API 게이트웨이로 배포하기 위한 완벽한 솔루션을 자세히 설명합니다. 이 블로그에서 다루는 전체 파일 세트는 GitHub Gist repo 에서 검토하고 다운로드할 수 있습니다.

이 시리즈의 다른 게시물을 확인하세요:

  • 2부에서는 악의적이거나 부적절한 동작을 하는 클라이언트로부터 백엔드 서비스를 보호하기 위한 보다 고급 사용 사례를 살펴봅니다.
  • 3부에서는 NGINX를 gRPC 서비스를 위한 API 게이트웨이로 배포하는 방법을 설명합니다.

NGINX Plus를 사용해보려면 오늘 무료 30일 체험판을 시작하거나 저희에게 연락해 사용 사례에 대해 논의해 보세요.


"이 블로그 게시물에는 더 이상 사용할 수 없거나 더 이상 지원되지 않는 제품이 참조될 수 있습니다. 사용 가능한 F5 NGINX 제품과 솔루션에 대한 최신 정보를 보려면 NGINX 제품군을 살펴보세요. NGINX는 이제 F5의 일부가 되었습니다. 이전의 모든 NGINX.com 링크는 F5.com의 유사한 NGINX 콘텐츠로 리디렉션됩니다."