NGINX Plus 릴리스 10은 JSON 웹 토큰(JWT, "조트"로 발음)을 사용하여 웹 및 API 서비스에서 인증을 오프로드하는 기능을 지원합니다. R10이 출시된 이후로 우리는 새로운 릴리스마다 기능을 지속적으로 향상시켜 왔습니다.
NGINX Plus R14 부터 NGINX Plus는 중첩된 클레임 과 배열 데이터를 포함하는 JWT를 지원합니다. NGINX Plus를 API 게이트웨이 시나리오에서 사용하면 JWT를 사용하여 백엔드 서비스와 API 대상에 대한 연결을 요청하는 클라이언트를 인증할 수 있습니다.
가끔 NGINX Plus를 사용하여 JWT를 인증하고 JWT 정보를 기반으로 보다 고급 부하 분산 결정을 내리는 기본 구성을 제공해 달라는 요청을 받습니다. 가장 간단한 해결책은 인증이 성공하면 서비스에 대한 액세스를 허용하고, 실패하면 연결을 차단하거나 리디렉션하는 것입니다.
이 게시물의 연습 과정은 NGINX Plus를 사용한 JWT 인증 및 콘텐츠 기반 라우팅에 대한 기본적인 개념 증명입니다. 가장 광범위한 가능성을 포괄하고 JWT에 대한 사전 지식이나 경험의 필요성을 줄이기 위해 "JWT 101" 연습 과정을 만들었습니다. 이를 통해 JWT에 대한 사전 지식이 없어도 이 솔루션을 배포할 수 있습니다(예제와 배경 지식 포함).
이미 JWT 경험이 있거나 환경에 기존 JWT가 있는 경우 처음 두 섹션을 건너뛰고 제공된 NGINX Plus 구성 스니펫을 사용자 환경에 맞게 조정하고 JWT 클레임 데이터를 기반으로 고급 부하 분산 결정을 내릴 수 있습니다.
이 문서에서는 NGINX Plus를 새로 설치하고 다음 위치에 기본 구성 파일이 있다고 가정합니다.
NGINX Plus를 설치하고 시작하는 방법에 대한 자세한 내용은 NGINX Plus 관리자 가이드를 참조하세요.
모든 CLI 명령은 루트
권한을 가정하므로 루트가
아닌 사용자는 해당 환경에서 sudo
권한이 있어야 합니다.
추가 배경 정보 및 NGINX Plus를 사용한 JWT의 다른 사용 사례는 다음 링크를 참조하세요.
아래 지침은 JWT 클레임의 기본 처리를 위해 NGINX Plus를 구성하는 방법을 보여주기 위해 예시에 특화된 페이로드 데이터로 JWT를 처음부터 만드는 과정을 안내합니다. 샘플 JWT 대신 기존 JWT를 사용하는 경우 JWT를 만드는 데 사용하는 서명 키와 일치하는 Base64URL로 인코딩된 문자열이 "secrets" 파일에 포함되어 있는지 확인해야 합니다. JWT 페이로드의 클레임을 수정해야 할 수도 있습니다.
메모: JWT를 어떻게 생성하든 Base64URL 인코딩을 사용해야 합니다 . 이 인코딩은 패딩 ( =
문자로 처리)은 물론 Base64 인코딩에서 일반적으로 사용되는 기타 HTTP와 호환되지 않는 문자도 올바르게 처리합니다. 많은 도구는 이 작업을 자동으로 처리하지만, 수동 CLI 기반 Base64 인코더와 일부 JWT 생성 도구는 이를 처리하지 않습니다. Base64URL 인코딩에 대한 자세한 내용은 Brock Allen의 base64url 인코딩 및 RFC 4648을 참조하세요.
이 예제에서는 jwt.io 의 GUI(Base64URL 인코딩을 올바르게 수행)를 사용하여 대칭 HS256 JWT를 생성합니다. 다음 스크린샷은 아래 지침에 지정된 값을 입력하고 서명이 검증된 후 GUI가 어떻게 보이는지 보여줍니다.
jwt.io 의 GUI에서 작업하여 오른쪽의 Decoded 열 필드에 표시된 값을 확인하거나 삽입하여 HS256 JWT를 생성합니다.
다음 기본값이 HEADER 필드에 나타나는지 확인하고 필요한 경우 일치하도록 내용을 수정합니다.
{ "알고리즘": "HS256",
"일반": "JWT"
}
VERIFY SIGNATURE 필드에서 상자에 있는 값(기본값은 secret
)을 nginx123
으로 바꿉니다. (두 단계를 반대로 진행하면 발생하는 문제를 방지하기 위해 PAYLOAD 필드에 데이터를 입력하기 전에 이 변경 작업을 수행하세요.)
PAYLOAD 필드의 내용을 다음으로 바꾸세요.
{ "exp": 1545091200,
"이름": "새로운 사용자 만들기",
"sub": "cuser",
"gname": "wheel",
"guid": "10",
"전체 이름": "존 도",
"uname": "jdoe",
"UID": "222",
"sudo": 참,
"dept": "IT",
"url": "http://secure.example.com"
}
메모: exp
클레임은 JWT의 만료 날짜 및 시간을 설정하고 이를 UNIX 에포크 시간( 1970년 1월 1일 UTC 자정 이후의 초 수)으로 표현합니다. 샘플 값은 2018년 12월 18일 UTC 자정을 나타냅니다. 만료 날짜를 조정하려면 에포크 시간을 변경하세요.
필드 아래의 막대가 파란색이고 서명 확인됨 이라고 표시되어 있는지 확인하세요.
왼쪽의 인코딩된 열의 값을 파일이나 버퍼에 복사합니다. 이는 사용자 jdoe가 http://secure.example.com 에 접근하기 위해 제시해야 하는 JWT의 전체 텍스트이며, 아래 테스트에서 이를 사용할 것입니다. 여기서는 표시 목적으로 JWT를 줄 바꿈과 함께 표시하지만 NGINX Plus에서는 단일 줄 문자열로 표시해야 합니다.
eyJhbGciOiJIUzi1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDUwOTEyMDAIm5hbWUiOi
JDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW1lIjoid2hlZWwiLCJndWlkI
조이MTAiLCJmdWxsTmFtZSI6IkpvaG4gRG9lIiwidW5hbWUiOiJqZG9lIiwidWlkIjoiMjIy
이위크3VkbyI6dHJ1Z스위ZGVwdCI6IklUIiwidXJs이조이아HR0cDovL3NlY3VyZS5leGFtcGx
llmNvbSJ9.YYQCNvzj17F726QvKoIuRGeUBl_xAKj62Zvc9xkZb4
NGINX Plus 호스트에서 작업하면서 다음 단계에 따라 nginx123
으로 서명된 JWT를 확인하는 데 NGINX Plus가 사용하는 키 파일을 만듭니다.
이 명령을 실행하면 서명 문자열에 해당하는 Base64URL로 인코딩된 문자열이 생성됩니다. ( tr
명령은 Base64URL 인코딩에 필요한 문자 대체를 수행합니다.)
# echo -n nginx123 | base64 | tr '+/' '-_' | tr -d '=' bmdpbngxMjM
/etc/nginx/ 디렉토리에서 NGINX Plus에서 JWT 서명을 검증하는 데 사용할 api_secret.jwk 라는 키 파일을 생성합니다. 다음 내용을 삽입하세요. k
필드의 값은 이전 단계에서 생성한 nginx123
의 Base64URL로 인코딩된 형식입니다.
{"키": [{
"k":"bmdpbngxMjM",
"kty":"10진수"
}]
}
이 섹션의 지침은 NGINX Plus가 요청에 포함된 JWT를 검증하고 클라이언트가 인증된 경우 보호된 리소스를 표시하도록 구성합니다(인증되지 않은 클라이언트에게 표시되는 기본 페이지가 아님). 또한 JWT 관련 정보를 캡처하는 새로운 로그 형식도 정의합니다.
이 지침에서는 NGINX Plus에서 읽지 않도록 default.conf 구성 파일의 이름을 바꾸고 테스트용으로 새 구성을 만드는 표준 모범 사례를 따릅니다. 이렇게 하면 테스트가 끝나거나 테스트 중에 문제가 발생할 경우 기본 구성을 쉽게 복원할 수 있습니다.
default.conf 이름 바꾸기:
# mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.bak
/etc/nginx/conf.d/ 에 다음 내용으로 jwt-test.conf 라는 새 구성 파일을 만듭니다. JWT 관련 로깅, JWT 검증 및 콘텐츠 기반 라우팅을 구성합니다(전체 분석은 스니펫 뒤에 나옵니다).
서버 {
listen 80;
access_log /var/log/nginx/host.access.log jwt;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
# JWT 검증
auth_jwt "JWT 테스트 영역" 토큰=$arg_myjwt;
auth_jwt_key_file /etc/nginx/api_secret.jwk;
error_log /var/log/nginx/host.jwt.error.log 디버그;
if ( $jwt_claim_uid = 222 ) {
add_header X-jwt-claim-uid "$jwt_claim_uid" 항상;
add_header X-jwt-status "$jwt_claim_url로 리디렉션" 항상;
return 301 $jwt_claim_url;
}
if ( $jwt_claim_uid != 222 ) {
add_header X-jwt-claim-uid "$jwt_claim_uid" 항상;
add_header X-jwt-status "잘못된 사용자, 리디렉션 없음" 항상;
}
}
}
위치
블록의 지시문은 NGINX Plus에게 JWT를 포함하는 HTTP 요청을 처리하는 방법을 알려줍니다. ( access_log
지시문에 의해 정의된 로깅 구성에 대한 자세한 내용은 다음 섹션을 참조하세요.) NGINX Plus는 다음 단계를 수행합니다.
요청 문자열의 myjwt 인수에서 JWT를 추출합니다( auth_jwt
지시문의 토큰
인수에서 지정한 대로).
auth_jwt_key-file
지시문(여기서는 api_secret.jwk )에서 지정한 서명 키를 사용하여 JWT를 디코딩합니다. 이는 다음과 같이 페이로드에 적용됩니다(이러한 작업은 JWT 처리에 내재되어 있으며 해당 NGINX Plus 지침이 없습니다).
exp
클레임에 지정된 만료 날짜가 과거가 아닌지 확인합니다.$jwt_claim_claim -name
형태의 변수입니다(예: uid
클레임의 경우 $jwt_claim_uid
). 디버그
수준에서 모든 오류를 /var/log/nginx/host.jwt.error.log 에 기록합니다.
$jwt_claim_uid
의 값이 다음과 같은지 테스트합니다.222
(두 개의 if
지시어에 지정된 대로) 클라이언트에 적절한 응답을 전송합니다. 이는 JWT의 정보를 사용하여 콘텐츠 기반 라우팅을 수행하는 방식입니다.
222
NGINX Plus는 클라이언트( 반환
지시문)를 JWt의 url
클레임에 지정된 URL로 리디렉션하는 응답을 보냅니다. 디버깅 목적으로 응답에 두 개의 헤더( add_header
지시문)를 추가합니다. 첫 번째 헤더는 uid
클레임의 값을 캡처하고 두 번째 헤더는 클라이언트가 리디렉션되었다는 사실을 기록합니다.222
NGINX Plus는 기본 인덱스 페이지(동일한 위치
블록의 root
및 index
지시어에서 정의)를 제공합니다. 디버깅 목적으로 uid
클레임의 값을 캡처하고 클라이언트가 JWT에 지정된 URL에 액세스하지 못했다는 사실을 기록하는 헤더를 추가합니다.메모: if
지시어를 사용하여 변수를 평가하는 것은 일반적으로 모범 사례로 간주되지 않으며 , 대신 map
지시어를 사용하는 것이 좋습니다. 하지만 이 간단한 예제의 경우 if
지시어는 의도한 대로 작동합니다.
실제로 이 구성은 권한이 있는 사용자에게만 보호된 리소스에 대한 액세스를 제공합니다. 즉, 유효한 JWT가 있는 사용자는 JWT에 지정된 URL에 액세스할 수 있지만, 유효한 JWT가 없는 사용자는 기본 페이지에 액세스할 수 있습니다.
jwt-test.conf 의 access_log
지시문에서 참조되는 jwt 라는 로깅 형식을 정의하여 콘텐츠 기반 라우팅에 대한 JWT 처리 구성을 완료합니다. 액세스 로그에서 JWT 데이터를 캡처합니다.
다음 log_format
지시문을 /etc/nginx/nginx.conf 에 추가합니다.
log_format jwt '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" "$http_user_agent" '
'$jwt_header_alg $jwt_claim_uid $jwt_claim_url';
이 형식에는 이 연습에서 사용되는 두 개의 JWT 클레임( uid
및 url
)이 포함되지만 $jwt_claim_claim ‑name
형식으로 클레임에 해당하는 변수 이름을 사용하여 모든 JWT 클레임 데이터를 기록할 수 있습니다.
nginx.conf를 저장한 후 다음 명령을 실행하여 구문적 유효성을 위해 전체 구성(새로운 jwt-test.conf 파일 포함)을 테스트합니다. 보고된 오류를 수정하세요.
# nginx -t
NGINX Plus를 다시 로드합니다.
# nginx -s 다시 로드
브라우저나 curl
과 같은 CLI 도구를 사용하면 NGINX Plus가 JWT를 올바르게 검증하고, JWT를 제시하는 클라이언트를 인증하고, 콘텐츠 기반 라우팅을 수행하는지 테스트할 수 있습니다. (인증과 유효성 검사만 테스트하고 콘텐츠 기반 라우팅은 테스트하지 않으려면 jwt-test.conf 에서 두 개의 if
블록을 주석으로 처리하세요.)
테스트를 실행하려면 요청 URL에 myjwt 인수를 포함하여 url
클레임이 있는 JWT의 전체 텍스트를 제공합니다.222
. 다시 한번, 표시 목적으로 줄 바꿈을 추가했습니다.
http://example.com/index.html?myjwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiO
jE1NDUwOTEyMDAIm5hbWUiOiJDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW
1l이조이드2hlZWwiLCJndWlk이조이MTAiLCJmdWxsTmFtZSI6이크피바G4gRG9l이위드W5hbWUiOiJqZG9
리위드윌크이조이MjIyIiwic3VkbyI6dHJ1ZSwiZGVwdCI6IklUIiwidXJs이조이아HR0cDovL3NlY3VyZS5le
GFtcGxlLmNvbSJ9.YYQCNvzj17F726QvKoIiuRGeUBl_xAKj62Zvc9xkZb4
다음은 해당 curl
명령어입니다(줄 바꿈이 없으므로 원하는 경우 복사하여 붙여넣을 수 있음):
# 컬 -v example.com/index.html?myjwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDUwOTEyMDAsIm5hbWUiOiJDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW1lIjoid2hlZWwiLCJndWlkIjoiMTAiLCJmd WxsTmFtZSI6IkpvaG4gRG9lIiwidW5hbWUiOiJqZG9lIiwidWlkIjoiMjIyIiwic3VkbyI6dHJ1ZSwiZGVwdCI6IklU IiwidXJsIjoiaHR0cDovL3NlY3VyZS5leGFtcGxlLmNvbSJ9.YYQCNvzj17F726QvKoIiuRGeUBl_xAKj62Zvc9xkZb4
JWT의 uid
클레임 값은 다음과 같습니다.222
NGINX Plus가 제한된 페이지인 http://secure.example.com 의 내용을 표시할 것으로 예상합니다.
이제 JWT의 url
클레임이 아닌지 확인하기 위해 테스트합니다.222
NGINX Plus는 제한된 페이지의 내용을 표시하지 않고 대신 로컬 서버의 index.html 페이지(이 경우 http://example.com/index.html ) 를 표시합니다.
우리는 jwt.io 에서 uid
클레임이 아닌 다른 JWT를 생성하는 것으로 시작합니다.222
; 예를 들어, 우리는 그것을 만든다111
. 해당 JWT를 포함한 요청 URL은 다음과 같습니다.
http://example.com/index.html?myjwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiO
jE1NDUwOTEyMDAIm5hbWUiOiJDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW
1l이조이드2hlZWwiLCJndWlk이조이MTAiLCJmdWxsTmFtZSI6이크피바G4gRG9l이위드W5hbWUiOiJqZG9
리위드윌크이조이MTEx이위크3VkbyI6dHJ1Z스위ZGVwdCI6이클UI이위드XJs이조이아HR0c도브L3NlY3VyZS5l
eGFtcGxlLmNvbSJ9.Ch9xqsGzB8fRVX-3CBuCxP1Ia3oGKB1OnO6qwi_oBgg
curl
명령어는 다음과 같습니다.
# 컬 -v example.com/index.html?myjwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDUwOTEyMDAsIm5hbWUiOiJDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW1lIjoid2hlZWwiLCJndWlkIjoiMTAiLCJmd WxsTmFtZSI6IkpvaG4gRG9lIiwidW5hbWUiOiJqZG9lIiwidWlkIjoiMTExIiwic3VkbyI6dHJ1ZSwiZGVwdCI6IklUIiwidXJsIjoiaHR0cDovL3NlY3VyZS5leGFtcGxlLmNvbSJ9.Ch9xqsGzB8fRVX-3CBuCxP1Ia3oGKB1OnO6qwi_oBgg
이 경우에는 NGINX Plus가 http://example.com/index.html을 제공할 것으로 예상됩니다.
두 테스트 조건에서 헤더 검사 도구(예: curl
또는 일부 브라우저와 함께 제공되는 개발자 도구)를 사용하여 새 헤더인 X-jwt-claim-uid
및 X-jwt-status가
응답에 추가되었는지 확인할 수 있습니다.
테스트 중에 문제가 발생하면 /var/log/nginx/host.jwt* 에서 액세스 및 오류 로그를 확인하세요. 특히 오류 로그는 검증, 검증 파일 접근 등의 문제에 대한 정보를 보여줍니다.
기본적인 예에서 NGINX Plus는 요청 URL의 myjwt 인수에서 JWT를 추출합니다. NGINX Plus는 쿠키에서 JWT를 전달하는 것도 지원합니다(자세한 내용은 NGINX JWT 참조 문서를 참조하세요). jwt-test.conf 에서 auth_jwt
지시문을 변경하여 토큰
매개변수의 첫 번째 요소가 $ arg 대신 $
cookie가
되도록 합니다.
auth_jwt "JWT 테스트 영역" 토큰=$cookie_myjwt;
myjwt 라는 쿠키에 JWT를 제공하려면 적절한 curl
명령은 다음과 같습니다.
# curl -v --cookie myjwt= JWT-text example.com/index.html
JWT를 사용한 콘텐츠 기반 라우팅을 직접 시도해 보세요. 오늘 NGINX의 무료 30일 평가판을 시작하거나, 사용 사례에 대해 논의하기 위해 저희에게 연락하세요 .
"이 블로그 게시물에는 더 이상 사용할 수 없거나 더 이상 지원되지 않는 제품이 참조될 수 있습니다. 사용 가능한 F5 NGINX 제품과 솔루션에 대한 최신 정보를 보려면 NGINX 제품군을 살펴보세요. NGINX는 이제 F5의 일부가 되었습니다. 이전의 모든 NGINX.com 링크는 F5.com의 유사한 NGINX 콘텐츠로 리디렉션됩니다."