Microsoft Entra ID로 SAML SSO용 NGINX Plus 구성하기

관리자
조회수 339


보안을 강화하고 사용자 경험을 개선하기 위해 F5 NGINX Plus(R29+)는 이제 SAML(보안 어설션 마크업 언어)을 지원합니다. 웹 애플리케이션에 싱글 사인온(SSO)을 제공하는 잘 정립된 프로토콜인 SAML은 ID 공급자(IdP)가 리소스에 대한 액세스를 위해 사용자를 인증한 다음 해당 정보를 서비스 공급자(SP)에게 전달하여 권한을 부여할 수 있게 해줍니다.

이 블로그 게시물에서는 기본적으로 SAML을 지원하지 않는 웹 애플리케이션을 사용하여 NGINX를 Microsoft Entra ID(이전의 Azure AD)와 통합하는 방법을 단계별로 다룹니다. 또한 애플리케이션에 대한 SSO를 구현하고 이를 Microsoft Entra ID 에코시스템과 통합하는 방법도 다룹니다. 튜토리얼을 따라가다 보면 NGINX가 SAML 어설션(UPN, 이름, 성, 그룹 멤버십 포함)에서 클레임을 추출한 다음 HTTP 헤더를 통해 애플리케이션에 전달하는 방법을 추가로 배울 수 있습니다.


이 튜토리얼에는 세 단계가 포함되어 있습니다:

  1. Microsoft Entra ID를 IdP로 구성하기
  2. SAML 설정 및 NGINX Plus를 역방향 프록시로 구성하기
  3. 구성 테스트하기

이 튜토리얼을 완료하려면 다음이 필요합니다:

  • 30일 무료 평가판으로 받을 수 있는 NGINX Plus(R29+)
  • 무료 또는 엔터프라이즈 Microsoft Entra ID 계정
  • NGINX Plus 서버에 설치된 유효한 SSL/TLS 인증서(이 튜토리얼에서는 dev.sports.com.crt 및 dev.sports.com.key 사용)
  • SAML 어설션을 확인하려면 IdP에서 공개 인증서 demonginx.cer을 다운로드하여 수행할 수 있습니다.

참고: 키-값 저장소는 NGINX Plus 전용이므로 이 튜토리얼은 NGINX 오픈 소스 배포에는 적용되지 않습니다.

NGINX Plus를 SAML 서비스 공급자로 사용

이 설정에서 NGINX Plus는 SAML SP로 작동하며 사용자 에이전트를 통해 NGINX Plus와 간접적으로 통신하는 SAML IdP로 SSO 구현에 참여할 수 있습니다.

아래 다이어그램은 요청 및 응답을 위한 SP 개시 및 POST 바인딩이 포함된 SSO 프로세스 흐름을 보여줍니다. 이 통신 채널은 직접적인 것이 아니며 사용자 에이전트를 통해 관리된다는 점에 다시 한 번 유의해야 합니다.



Figure 1: SAML SP-Initiated SSO with POST bindings for AuthnRequest and Response



1단계: Microsoft Entra ID를 ID 공급자로 구성하기

Microsoft Entra ID 관리 포털에 액세스하려면 로그인하고 왼쪽 패널로 이동합니다. Microsoft Entra ID를 선택한 다음 SSO 구성이 필요한 디렉터리의 제목을 클릭합니다. 선택한 후 엔터프라이즈 애플리케이션을 선택합니다.


그림 2: 관리 포털에서 엔터프라이즈 애플리케이션 선택하기

애플리케이션을 만들려면 포털 상단의 새 애플리케이션 버튼을 클릭합니다. 이 예에서는 demonginx라는 애플리케이션을 만들었습니다.



그림 3: Microsoft Entra ID에서 새 애플리케이션 만들기

새로 만든 애플리케이션 개요로 리디렉션된 후 왼쪽 메뉴를 통해 시작하기로 이동하고 관리에서 Single sign-on을 클릭합니다. 그런 다음 통합 인증 방법으로 SAML을 선택합니다.



그림 4: SSO 섹션을 사용하여 SAML 구성 시작하기

엔터프라이즈 애플리케이션에서 SSO를 설정하려면 Microsoft Entra ID 내에서 NGINX Plus를 SP로 등록해야 합니다. 이렇게 하려면 그림 5와 같이 기본 SAML 구성에서 편집 옆의 연필 아이콘을 클릭합니다.

