Microsoft ID 플랫폼에서 서명 키 롤오버
이 문서에서는 Microsoft ID 플랫폼에서 보안 토큰에 서명하는 데 사용하는 공개 키에 대해 알아야 할 사항을 설명합니다. 이러한 키 롤오버가 정기적으로 있으며, 비상 시에는 곧바로 롤오버될 수 있습니다. Microsoft ID 플랫폼을 사용하는 모든 애플리케이션은 키 롤오버 프로세스를 프로그래매틱 방식으로 처리할 수 있어야 합니다. 키가 작동하는 방식, 애플리케이션에 대한 롤오버의 영향을 평가하는 방법을 이해합니다. 필요한 경우 애플리케이션을 업데이트하거나 키 롤오버를 처리하도록 주기적인 수동 롤오버 프로세스를 설정하는 방법도 알아봅니다.
Microsoft ID 플랫폼의 서명 키 개요
Microsoft ID 플랫폼은 업계 표준을 기반으로 하는 공개 키 암호화를 사용하여 플랫폼 자체 및 이를 사용하는 애플리케이션 간의 신뢰를 구축합니다. 실질적인 측면에서 Microsoft ID 플랫폼은 공개 키 및 프라이빗 키 쌍으로 구성된 서명 키를 사용하는 방식으로 작동합니다. 사용자가 인증을 위해 Microsoft ID 플랫폼을 사용하는 애플리케이션에 로그인하면 Microsoft ID 플랫폼은 사용자에 대한 정보가 포함된 보안 토큰을 만듭니다. 이 토큰은 애플리케이션으로 다시 전송되기 전에 프라이빗 키를 사용하여 Microsoft ID 플랫폼 서명합니다. 해당 토큰이 유효하고 Microsoft ID 플랫폼에서 발생한 것인지 확인하기 위해 애플리케이션은 테넌트의 OpenID Connect Discovery 문서 또는 SAML/WS-Fed 페더레이션 메타데이터 문서에 포함된 Microsoft ID 플랫폼이 노출한 공개 키를 사용하여 토큰의 서명을 유효성 검사해야 합니다.
보안을 위해 Microsoft ID 플랫폼의 서명 키는 주기적으로 롤링하고, 비상 시에는 곧바로 롤오버될 수 있습니다. 이러한 키 롤 사이에는 설정되거나 보장된 시간이 없습니다. Microsoft ID 플랫폼 통합되는 모든 애플리케이션은 발생 빈도에 관계없이 키 롤오버 이벤트를 처리하도록 준비해야 합니다. 애플리케이션이 갑작스러운 새로 고침을 처리하지 않고 만료된 키를 사용하여 토큰의 서명을 확인하려고 하면 애플리케이션에서 토큰을 잘못 거부합니다. 표준 라이브러리를 사용하여 키 메타데이터가 올바르게 새로 고쳐지고 최신 상태로 유지되도록 하는 것이 좋습니다. 표준 라이브러리가 사용되지 않는 경우 구현이 모범 사례 섹션을 따르는지 확인합니다 .
OpenID Connect discovery 문서와 페더레이션 메타데이터 문서에는 사용 가능한 키가 항상 두 개 이상 있습니다. 하나의 키가 곧 롤오버되고 다른 키가 대체되는 방식으로 문서에 지정된 모든 키를 사용하도록 애플리케이션이 준비되어야 합니다. 새 플랫폼, 새 클라우드 또는 새 인증 프로토콜을 지원하므로 제공되는 키 수는 Microsoft ID 플랫폼 내부 아키텍처에 따라 점차 변경될 수 있습니다. JSON 응답에서 키의 순서나 키가 노출된 순서는 애플리케이션에 의미 있는 것으로 간주해서는 안 됩니다. JSON 웹 키 데이터 구조에 대해 자세히 알아보려면 RFC7517 참조할 수 있습니다.
단일 서명 키만 지원하는 애플리케이션 또는 서명 키에 대한 수동 업데이트가 필요한 애플리케이션은 본질적으로 보안이 떨어지고 안정성이 떨어집니다. 표준 라이브러리를 사용하도록 업데이트하여 다른 모범 사례 중에서도 항상 최신 서명 키를 사용하도록 해야 합니다.
키 메타데이터 캐싱 및 유효성 검사 모범 사례
- OIDC(OpenID Connect) 및 페더레이션 메타데이터에 설명된 대로 테넌트별 엔드포인트를 사용하여 키 검색
- 애플리케이션이 여러 테넌트에 배포되더라도 애플리케이션이 제공하는 각 테넌트에 대해 항상 독립적으로 키를 검색하고 캐시하는 것이 좋습니다(테넌트별 엔드포인트 사용). 오늘날 테넌트에서 공통적으로 사용되는 키는 나중에 테넌트 간에 고유해질 수 있습니다.
- 아래 캐싱 알고리즘을 사용하여 캐싱이 복원력 있고 안전한지 확인합니다.
키 메타데이터 캐싱 알고리즘:
표준 라이브러리는 복원력 있고 안전한 키 캐싱을 구현합니다. 구현에서 미묘한 결함을 방지하기 위해 사용하는 것이 좋습니다. 사용자 지정 구현의 경우 대략적인 알고리즘은 다음과 같습니다.
일반적인 고려 사항:
- 토큰의 유효성을 검사하는 서비스에는 많은 고유 키(10-1000)를 저장할 수 있는 캐시가 있어야 합니다.
- 키 ID(OIDC 키 메타데이터 사양의 "kid")를 캐시 키로 사용하여 키를 개별적으로 캐시해야 합니다.
- 캐시에 있는 키의 TSL(Time to Live)은 24시간으로 구성되어야 하며 새로 고침은 매시간 발생합니다. 이렇게 하면 시스템이 제거되는 키에 신속하게 응답할 수 있지만 키 가져오기의 문제로 인해 영향을 받지 않는 캐시 기간이 충분합니다.
- 키를 새로 고쳐야 합니다.
- 프로세스 시작 시 또는 캐시가 비어 있는 경우
- 백그라운드 작업으로 주기적으로(1시간마다 권장)
- 수신된 토큰이 알 수 없는 키(헤더의 알 수 없는 kid 또는 tid )로 서명된 경우 동적으로
KeyRefresh 프로시저(IdentityModel의 개념 알고리즘)
초기화
구성 관리자는 구성 데이터와 이 데이터를 검색하고 유효성을 검사하는 데 필요한 인터페이스를 가져오기 위해 특정 주소로 설정됩니다.
구성 검사
새 데이터를 가져오기 전에 시스템은 먼저 미리 정의된 새로 고침 간격에 따라 기존 데이터가 여전히 유효한지 확인합니다.
데이터 검색 데이터가 오래되었거나 누락된 경우 중복(및 스레드 고갈)을 방지하기 위해 하나의 스레드만 새 데이터를 가져오도록 시스템이 잠깁니다. 그런 다음 시스템은 지정된 엔드포인트에서 최신 구성 데이터를 검색하려고 시도합니다.
유효성 검사
새 데이터가 검색되면 필요한 표준을 충족하고 손상되지 않도록 유효성이 검사됩니다. 메타데이터는 들어오는 요청이 새 키로 성공적으로 유효성을 검사한 경우에만 허용됩니다.
오류 처리
데이터 검색 중에 오류가 발생하면 오류가 기록됩니다. 새 데이터를 가져올 수 없는 경우 시스템은 마지막으로 알려진 정상 구성으로 계속 작동합니다.
자동 업데이트 시스템은 새로 고침 간격에 따라 구성 데이터를 주기적으로 확인하고 업데이트합니다(12시간을 더하거나 뺀 1시간의 지터를 사용하는 것이 좋습니다). 또한 필요한 경우 수동으로 업데이트를 요청하여 데이터가 항상 최신인지 확인할 수 있습니다.
새 키를 사용하여 토큰의 유효성 검사 구성에서 아직 알려지지 않은 서명 키를 사용하여 토큰이 도착하는 경우 시스템은 활성 경로에서 동기화 호출을 사용하여 구성을 페치하여 일반 예상 업데이트 이외의 메타데이터에서 새 키를 처리하려고 시도합니다(하지만 5분 이하의 빈도는 없음).
이 접근 방식을 사용하면 시스템에서 항상 가장 최신의 유효한 구성 데이터를 사용하는 동시에 오류를 정상적으로 처리하고 중복 작업을 방지할 수 있습니다.
이 알고리즘의 .NET 구현은 BaseConfigurationManager에서 사용할 수 있습니다. 복원력 및 보안 평가에 따라 변경될 수 있습니다. 여기에 설명도 참조하세요.
KeyRefresh 프로시저(의사 코드):
이 절차에서는 전역(lastSuccessfulRefreshTime 타임스탬프)을 사용하여 키를 너무 자주 새로 고치는 조건을 방지합니다.
KeyRefresh(issuer)
{
// Store cache entries and last successful refresh timestamp per distinct 'issuer'
if (LastSuccessfulRefreshTime is set and more recent than 5 minutes ago)
return // without refreshing
// Load keys URI using the tenant-specific OIDC configuration endpoint ('issuer' is the input parameter)
oidcConfiguration = download JSON from "{issuer}/.well-known/openid-configuration"
// Load list of keys from keys URI
keyList = download JSON from jwks_uri property of oidcConfiguration
foreach (key in keyList)
{
cache entry = lookup in cache by kid property of key
if (cache entry found)
set expiration of cache entry to now + 24h
else
add key to cache with expiration set to now + 24h
}
set LastSuccessfulRefreshTime to now // current timestamp
}
서비스 시작 절차:
- 키를 업데이트하는 KeyRefresh
- 1시간마다 KeyRefresh를 호출하는 백그라운드 작업 시작
키의 유효성을 검사하기 위한 TokenValidation 프로시저(의사 코드):
ValidateToken(token)
{
kid = token.header.kid // get key id from token header
issuer = token.body.iss // get issuer from 'iss' claim in token body
key = lookup in cache by issuer and kid
if (key found)
{
validate token with key and return
}
else // key is not found in the cache
{
call KeyRefresh(issuer) // to opportunistically refresh the keys for the issuer
key = lookup in cache by issuer and kid
if (key found)
{
validate token with key and return
}
else // key is not found in the cache even after refresh
{
return token validation error
}
}
}
애플리케이션이 영향을 받을지 여부와 그에 대한 대처 방안을 평가하는 방법
애플리케이션이 키 롤오버를 처리하는 방식은 애플리케이션 유형 또는 사용된 ID 프로토콜 및 라이브러리 버전과 같은 변수에 따라 달라집니다. 아래 섹션에서는 가장 일반적인 유형의 애플리케이션이 키 롤오버의 영향을 받는지 여부와 자동 롤오버를 지원하거나 수동으로 키를 업데이트하도록 애플리케이션을 업데이트하는 방법에 대한 지침을 제공하는지 여부를 평가합니다.
- 리소스에 액세스하는 네이티브 클라이언트 애플리케이션
- 리소스에 액세스하는 웹 애플리케이션/API
- 리소스를 보호하고 Azure App Services를 사용하여 빌드된 웹 애플리케이션/API
- ASP.NET OWIN OpenID Connect, WS-Fed 또는 WindowsAzureActiveDirectoryBearerAuthentication 미들웨어를 사용하여 리소스를 보호하는 웹 애플리케이션/API
- ASP.NET Core OpenID Connect 또는 JwtBearerAuthentication 미들웨어를 사용하여 리소스를 보호하는 웹 애플리케이션/API
- Node.js
passport-azure-ad
모듈을 사용하여 리소스를 보호하는 웹 애플리케이션/API - 리소스를 보호하며 Visual Studio 2015 이상을 사용하여 만든 웹 애플리케이션/API
- 리소스를 보호하며 Visual Studio 2013을 사용하여 만든 웹 애플리케이션
- 리소스를 보호하며 Visual Studio 2013을 사용하여 만든 웹 API
- 리소스를 보호하며 Visual Studio 2012를 사용하여 만든 웹 애플리케이션
- 다른 라이브러리를 사용하거나 지원되는 프로토콜을 수동으로 구현하여 리소스를 보호하는 웹 애플리케이션/API
이 설명서는 다음에 적용할 수 없습니다 .
- Microsoft Entra Application Gallery(사용자 지정 포함)에서 추가된 애플리케이션에는 서명 키에 대한 별도의 지침이 있습니다. 추가 정보.
- 애플리케이션 프록시를 통해 게시된 온-프레미스 애플리케이션은 서명 키에 대해 걱정할 필요가 없습니다.
리소스에 액세스하는 네이티브 클라이언트 애플리케이션
리소스에만 액세스하는 애플리케이션(예: Microsoft Graph, KeyVault, Outlook API 및 기타 Microsoft API)은 토큰만 가져와 리소스 소유자에게 전달합니다. 리소스를 보호하지 못한다면 토큰을 검사하지 않으므로 제대로 서명되었는지 확인할 필요도 없습니다.
데스크톱 또는 모바일의 네티이브 클라이언트 애플리케이션이 이 범주에 해당하므로 롤오버의 영향을 받지 않습니다.
리소스에 액세스하는 웹 애플리케이션/API
리소스에만 액세스하는 애플리케이션(예: Microsoft Graph, KeyVault, Outlook API 및 기타 Microsoft API)은 일반적으로 토큰만 가져와 리소스 소유자에게 전달합니다. 리소스를 보호하지 못한다면 토큰을 검사하지 않으므로 제대로 서명되었는지 확인할 필요도 없습니다.
앱 전용 흐름을 사용하여 토큰을 요청하는 웹 애플리케이션 및 웹 API(클라이언트 자격 증명/클라이언트 인증서)가 이 범주에 해당하므로 롤오버의 영향을 받지 않습니다.
리소스를 보호하고 Azure App Services를 사용하여 빌드된 웹 애플리케이션/API
Azure App Services의 인증/권한 부여(EasyAuth) 기능에는 이미 키 롤오버를 자동으로 처리하는 데 필요한 논리가 있습니다.
ASP.NET OWIN OpenID Connect, WS-Fed 또는 WindowsAzureActiveDirectoryBearerAuthentication 미들웨어를 사용하여 리소스를 보호하는 웹 애플리케이션/API
애플리케이션에서 ASP.NET OWIN OpenID Connect, WS-Fed 또는 WindowsAzureActiveDirectoryBearerAuthentication 미들웨어를 사용 하는 경우, 자동으로 키 롤오버를 처리하는 데 필요한 논리가 이미 있는 것입니다.
애플리케이션의 Startup.cs 또는 Startup.Auth.cs 파일에서 다음 코드 조각을 찾아봄으로써 애플리케이션에서 이들 미들웨어를 사용하는지 확인할 수 있습니다.
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
// ...
});
app.UseWsFederationAuthentication(
new WsFederationAuthenticationOptions
{
// ...
});
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
// ...
});
.NET Core OpenID Connect 또는 JwtBearerAuthentication 미들웨어를 사용하여 리소스를 보호하는 웹 애플리케이션/API
애플리케이션에서 ASP.NET OWIN OpenID Connect 또는 JwtBearerAuthentication 미들웨어를 사용 하는 경우, 자동으로 키 롤오버를 처리하는 데 필요한 논리가 이미 있는 것입니다.
애플리케이션의 Startup.cs 또는 Startup.Auth.cs에서 다음 코드 조각을 찾아봄으로써 애플리케이션에서 이들 미들웨어를 사용하는지 확인할 수 있습니다.
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
// ...
});
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
// ...
});
Node.js passport-azure-ad
모듈을 사용하여 리소스를 보호하는 웹 애플리케이션/API
애플리케이션에서 Node.js passport-ad module을 사용하는 경우, 자동으로 키 롤오버를 처리하는 데 필요한 논리가 이미 있는 것입니다.
애플리케이션의 app.js에서 다음 코드 조각을 찾아봄으로써 애플리케이션 passport ad를 확인할 수 있습니다.
var OIDCStrategy = require('passport-azure-ad').OIDCStrategy;
passport.use(new OIDCStrategy({
//...
));
리소스를 보호하며 Visual Studio 2015 이상을 사용하여 만든 웹 애플리케이션/API
Visual Studio 2015 이상에서 웹 애플리케이션 템플릿을 사용하여 애플리케이션을 빌드했고 인증 변경 메뉴에서 회사 및 학교 계정을 선택한 경우 자동으로 키 롤오버를 처리하는 데 필요한 논리가 이미 있는 것입니다. OWIN OpenID Connect 미들웨어에 포함된 이 논리는 OpenID Connect discovery 문서에서 키를 검색하고 캐시하며 주기적으로 새로 고칩니다.
인증을 솔루션에 수동으로 추가하면 애플리케이션에 필요한 키 롤오버 논리가 없을 수도 있습니다. 사용자가 직접 작성하거나 웹 애플리케이션/다른 라이브러리를 사용하거나 지원되는 프로토콜을 수동으로 구현하는 API의 단계를 따를 수 있습니다.
리소스를 보호하며 Visual Studio 2013을 사용하여 만든 웹 애플리케이션
Visual Studio 2013에서 웹 애플리케이션 템플릿을 사용하여 애플리케이션을 빌드했고 인증 변경 메뉴에서 조직 계정을 선택한 경우 자동으로 키 롤오버를 처리하는 데 필요한 논리가 이미 있는 것입니다. 이 논리는 조직의 고유 ID 및 서명 키 정보를 프로젝트와 연결된 두 데이터베이스 테이블에 저장합니다. 프로젝트의 Web.config 파일에서 데이터베이스에 대한 연결 문자열을 찾을 수 있습니다.
인증을 솔루션에 수동으로 추가하면 애플리케이션에 필요한 키 롤오버 논리가 없을 수도 있습니다. 직접 작성하거나 다른 라이브러리를 사용하거나 지원되는 프로토콜을 수동으로 구현하는 웹 애플리케이션/API의 단계를 따라야 합니다.
다음 단계는 애플리케이션에서 논리가 제대로 작동하는지 확인하는 데 도움이 됩니다.
- Visual Studio 2013에서 솔루션을 열고 오른쪽 창에서 서버 탐색기 탭을 선택합니다.
- 데이터 연결, DefaultConnection, 테이블을 차례로 확장합니다. IssuingAuthorityKeys 테이블을 찾아 마우스 오른쪽 단추로 클릭한 후 테이블 데이터 표시를 선택합니다.
- IssuingAuthorityKeys 테이블에는 키에 대한 지문 값에 해당하는 행이 하나 이상 있습니다. 테이블의 모든 행을 삭제합니다.
- 테넌트 테이블을 마우스 오른쪽 단추로 클릭한 다음 테이블 데이터 표시를 선택합니다.
- 테넌트 테이블에는 고유한 디렉터리 테넌트 식별자에 해당하는 행이 하나 이상 있습니다. 테이블의 모든 행을 삭제합니다. Tenants 테이블과 IssuingAuthorityKeys 테이블 모두에서 행을 삭제하지 않으면 런타임에 오류가 발생합니다.
- 애플리케이션을 빌드 및 실행합니다. 계정에 로그인한 후에 애플리케이션을 중지할 수 있습니다.
- 서버 탐색기로 돌아가 IssuingAuthorityKeys 및 테넌트 테이블에서 값을 확인합니다. 페더레이션 메타데이터 문서의 적절한 정보로 자동으로 다시 채워진 것을 알 수 있습니다.
리소스를 보호하며 Visual Studio 2013을 사용하여 만든 웹 API
Visual Studio 2013에서 Web API 템플릿을 사용하여 Web API 애플리케이션을 만들었고 인증 변경 메뉴에서 조직 계정을 선택한 경우 애플리케이션에 필요한 논리가 이미 있는 것입니다.
인증을 수동으로 구성한 경우 아래 지침을 따라 키 정보를 자동으로 업데이트하는 웹 API를 구성하는 방법을 알아봅니다.
다음 코드 조각은 페더레이션 메타데이터 문서에서 최신 키를 가져온 후 JWT 토큰 처리기 를 사용하여 토큰의 유효성을 검사하는 방법을 보여 줍니다. 이 코드 조각은 Microsoft ID 플랫폼에서 향후 토큰의 유효성을 검사하기 위해 키를 유지하는 데 키 위치에 관계없이(데이터베이스, 구성 파일 또는 다른 곳) 고유의 캐싱 메커니즘을 사용한다고 가정합니다.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IdentityModel.Tokens;
using System.Configuration;
using System.Security.Cryptography.X509Certificates;
using System.Xml;
using System.IdentityModel.Metadata;
using System.ServiceModel.Security;
using System.Threading;
namespace JWTValidation
{
public class JWTValidator
{
private string MetadataAddress = "[Your Federation Metadata document address goes here]";
// Validates the JWT Token that's part of the Authorization header in an HTTP request.
public void ValidateJwtToken(string token)
{
JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler()
{
// Do not disable for production code
CertificateValidator = X509CertificateValidator.None
};
TokenValidationParameters validationParams = new TokenValidationParameters()
{
AllowedAudience = "[Your App ID URI goes here]",
ValidIssuer = "[The issuer for the token goes here, such as https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee/]",
SigningTokens = GetSigningCertificates(MetadataAddress)
// Cache the signing tokens by your desired mechanism
};
Thread.CurrentPrincipal = tokenHandler.ValidateToken(token, validationParams);
}
// Returns a list of certificates from the specified metadata document.
public List<X509SecurityToken> GetSigningCertificates(string metadataAddress)
{
List<X509SecurityToken> tokens = new List<X509SecurityToken>();
if (metadataAddress == null)
{
throw new ArgumentNullException(metadataAddress);
}
using (XmlReader metadataReader = XmlReader.Create(metadataAddress))
{
MetadataSerializer serializer = new MetadataSerializer()
{
// Do not disable for production code
CertificateValidationMode = X509CertificateValidationMode.None
};
EntityDescriptor metadata = serializer.ReadMetadata(metadataReader) as EntityDescriptor;
if (metadata != null)
{
SecurityTokenServiceDescriptor stsd = metadata.RoleDescriptors.OfType<SecurityTokenServiceDescriptor>().First();
if (stsd != null)
{
IEnumerable<X509RawDataKeyIdentifierClause> x509DataClauses = stsd.Keys.Where(key => key.KeyInfo != null && (key.Use == KeyType.Signing || key.Use == KeyType.Unspecified)).
Select(key => key.KeyInfo.OfType<X509RawDataKeyIdentifierClause>().First());
tokens.AddRange(x509DataClauses.Select(token => new X509SecurityToken(new X509Certificate2(token.GetX509RawData()))));
}
else
{
throw new InvalidOperationException("There is no RoleDescriptor of type SecurityTokenServiceType in the metadata");
}
}
else
{
throw new Exception("Invalid Federation Metadata document");
}
}
return tokens;
}
}
}
리소스를 보호하며 Visual Studio 2012를 사용하여 만든 웹 애플리케이션
Visual Studio 2012에서 애플리케이션을 빌드한 경우 애플리케이션을 구성하는 데 아마도 ID 및 액세스 도구를 사용한 것입니다. 또한 VINR(발급자 이름 레지스트리)의 유효성 검사도 사용할 수 있습니다. VINR은 발급된 토큰의 유효성을 검사하는 데 사용된 키와 신뢰할 수 있는 ID 공급자(Microsoft ID 플랫폼)에 대한 정보의 유지 관리를 담당합니다. 또한 VINR을 통해 해당 디렉터리에 연결된 최신 페더레이션 메타데이터 문서를 다운로드하고 구성이 최신 문서와 함께 만료되었는지 확인하며 필요에 따라 새 키를 사용하도록 애플리케이션을 업데이트하여 Web.config 파일에 저장된 키 정보를 자동으로 간편하게 업데이트할 수 있습니다.
Microsoft에서 제공하는 코드 샘플 또는 연습 문서를 사용하여 애플리케이션을 만든 경우 키 롤오버 논리가 프로젝트에 이미 포함됩니다. 아래 코드가 프로젝트에 이미 있다는 것을 알 수 있습니다. 애플리케이션에 이 논리가 아직 없는 경우 아래 단계에 따라 해당 논리를 추가하고 올바르게 작동하는지 확인합니다.
- 솔루션 탐색기에서 참조를 해당 프로젝트에 대한 System.IdentityModel 어셈블리에 추가합니다.
- Global.asax.cs 파일을 열고 지시문을 사용하여 다음을 추가합니다.
using System.Configuration; using System.IdentityModel.Tokens;
- Global.asax.cs 파일에 다음 메서드를 추가합니다.
protected void RefreshValidationSettings() { string configPath = AppDomain.CurrentDomain.BaseDirectory + "\\" + "Web.config"; string metadataAddress = ConfigurationManager.AppSettings["ida:FederationMetadataLocation"]; ValidatingIssuerNameRegistry.WriteToConfig(metadataAddress, configPath); }
- 아래와 같이 Global.asax.cs의 Application_Start() 메서드에서 RefreshValidationSettings() 메서드를 추가합니다.
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); ... RefreshValidationSettings(); }
이러한 단계를 완료하면 애플리케이션의 Web.config가 최신 키를 포함한 페더레이션 메타데이터 문서의 최신 정보로 업데이트됩니다. 이 업데이트는 애플리케이션 풀이 IIS에서 재활용될 때마다 발생하며 기본적으로 IIS는 29시간마다 애플리케이션을 재활용하도록 설정됩니다.
아래 단계에 따라 키 롤오버 논리가 제대로 작동하는지 확인합니다.
- 애플리케이션이 위의 코드를 사용 중인지를 확인한 후 Web.config 파일을 열고 <issuerNameRegistry> 블록으로 이동하여 구체적으로 다음 몇 줄을 확인합니다.
<issuerNameRegistry type="System.IdentityModel.Tokens.ValidatingIssuerNameRegistry, System.IdentityModel.Tokens.ValidatingIssuerNameRegistry"> <authority name="https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee/"> <keys> <add thumbprint="AA11BB22CC33DD44EE55FF66AA77BB88CC99DD00" /> </keys>
- <add thumbprint=""> 설정에서 모든 문자를 다른 것으로 바꿔서 지문 값을 변경합니다. Web.config 파일을 저장합니다.
- 애플리케이션을 빌드하고 실행합니다. 로그인 프로세스를 완료할 수 있으면 애플리케이션은 디렉터리의 페더레이션 메타데이터 문서에서 필요한 정보를 다운로드하여 키를 성공적으로 업데이트합니다. 로그인에 문제가 있는 경우 Microsoft ID 플랫폼 사용하여 웹 애플리케이션에 로그온 추가 문서를 읽거나 Microsoft Entra ID용 다중 테넌트 클라우드 애플리케이션 코드 샘플을 다운로드하고 검사하여 애플리케이션의 변경 내용이 올바른지 확인합니다.
다른 라이브러리를 사용하거나 지원되는 프로토콜을 수동으로 구현하여 리소스를 보호하는 웹 애플리케이션/API
다른 라이브러리를 사용하거나 지원되는 프로토콜을 수동으로 구현하는 경우 라이브러리 또는 구현을 검토하여 OpenID Connect 검색 문서 또는 페더레이션 메타데이터 문서에서 키를 검색하는지 확인해야 합니다. 이를 확인하는 하나의 방법은 OpenID discovery 문서 또는 페더레이션 메타데이터 문서에 대한 모든 호출 코드 또는 라이브러리 코드를 검색하는 것입니다.
키가 어딘가에 저장되거나 애플리케이션에 하드 코딩되는 경우 이 지침 문서의 끝에 있는 지침에 따라 수동 롤오버를 수행하여 수동으로 키를 검색하고 적절하게 업데이트할 수 있습니다. Microsoft ID 플랫폼의 롤오버 케이던스가 늘어나거나 긴급 대역 외 롤오버가 발생하는 경우, 향후 작업 중단 및 오버헤드를 방지하기 위해 이 문서에 설명된 방법 중 하나를 사용하여 자동 롤오버를 지원하도록 애플리케이션을 향상하는 것이 아주 좋습니다.
애플리케이션을 테스트하여 영향을 받을지 확인하는 방법
다음 PowerShell 스크립트를 사용하여 애플리케이션이 자동 키 롤오버를 지원하는지 여부를 검증할 수 있습니다.
PowerShell을 사용하여 서명 키를 확인하고 업데이트하려면 MSIdentityTools PowerShell 모듈이 필요합니다.
MSIdentityTools PowerShell 모듈을 설치합니다.
Install-Module -Name MSIdentityTools
관리자 계정으로 Connect-MgGraph 명령을 사용하여 로그인하여 필요한 범위에 동의합니다.
Connect-MgGraph -Scope "Application.ReadWrite.All"
사용 가능한 서명 키 지문 목록을 가져옵니다.
Get-MsIdSigningKeyThumbprint
키 지문을 선택하고 애플리케이션에서 해당 키를 사용하도록 Microsoft Entra ID를 구성합니다(Microsoft Entra 관리 센터에서 앱 ID 가져오기).
Update-MsIdApplicationSigningKeyThumbprint -ApplicationId <ApplicationId> -KeyThumbprint <Thumbprint>
로그인하여 새 토큰을 받고 웹 애플리케이션을 테스트합니다. 키 업데이트 변경은 즉각적이지만 새 브라우저 세션(예: Internet Explorer의 "InPrivate", Chrome의 "Incognito" 또는 Firefox의 "프라이빗" 모드 사용)을 사용하여 새 토큰을 발급했는지 확인합니다.
반환된 각 서명 키 지문에 대해
Update-MsIdApplicationSigningKeyThumbprint
cmdlet을 실행하고 웹 애플리케이션 로그인 프로세스를 테스트합니다.웹 애플리케이션에 사용자가 올바르게 로그인되면 자동 롤오버가 지원됩니다. 그렇지 않은 경우 수동 롤오버를 지원하도록 애플리케이션을 수정합니다. 자세한 내용은 수동 롤오버 프로세스 설정을 확인하세요.
정상적인 동작으로 되돌리려면 다음 스크립트를 실행합니다.
Update-MsIdApplicationSigningKeyThumbprint -ApplicationId <ApplicationId> -Default
애플리케이션에서 자동 롤오버를 지원하지 않는 경우 수동 롤오버를 수행하는 방법
애플리케이션이 자동 롤오버를 지원하지 않는 경우 주기적으로 Microsoft ID 플랫폼의 서명 키를 모니터링하고 적절하게 수동 롤오버를 수행하는 프로세스를 설정해야 합니다.
PowerShell을 사용하여 서명 키를 확인하고 업데이트하려면 PowerShell 모듈이 MSIdentityTools
필요합니다.
MSIdentityTools
PowerShell 모듈을 설치합니다.Install-Module -Name MSIdentityTools
최신 서명 키를 가져옵니다(Microsoft Entra 관리 센터에서 테넌트 ID 가져오기).
Get-MsIdSigningKeyThumbprint -Tenant <tenandId> -Latest
이 키를 애플리케이션이 현재 하드 코딩되었거나 사용하도록 구성된 키와 비교합니다.
최신 키가 애플리케이션에서 사용하는 키와 다른 경우 최신 서명 키를 다운로드합니다.
Get-MsIdSigningKeyThumbprint -Latest -DownloadPath <DownloadFolderPath>
새 키를 사용하도록 애플리케이션의 코드 또는 구성을 업데이트합니다.
애플리케이션에서 해당 최신 키를 사용하도록 Microsoft Entra ID를 구성합니다(Microsoft Entra 관리 센터에서 앱 ID 가져오기).
Get-MsIdSigningKeyThumbprint -Latest | Update-MsIdApplicationSigningKeyThumbprint -ApplicationId <ApplicationId>
로그인하여 새 토큰을 받고 웹 애플리케이션을 테스트합니다. 키 업데이트 변경은 즉각적이지만 새 브라우저 세션을 사용하여 새 토큰을 발급했는지 확인합니다. 예를 들어 Microsoft Edge의 "InPrivate", Chrome의 "Incognito" 또는 Firefox의 "프라이빗" 모드를 사용합니다.
문제가 발생하는 경우 사용 중이던 이전 키로 되돌리고 Azure 지원에 문의하세요.
Update-MsIdApplicationSigningKeyThumbprint -ApplicationId <ApplicationId> -KeyThumbprint <PreviousKeyThumbprint>
수동 롤오버를 지원하도록 애플리케이션을 업데이트한 후 정상적인 동작으로 되돌립니다.
Update-MsIdApplicationSigningKeyThumbprint -ApplicationId <ApplicationId> -Default