NGINX Plus API Gateway로 JWT 인증 구현하기
JSON 웹 토큰(JWT)은 ID 정보를 교환하는 컴팩트하고 이식성이 뛰어난 수단입니다. JWT 사양은 OAuth 2.0 에코시스템을 위한 SSO(Single Sign-On) 토큰을 제공하는 OpenID Connect 의 중요한 토대였습니다. JWT는 자체적으로 인증 자격 증명으로 사용할 수도 있으며 기존 API Key보다 웹 기반 API에 대한 액세스를 제어하는 더 나은 방법입니다.
NGINX Plus R10 이상은 JWT를 직접 검증할 수 있습니다. 이 모범 사례에서는 NGINX Plus를 API Gateway로 사용하여 API EndPoint에 Frontend를 제공하고 JWT를 사용하여 Client 애플리케이션을 인증하는 방법을 설명합니다.
※ 네이티브 JWT 지원은 NGINX 오픈소스(OSS)가 아닌 NGINX Plus에서만 사용할 수 있습니다.
NGINX Plus R15 이상은 OpenID Connect 1.0의 “인증 코드 흐름”도 제어할 수 있어 대부분의 주요 ID 공급자와 통합할 수 있습니다.
목차
1. JWT의 구조 해부
2. API Key에 JWT 사용하기
3. NGINX Plus를 인증 API Gateway로 구성
3-1. API Client에 JWT 발행
3-2. 로깅 및 속도 제한을 위한 JWT 클레임 활용
4. Revokings JWTs
5. 요약
1. JWT의 구조 해부
JWT는 헤더, 페이로드 및 서명의 세 부분으로 구성됩니다. 전송에서 그들은 다음과 같이 보입니다. 가독성을 위해 줄 바꿈(실제 JWT는 단일 문자열임)과 색상 코딩을 추가하여 세 부분을 구분했습니다.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.ewogICAgInN1YiI6ICJsYzEiLAogICAgImVtYWlsIjo
gImxpYW0uY3JpbGx5QG5naW54LmNvbSIsCn0=.VGYHWPterIaLjRi0LywgN3jnDUQbSsFptUw99g2slfc
그림과 같이 마침표( .
)는 헤더, 페이로드 및 서명을 구분합니다. 헤더와 페이로드는 Base64로 인코딩된 JSON 객체입니다. 서명은 alg
헤더에 지정된 알고리즘을 사용하여 암호화되며 샘플 JWT를 디코딩할 때 확인할 수 있습니다.
인코딩 | 디코딩됨 | |
---|---|---|
헤더 | eyJhbGciOiJIUzI1NiIsInR5cCI6Ik | { |
유효 탑재량 | ewogICAgInN1YiI6ICJsYzEiLAogICAgImVtYWlsIjogImxpYW0uY3JpbGx5QG5naW54LmNvbSIsCn0= | { |
JWT 표준은 여러 서명 알고리즘을 정의합니다. 이 예제의 값 HS256
은 이 포스트의 모든 샘플 JWT에 사용 중인 HMAC SHA‑256을 나타냅니다. NGINX Plus는 표준에 정의된 HSxxx, RSxxx, ESxxx 등 서명 알고리즘을 지원합니다 . JWT를 암호화 방식으로 서명하는 기능은 JWT를 인증 자격 증명으로 사용하기에 이상적입니다.
2. API Key에 JWT 사용하기
API Client(API 리소스를 요청하는 원격 소프트웨어 클라이언트)를 인증하는 일반적인 방법은 일반적으로 API Key라고 하는 공유 비밀을 사용하는 것 입니다. 기존 API Key는 기본적으로 클라이언트가 모든 요청에 대해 추가 HTTP 헤더로 보내는 길고 복잡한 암호입니다. API EndPoint는 제공된 API Key가 유효한 키 목록에 있는 경우 요청된 리소스에 대한 액세스 권한을 부여합니다. 일반적으로 API EndPoint는 API Key 자체의 유효성을 검사하지 않습니다. 대신 API Gateway가 인증 프로세스를 처리하고 각 요청을 적절한 EndPoint로 라우팅합니다. 계산 오프로딩 외에도 많은 API EndPoint에 대한 고가용성 및 로드 밸런싱과 같은 리버스 프록시와 함께 제공되는 이점을 제공합니다.

서로 다른 API Client에 서로 다른 액세스 제어 및 정책을 적용하는 것이 일반적입니다. 기존 API Key를 사용하면 API Key를 속성 세트와 일치시키기 위한 조회가 필요합니다. 각각의 모든 요청에 대해 이 조회를 수행하면 시스템의 전체 대기 시간에 이해할 수 있는 영향을 미칩니다. JWT를 사용하면 이러한 속성이 포함되어 별도의 조회가 필요하지 않습니다.
JWT를 API Key로 사용하면 모범 사례 인증 기술을 ID 속성 교환을 위한 표준 기반 스키마와 결합하여 기존 API Key에 대한 고성능 대안을 제공합니다.

3. NGINX Plus를 인증 API Gateway로 구성
JWT를 검증하기 위한 NGINX Plus 구성은 매우 간단합니다.
upstream api_server {
server 10.0.0.1;
server 10.0.0.2;
}
server {
listen 80;
location /products/ {
auth_jwt "Products API";
auth_jwt_key_file conf/api_secret.jwk;
proxy_pass http://api_server;
}
}
가장 먼저 하는 일은 upstream
블록에서 API EndPoint를 호스팅하는 서버의 주소를 지정하는 것입니다. 이 블록은 /products/ location
로 시작하는 URL에 대한 모든 요청이 인증되어야 함을 지정합니다. 이 auth_jwt
지시문은 인증에 실패할 경우 401 상태 코드와 함께 반환 될 인증 영역을 정의합니다 .
이 auth_jwt_key_file
지시문은 NGINX Plus에 JWT의 서명 요소를 확인하는 방법을 알려줍니다. 이 예에서는 HMAC SHA‑256 알고리즘을 사용하여 JWT에 서명하므로 서명에 사용되는 대칭 키를 포함하도록 conf/api_secret.jwk 에 JSON 웹 키를 생성해야 합니다. 파일은 JSON 웹 키 사양 에 설명된 형식을 따라야 합니다. 우리의 예는 다음과 같습니다.
{"keys":
[{
"k":"ZmFudGFzdGljand0",
"kty":"oct",
"kid":"0001"
}]
}
대칭 키는 k
필드에 정의되며 여기에 일반 텍스트 문자열의 Base64URL 인코딩 fantasticjwt
값이 있습니다. 다음 명령을 실행하여 인코딩된 값을 얻었습니다.
$ echo -n fantasticjwt | base64 | tr '+/' '-_' | tr -d '='
필드는 kty
키 유형을 대칭 키(옥텟 시퀀스)로 정의합니다. 마지막으로 kid
(Key ID) 필드는 이 JSON 웹 키에 대한 일련 번호를 정의합니다. 여기 0001
에서 동일한 파일에서 여러 키를 지원하고( auth_jwt_key_file
지시문에 의해 명명된) 해당 키와 서명된 JWT의 수명 주기를 관리할 수 있습니다. .
이제 API Client에 JWT를 발행할 준비가 되었습니다.
3-1. API Client에 JWT 발행
샘플 API Client로 “인용 시스템” 애플리케이션을 사용하고 API Client용 JWT를 생성합니다. 먼저 JWT 헤더를 정의합니다.
{
"typ":"JWT",
"alg":"HS256",
"kid":"0001"
}
typ
필드는 유형을 JSON 웹 토큰으로 정의하고, 필드 alg
는 JWT가 HMAC SHA256 알고리즘으로 kid
서명되었음을 지정하고, 필드는 JWT가 해당 일련 번호로 JSON 웹 키로 서명되었음을 지정합니다.
다음으로 JWT 페이로드를 정의합니다.
{
"name":"Quotation System",
"sub":"quotes",
"iss":"My API Gateway"
}
(sub
제목) 필드는 필드의 전체 값에 대한 고유 식별자입니다 name
. 이 iss
필드는 API Gateway가 타사 발급자 또는 중앙 집중식 ID 관리 시스템의 JWT도 수락하는 경우에 유용한 JWT의 발급자를 설명합니다.
이제 JWT를 만드는 데 필요한 모든 것이 준비되었으므로 다음 단계에 따라 올바르게 인코딩하고 서명합니다. 명령과 인코딩된 값은 가독성을 위해서만 여러 줄에 나타납니다. 각각은 실제로 다음과 같이 입력되거나 한 줄에 나타납니다.
- 헤더와 페이로드를 별도로 병합하고 Base64URL 인코딩합니다.
$ echo -n '{"typ":"JWT","alg":"HS256","kid":"0001"}' | base64 | tr '+/' '-_' | tr -d '='
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEifQ
$ echo -n '{"name":"Quotation System","sub":"quotes","iss":"My API Gateway"}' | base64 | tr '+/' '-_' | tr -d '='
eyJuYW1lIjoiUXVvdGF0aW9uIFN5c3RlbSIsInN1YiI6InF1b3RlcyIsImlzcyI6Ik
15IEFQSSBHYXRld2F5In0
2. 인코딩된 헤더와 페이로드를 마침표(.)로 연결하고 결과를 HEADER_PAYLOAD
변수에 할당합니다.
$ HEADER_PAYLOAD=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAw
MDEifQ.eyJuYW1lIjoiUXVvdGF0aW9uIFN5c3RlbSIsInN1YiI6InF1b3RlcyIsIm
lzcyI6Ik15IEFQSSBHYXRld2F5In0
3. 대칭 키로 헤더와 페이로드에 서명하고 서명을 Base64URL 인코딩합니다.
$ echo -n $HEADER_PAYLOAD | openssl dgst -binary -sha256 -hmac fantasticjwt | base64 | tr '+/' '-_' | tr -d '='
ggVOHYnVFB8GVPE-VOIo3jD71gTkLffAY0hQOGXPL2I
4. 헤더와 페이로드에 인코딩된 서명을 추가합니다.
$ echo $HEADER_PAYLOAD.ggVOHYnVFB8GVPE-VOIo3jD71gTkLffAY0hQOGXPL2I > quotes.jwt
5. API Gateway에 인증된 요청을 만들어 테스트합니다(이 예에서 Gateway는 localhost에서 실행 중임).
$ curl -H "Authorization: Bearer `cat quotes.jwt`" http://localhost/products/widget1
5단계의 curl 명령은 NGINX Plus가 기본적으로 기대하는 베어러 토큰 형태로 JWT를 NGINX Plus에 보냅니다. NGINX Plus는 쿠키 또는 쿼리 문자열 매개변수에서 JWT를 가져올 수도 있습니다. 이를 구성하려면 auth_jwt 지시문에 token= 매개변수를 포함합니다. 예를 들어 다음 구성을 사용하면 NGINX Plus는 이 curl 명령으로 전송된 JWT의 유효성을 검사할 수 있습니다.
$ curl http://localhost/products/widget1?apijwt=`cat quotes.jwt`
server {
listen 80;
location /products/ {
auth_jwt "Products API" token=$arg_apijwt;
auth_jwt_key_file conf/api_secret.jwk;
proxy_pass http://api_server;
}
}
NGINX Plus를 구성하고 위와 같이 JWT를 생성 및 확인했으면 JWT를 API Client 개발자에게 보낼 준비가 된 것이며 각 API 요청과 함께 JWT를 제출하는 데 사용할 메커니즘에 동의합니다.
3-2. 로깅 및 속도 제한을 위한 JWT 클레임 활용
인증 자격 증명으로서 JWT의 주요 이점 중 하나는 JWT 및 해당 페이로드(예: 발급자, 발급 대상 사용자 및 의도된 수신자)와 관련된 엔터티를 나타내는 “클레임”을 전달한다는 것입니다. JWT를 검증한 후 NGINX Plus는 헤더 및 페이로드에 있는 모든 필드에 변수로 액세스할 수 있습니다. 이들은 원하는 필드에 $jwt_header_ 또는 $jwt_claim_ 접두사를 붙여 액세스합니다(예: 하위 청구의 경우 $jwt_claim_sub). 이는 API 자체에서 JWT 처리를 구현할 필요 없이 JWT에 포함된 정보를 API 끝점으로 매우 쉽게 프록시할 수 있음을 의미합니다.
이 구성 예제는 일부 고급 기능을 보여줍니다.
log_format jwt '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" "$http_user_agent" '
'$jwt_header_alg $jwt_claim_sub';
limit_req_zone $jwt_claim_sub zone=10rps_per_client:1m rate=10r/s;
server {
listen 80;
location /products/ {
auth_jwt "Products API";
auth_jwt_key_file conf/api_secret.jwk;
limit_req zone=10rps_per_client;
proxy_pass http://api_server;
proxy_set_header API-Client $jwt_claim_sub;
access_log /var/log/nginx/access_jwt.log jwt;
}
}
log_format 지시어는 $jwt_header_alg 및 $jwt_claim_sub라는 두 개의 추가 필드로 공통 로그 형식을 확장하는 jwt라는 새로운 형식을 정의합니다. 위치 블록 내에서 access_log 지시문을 사용하여 검증된 JWT에서 얻은 값으로 로그를 작성합니다.
이 예에서는 클레임 기반 변수를 사용하여 IP 주소 대신 API 클라이언트별로 API 속도 제한을 제공합니다. 이는 여러 API 클라이언트가 단일 포털에 포함되어 있고 IP 주소로 구분할 수 없는 경우에 특히 유용합니다. limit_req_zone 지시문은 속도 제한을 계산하기 위한 키로 JWT 하위 클레임을 사용하고 limit_req 지시문을 포함하여 위치 블록에 적용합니다.
마지막으로 요청이 API 끝점으로 프록시될 때 JWT 제목을 새 HTTP 헤더로 제공합니다. proxy_set_header 지시문은 API 엔드포인트가 쉽게 사용할 수 있는 API‑Client라는 HTTP 헤더를 추가합니다. 따라서 API 끝점은 JWT 처리 논리를 구현할 필요가 없습니다. 이는 API 엔드포인트 수가 증가함에 따라 점점 더 중요해집니다.
4. Revokings JWTs
때때로 API 클라이언트의 JWT를 취소하거나 재발급해야 할 수 있습니다. 간단한 맵 블록을 auth_jwt_require 지시문과 결합하여 JWT의 만료 날짜(exp 클레임에 표시됨)에 도달할 때까지 해당 JWT를 유효하지 않은 것으로 표시하여 API 클라이언트에 대한 액세스를 거부할 수 있습니다. JWT를 안전하게 제거할 수 있습니다.
이 예에서는 토큰의 sub 클레임 값에 따라 $jwt_status 변수를 0 또는 1로 설정합니다($jwt_claim_sub 변수에 캡처됨). 그런 다음 위치 블록에서 auth_jwt_require 지시문을 사용하여 토큰을 추가로 검증(또는 거부)합니다. 유효하려면 $jwt_status 변수가 비어 있거나 0과 같지 않아야 합니다.
map $jwt_claim_sub $jwt_status {
"quotes" 0;
"test" 0;
default 1;
}
server {
listen 80;
location /products/ {
auth_jwt "Products API";
auth_jwt_key_file conf/api_secret.jwk;
auth_jwt_require $jwt_status;
proxy_pass http://api_server;
}
}
5. 요약
JSON 웹 토큰은 API에 대한 인증된 액세스를 제공하는 데 적합합니다. API Client 개발자의 경우 기존 API Key만큼 쉽게 처리할 수 있으며 데이터베이스 조회가 필요한 ID 정보를 API Gateway에 제공합니다. NGINX Plus는 JWT 자체에 포함된 정보를 기반으로 JWT 인증 및 정교한 구성 솔루션을 지원합니다. 다른 API Gateway 기능과 결합된 NGINX Plus를 사용하면 속도, 안정성, 확장성 및 보안을 갖춘 API 기반 서비스를 제공할 수 있습니다.
댓글을 달려면 로그인해야 합니다.