다음 값을 추가한 다음 저장을 클릭합니다:

  • 식별자(엔티티 ID) - https://dev.sports.com
  • 회신 URL(어설션 소비자 서비스 URL) - https://dev.sports.com/saml/acs
  • 로그인 URL: https://dev.sports.com
  • 로그아웃 URL(선택 사항): https://dev.sports.com/saml/sls

인증 인증서 사용은 선택 사항입니다. 이 설정을 사용하도록 설정할 때는 NGINX에서 두 가지 구성 옵션을 해결해야 합니다:

  1. 공개 키로 서명을 확인하려면 $saml_sp_sign_authn을 true로 설정해야 합니다. 이렇게 하면 SP가 IdP로 전송된 AuthnRequest에 서명하도록 지시합니다.
  2. 이 서명에 사용할 개인 키의 경로를 $saml_sp_signing_key를 구성하여 제공하세요. 서명 확인을 위해 해당 공개 키 인증서를 Microsoft Entra ID에 업로드해야 합니다.

참고: 이 데모에서는 속성 및 클레임이 수정되었으며 새로운 SAML 속성이 추가되었습니다. 이러한 SAML 속성은 IdP에서 전송합니다. 이러한 속성을 올바르게 수신하고 처리하도록 NGINX 구성이 설정되어 있는지 확인하세요. NGINX GitHub 리포지토리에서 관련 설정을 확인하고 조정할 수 있습니다.

Microsoft Entra ID에서 IdP 인증서(Raw)를 다운로드하여 NGINX Plus 인스턴스에 저장합니다.



Figure 5: Downloading the IdP Certificate (Raw) from Microsoft Entra ID

그림 6: 새 사용자 또는 그룹 추가하기

Microsoft Entra ID에서 사용자 및 그룹을 추가하거나 할당하여 SSO 사용 회사 애플리케이션에 대한 액세스 권한을 부여할 수 있습니다.

왼쪽 메뉴에서 사용자 및 그룹을 클릭한 다음 상단 버튼 사용자/그룹 추가를 클릭합니다.


2단계: SAML 설정 및 NGINX Plus를 역방향 프록시로 구성하기

NGINX Plus SP에서 파일을 구성하기 전에 필요한 인증서가 있는지 확인하세요:

  • TLS 세션 종료를 위한 인증서(dev.sports.com.crt 및 dev.sports.com.key)
  • IdP 서명 확인을 위해 Microsoft Entra ID에서 다운로드한 인증서(demonginx.cer)

참고: 인증서는 SPKI 형식이어야 합니다.

이 단계를 시작하려면 서명 확인을 위해 Microsoft Entra ID에서 IdP 인증서를 다운로드합니다. 그런 다음 PEM을 DER 형식으로 변환합니다:

openssl x509 -in demonginx.cer -outform DER -out demonginx.der

SAML SP 어설션을 확인하려는 경우, TLS 종료에 사용된 것과 다른 공개/개인 키를 사용하는 것이 좋습니다.

공개 키 인증서를 SPKI 형식으로 추출합니다:

openssl x509 -inform DER -in demonginx.der -pubkey -noout > demonginx.spki

frontend.conf 파일을 편집하여 다음 항목을 업데이트합니다:

  • ssl_certificate - TLS 인증서 경로를 포함하도록 업데이트합니다.
  • ssl_certificate_key - TLS 비공개 키 경로를 포함하도록 업데이트합니다.

프로덕션 배포에서는 비즈니스 요구 사항에 따라 다른 백엔드 대상을 사용할 수 있습니다. 이 예에서는 백엔드에서 사용자 지정 응답을 제공합니다:

"애플리케이션 페이지에 오신 것을 환영합니다\n 내 objectid는 $http_objectid\n 내 이메일은 $http_mail\n";



사용자의 메일 및 objectid에 대한 새로운 클레임을 추가하여 Microsoft Entra ID의 속성 및 클레임을 수정했습니다. 이러한 업데이트를 통해 애플리케이션에 보다 개인화된 맞춤형 응답을 제공하여 사용자 경험을 개선할 수 있습니다.



그림 7: Microsoft Entra ID의 수정된 속성 및 클레임

다음 단계는 백엔드 애플리케이션으로 트래픽을 프록시할 NGINX를 구성하는 것입니다. 

이 데모에서 백엔드 SAML 애플리케이션은 https://dev.sports.com 에서 공개적으로 사용할 수 있습니다.

frontend.conf 파일을 편집합니다:

# This is file frontend.conf 
# This is the backend application we are protecting with SAML SSO 
upstream my_backend { 
    zone my_backend 64k; 
    server dev.sports.com; 
} 

# Custom log format to include the 'NameID' subject in the REMOTE_USER field 
log_format saml_sso '$remote_addr - $saml_name_id [$time_local] "$request" "$host" ' 
                    '$status $body_bytes_sent "$http_referer" ' 
                    '"$http_user_agent" "$http_x_forwarded_for"'; 

# The frontend server - reverse proxy with SAML SSO authentication 
# 
server { 
    # Functional locations implementing SAML SSO support 
    include conf.d/saml_sp.server_conf; 
 

    # Reduce severity level as required 
    error_log /var/log/nginx/error.log debug; 
    listen 443 ssl; 
    ssl_certificate     /home/ubuntu/dev.sports.com.crt; 
    ssl_certificate_key  /home/ubuntu/dev.sports.com.key; 
    ssl_session_cache shared:SSL:5m; 
 

    location / { 
        # When a user is not authenticated (i.e., the "saml_access_granted." 
        # variable is not set to "1"), an HTTP 401 Unauthorized error is 
        # returned, which is handled by the @do_samlsp_flow named location. 
        error_page 401 = @do_samlsp_flow; 

        if ($saml_access_granted != "1") { 
            return 401; 
        } 

        # Successfully authenticated users are proxied to the backend, 
        # with the NameID attribute passed as an HTTP header        
        proxy_set_header mail $saml_attrib_mail;  # Microsoft Entra ID's user.mail 
        proxy_set_header objectid $saml_attrib_objectid; # Microsoft Entra ID's objectid 
        access_log /var/log/nginx/access.log saml_sso; 
        proxy_pass http://my_backend; 
        proxy_set_header Host dev.sports.com; 
        return 200 "Welcome to Application page\n My objectid is $http_objectid\n My email is $http_mail\n"; 
        default_type text/plain; 

   } 
} 
# vim: syntax=nginx          

saml_attrib_mail 및 saml_attrib_ objectid 속성이 NGINX 구성에 반영되도록 하려면 saml_sp_configuration.conf의 키-값 저장소 부분을 다음과 같이 업데이트합니다:

keyval_zone    zone=saml_attrib_mail:1M                state=/var/lib/nginx/state/saml_attrib_email.json   timeout=1h; keyval   $cookie_auth_token $saml_attrib_mail    zone=saml_attrib_mail;  keyval_zone zone=saml_attrib_objectid:1M            state=/var/lib/nginx/state/saml_attrib_objectid.json   timeout=1h; keyval   $cookie_auth_token $saml_attrib_objectid   zone=saml_attrib_objectid; 

다음으로 SAML SSO 구성 파일을 구성합니다. 이 파일에는 SP 및 IdP에 대한 기본 구성이 포함되어 있습니다. 특정 SP 및 IdP 설정에 따라 사용자 지정하려면 파일에 포함된 여러 맵{} 블록을 조정해야 합니다.

이 표는 saml_sp_configuration.conf 내의 변수에 대한 설명을 제공합니다:

0a9ba607d00e7.png

참고: 구성 파일의 나머지 부분이 여전히 파일에 표시되는지 확인합니다(예 키-값 저장소). 

또한 배포에 따라 saml_sp_configuration.conf 파일 내의 변수를 적절하게 조정했는지 확인하세요.

# Zone for storing SAML session access information. (REQUIRED) 
# Timeout determines how long the SP keeps session access decision (the session lifetime). 
keyval_zone zone=saml_session_access:1M             state=/var/lib/nginx/state/saml_session_access.json              timeout=1h; 

# Zone for storing SAML NameID values. (REQUIRED) 
# Timeout determines how long the SP keeps NameID values. Must be equal to session lifetime. 
keyval_zone zone=saml_name_id:1M                    state=/var/lib/nginx/state/saml_name_id.json                     timeout=1h; 

# Zone for storing SAML NameID format values. (REQUIRED) 
# Timeout determines how long the SP keeps NameID format values. Must be equal to session lifetime. 
keyval_zone zone=saml_name_id_format:1M             state=/var/lib/nginx/state/saml_name_id_format.json              timeout=1h; 

# Zone for storing SAML SessionIndex values. (REQUIRED) 
# Timeout determines how long the SP keeps SessionIndex values. Must be equal to session lifetime. 
keyval_zone zone=saml_session_index:1M              state=/var/lib/nginx/state/saml_session_index.json               timeout=1h; 
  
# Zone for storing SAML AuthnContextClassRef values. (REQUIRED) 
# Timeout determines how long the SP keeps AuthnContextClassRef values. Must be equal to session lifetime. 
keyval_zone zone=saml_authn_context_class_ref:1M    state=/var/lib/nginx/state/saml_authn_context_class_ref.json     timeout=1h; 

# Zones for storing SAML attributes values. (OPTIONAL) 
# Timeout determines how long the SP keeps attributes values. Must be equal to session lifetime. 
keyval_zone zone=saml_attrib_uid:1M                 state=/var/lib/nginx/state/saml_attrib_uid.json                  timeout=1h; 
keyval_zone zone=saml_attrib_name:1M                state=/var/lib/nginx/state/saml_attrib_name.json                 timeout=1h; 
keyval_zone zone=saml_attrib_memberOf:1M            state=/var/lib/nginx/state/saml_attrib_memberOf.json             timeout=1h; 

######### SAML-related variables whose value is looked up by the key (session cookie) in the key-value database. 

# Required: 
keyval $saml_request_id     $saml_request_redeemed          zone=saml_request_id;               # SAML Request ID 
keyval $saml_response_id    $saml_response_redeemed         zone=saml_response_id;              # SAML Response ID 
keyval $cookie_auth_token   $saml_access_granted            zone=saml_session_access;           # SAML Access decision 
keyval $cookie_auth_token   $saml_name_id                   zone=saml_name_id;                  # SAML NameID 
keyval $cookie_auth_token   $saml_name_id_format            zone=saml_name_id_format;           # SAML NameIDFormat 
keyval $cookie_auth_token   $saml_session_index             zone=saml_session_index;            # SAML SessionIndex 
keyval $cookie_auth_token   $saml_authn_context_class_ref   zone=saml_authn_context_class_ref;  # SAML AuthnContextClassRef 

# Optional: 
keyval $cookie_auth_token   $saml_attrib_uid                zone=saml_attrib_uid; 
keyval $cookie_auth_token   $saml_attrib_name               zone=saml_attrib_name; 
keyval $cookie_auth_token   $saml_attrib_memberOf           zone=saml_attrib_memberOf; 
 

keyval_zone    zone=saml_attrib_mail:1M                state=/var/lib/nginx/state/saml_attrib_mail.json   timeout=1h; 
keyval         $cookie_auth_token $saml_attrib_mail    zone=saml_attrib_mail; 
  
keyval $cookie_auth_token   $saml_attrib_objectid           zone=saml_attrib_objectid; 
keyval_zone zone=saml_attrib_objectid:1M            state=/var/lib/nginx/state/saml_attrib_objectid.json             timeout=1h; 
  

######### Imports a module that implements SAML SSO and SLO functionality 
js_import samlsp from conf.d/saml_sp.js; 

3단계: 구성 테스트


구성을 테스트하려면 두 가지 부분이 필요합니다:

  1. SAML 흐름 확인
  2. SP 시작 로그아웃 기능 테스트

SAML 흐름 확인

NGINX Plus를 사용하여 SAML SP를 구성하고 Microsoft Entra ID를 사용하여 IdP를 구성한 후에는 SAML 흐름의 유효성을 검사하는 것이 중요합니다. 이 유효성 검사 프로세스는 IdP를 통한 사용자 인증이 성공적으로 이루어지고 SP로 보호되는 리소스에 대한 액세스 권한이 부여되었는지 확인합니다.

SP에서 시작된 SAML 플로우를 확인하려면 선호하는 브라우저를 열고 주소창에 https://dev.sports.com 을 입력합니다. 그러면 IdP 로그인 페이지로 이동합니다.



그림 8: IdP 로그인 페이지

IdP의 로그인 페이지에 구성된 사용자의 자격 증명을 입력합니다. 제출 시 IdP에서 사용자를 인증합니다.



그림 9: 구성된 사용자의 자격 증명 입력하기

세션이 성공적으로 설정되면 사용자에게 이전에 요청된 보호된 리소스에 대한 액세스 권한이 부여됩니다. 그 후 해당 리소스가 사용자의 브라우저에 표시됩니다.



그림 9: 구성된 사용자의 자격 증명 입력하기

세션이 성공적으로 설정되면 사용자에게 이전에 요청된 보호된 리소스에 대한 액세스 권한이 부여됩니다. 그 후 해당 리소스가 사용자의 브라우저에 표시됩니다.

그림 10: 성공적으로 로드된 애플리케이션 페이지

SP 및 IdP 로그를 확인하면 SAML 흐름에 대한 중요한 정보를 얻을 수 있습니다. SP 측(NGINX Plus)에서 auth_token 쿠키가 올바르게 설정되었는지 확인합니다. IdP 측(Microsoft Entra ID)에서는 인증 프로세스가 오류 없이 완료되고 SAML 어설션이 SP로 전송되는지 확인합니다.

NGINX access.log는 다음과 같이 표시되어야 합니다:

127.0.0.1 - - [14/Aug/2023:21:25:49 +0000] "GET / HTTP/1.0" 200 127 "https://login.microsoftonline.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.1 Safari/605.1.15" "-"  99.187.244.63 - Akash Ananthanarayanan [14/Aug/2023:21:25:49 +0000] "GET / HTTP/1.1" "dev.sports.com" 200 127 "https://login.microsoftonline.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.1 Safari/605.1.15" "- 

NGINX debug.log는 다음과 같습니다:


2023/08/14 21:25:49 [info] 27513#27513: *399 js: SAML SP success, creating session _d4db9b93c415ee7b4e057a4bb195df6cd0be7e4d 

SP 시작 로그아웃 기능 테스트하기

SAML 단일 로그아웃(SLO)을 사용하면 사용자가 한 번의 작업으로 관련된 모든 IdP 및 SP에서 로그아웃할 수 있습니다. 

NGINX Plus는 SP 시작 로그아웃 시나리오와 IdP 시작 로그아웃 시나리오를 지원하여 SSO 환경의 보안 및 사용자 경험을 향상시킵니다. 

이 예에서는 SP 개시 로그아웃 시나리오를 사용합니다.

그림 11: 로그아웃 요청 및 로그아웃 응답에 대한 POST/리디렉션 바인딩이 있는 SAML SP 개시 SLO

세션을 인증한 후 SP에 구성된 로그아웃 URL에 액세스하여 로그아웃합니다. 

예를 들어, NGINX Plus에서 https://dev.sports.com/logout 을 로그아웃 URL로 설정한 경우 브라우저의 주소창에 해당 URL을 입력합니다.



그림 12: 세션에서 성공적으로 로그아웃하기

안전한 로그아웃을 보장하기 위해 SP는 SAML 요청을 시작해야 하며, 이 요청은 IdP에서 확인 및 처리됩니다. 이 작업은 사용자의 세션을 효과적으로 종료하고 IdP는 사용자의 브라우저를 다시 SP로 리디렉션하는 SAML 응답을 보냅니다.


결론

축하합니다! 이제 NGINX Plus는 인증 프로세스에 또 다른 보안 계층과 편의성을 제공하는 SAML SP 역할을 할 수 있습니다. 이 새로운 기능은 보안과 효율성을 우선시하는 조직을 위한 더욱 강력하고 다재다능한 솔루션이 될 수 있도록 NGINX Plus의 중요한 진전입니다.

NGINX Plus에서 SAML 사용에 대해 자세히 알아보기

지금 바로 NGINX Plus 30일 무료 체험을 시작하여 NGINX Plus에서 SAML 사용을 시작할 수 있습니다. 유용하게 사용하시길 바라며 여러분의 피드백을 환영합니다.

SAML이 포함된 NGINX Plus에 대한 자세한 내용은 아래 리소스에서 확인할 수 있습니다.

  • NGINX Plus R29 발표
  • GitHub의 레퍼런스 구현으로서 NGINX Plus의 SAML 지원


위 내용과 같이 NGINX Plus를 활용하여 Demo 가 필요하시면 하단의 전문가에게 상담받기 버튼을 클릭해주세요