Azure 리소스의 관리 ID는 Microsoft Entra ID에서 자동으로 관리되는 ID를 Azure 서비스에 제공합니다. 이 ID를 사용하면 코드에 자격 증명이 없어도 Microsoft Entra 인증을 지원하는 모든 서비스에 인증할 수 있습니다.
이 문서에서는 토큰 획득을 위한 다양한 코드 및 스크립트 예제를 제공합니다. 토큰 만료 및 HTTP 오류 처리에 대한 지침도 포함되어 있습니다.
필수 조건
이 문서에서 Azure PowerShell 예제를 사용하려는 경우 최신 버전의 Azure PowerShell을 설치해야 합니다.
중요합니다
- 이 문서의 모든 샘플 코드/스크립트는 클라이언트가 Azure 리소스에 대한 관리 ID가 있는 가상 머신에서 실행되고 있다고 가정합니다. Azure Portal의 가상 머신 "연결" 기능을 사용하여 VM에 원격으로 연결합니다. VM에서 Azure 리소스에 대한 관리 ID를 사용하도록 설정하는 방법에 대한 자세한 내용은 Azure Portal을 사용하여 VM에서 Azure 리소스에 대한 관리 ID 구성 또는 변형 문서 중 하나(PowerShell, CLI, 템플릿 또는 Azure SDK 사용)를 참조하세요.
중요합니다
- Azure 리소스에 대한 관리 ID의 보안 경계는 ID가 사용되는 리소스입니다. 가상 머신에서 실행되는 모든 코드/스크립트는 사용 가능한 모든 관리 ID에 대한 토큰을 요청하고 검색할 수 있습니다.
개요
클라이언트 애플리케이션은 지정된 리소스에 액세스하기 위해 관리 ID 앱 전용 액세스 토큰 을 요청할 수 있습니다. 토큰은 Azure 리소스 서비스 주체에 대한 관리 ID를 기반으로 합니다. 따라서 클라이언트가 자체 서비스 주체에 따라 액세스 토큰을 가져올 필요가 없습니다. 이 토큰은 클라이언트 자격 증명이 필요한 서비스 간 호출에서 전달자 토큰으로 사용하기에 적합합니다.
링크 | 설명 |
---|---|
HTTP를 사용하여 토큰 가져오기 | Azure 리소스 토큰 엔드포인트에 대한 관리 ID에 대한 프로토콜 세부 정보 |
Azure.Identity를 사용하여 토큰 가져오기 | Azure.Identity를 사용하여 C# 클라이언트에서 Azure 리소스 REST 엔드포인트에 관리 ID를 사용하는 예제 |
C를 사용하여 토큰 가져오기# | HttpClient를 사용하여 C# 클라이언트에서 Azure 리소스 REST 엔드포인트에 관리 ID를 사용하는 예제 |
Java를 사용하여 토큰 가져오기 | Java 클라이언트에서 Azure 리소스 REST 엔드포인트에 관리 ID를 사용하는 예제 |
Go를 사용하여 토큰 가져오기 | Go 클라이언트에서 Azure 리소스 REST 엔드포인트에 관리 ID를 사용하는 예제 |
PowerShell을 사용하여 토큰 가져오기 | PowerShell 클라이언트에서 Azure 리소스 REST 엔드포인트에 관리 ID를 사용하는 예제 |
CURL을 사용하여 토큰 가져오기 | Bash/CURL 클라이언트에서 Azure 리소스 REST 엔드포인트에 관리 ID를 사용하는 예제 |
토큰 캐싱 처리 | 만료된 액세스 토큰 처리 지침 |
오류 처리 | Azure 리소스 토큰 엔드포인트에 대한 관리 ID에서 반환된 HTTP 오류를 처리하기 위한 지침 |
Azure 서비스에 대한 리소스 ID | 지원되는 Azure 서비스에 대한 리소스 ID를 가져올 위치 |
HTTP를 사용하여 토큰 가져오기
액세스 토큰을 획득하기 위한 기본 인터페이스는 REST를 기반으로 하므로 HTTP REST 호출을 수행할 수 있는 VM에서 실행되는 모든 클라이언트 애플리케이션에 액세스할 수 있습니다. 이 방법은 클라이언트가 가상 머신에서 엔드포인트를 사용한다는 점을 제외하고 Microsoft Entra 프로그래밍 모델과 유사합니다(Microsoft Entra 엔드포인트와 비교).
AZURE IMDS(Instance Metadata Service) 엔드포인트를 사용하는 샘플 요청 (권장):
GET 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/' HTTP/1.1 Metadata: true
요소 | 설명 |
---|---|
GET |
HTTP 동사는 엔드포인트에서 데이터를 검색한다는 것을 나타냅니다. 이 경우에는 OAuth 액세스 토큰입니다. |
http://169.254.169.254/metadata/identity/oauth2/token |
인스턴스 메타데이터 서비스의 Azure 리소스 엔드포인트에 대한 관리 ID입니다. |
api-version |
IMDS 엔드포인트의 API 버전을 나타내는 쿼리 문자열 매개 변수입니다. API 버전 2018-02-01 이상 사용 |
resource |
쿼리 문자열 매개 변수는 대상 리소스의 앱 ID URI를 나타냅니다. 발급된 토큰의 aud (대상 그룹) 클레임에도 표시됩니다. 이 예제에서는 앱 ID URI https://management.azure.com/ 가 있는 Azure Resource Manager에 액세스하기 위해 토큰을 요청합니다. |
Metadata |
관리 ID에 필요한 HTTP 요청 헤더 필드입니다. 이 정보는 SSRF(서버 쪽 요청 위조) 공격에 대한 완화로 사용됩니다. 이 값은 모두 소문자에서 "true"로 설정해야 합니다. |
object_id |
(선택 사항) 토큰을 원하는 관리 ID의 object_id 나타내는 쿼리 문자열 매개 변수입니다. VM에 여러 사용자 할당 관리 ID가 있는 경우 필수입니다. |
client_id |
(선택 사항) 토큰을 원하는 관리 ID의 client_id 나타내는 쿼리 문자열 매개 변수입니다. VM에 여러 사용자 할당 관리 ID가 있는 경우 필수입니다. |
msi_res_id |
(선택 사항) 토큰을 원하는 관리 ID의 msi_res_id(Azure 리소스 ID)를 나타내는 쿼리 문자열 매개 변수입니다. VM에 여러 사용자 할당 관리 ID가 있는 경우 필수입니다. |
샘플 응답:
HTTP/1.1 200 OK
Content-Type: application/json
{
"access_token": "eyJ0eXAi...",
"refresh_token": "",
"expires_in": "3599",
"expires_on": "1506484173",
"not_before": "1506480273",
"resource": "https://management.azure.com/",
"token_type": "Bearer"
}
요소 | 설명 |
---|---|
access_token |
요청된 액세스 토큰입니다. 보안 REST API를 호출하면 토큰이 요청 헤더 필드에 "전달자" 토큰으로 포함 Authorization 되므로 API가 호출자를 인증할 수 있습니다. |
refresh_token |
Azure 리소스에 대한 관리 ID에서 사용되지 않습니다. |
expires_in |
액세스 토큰이 만료되기 전 발급 시점부터 계속 유효한 시간(초)입니다. 발급 시간은 토큰의 iat 클레임에서 찾을 수 있습니다. |
expires_on |
액세스 토큰이 만료되는 시간 범위입니다. 날짜는 "1970-01-01T0:0:0Z UTC"(토큰의 exp 클레임에 해당)의 초 수로 표시됩니다. |
not_before |
액세스 토큰이 적용되는 시간 범위이며 수락할 수 있습니다. 날짜는 "1970-01-01T0:0:0Z UTC"(토큰의 nbf 클레임에 해당)의 초 수로 표시됩니다. |
resource |
액세스 토큰이 요청된 리소스로, 요청의 resource 쿼리 문자열 매개 변수와 일치합니다. |
token_type |
"전달자" 액세스 토큰인 토큰의 유형입니다. 즉, 리소스가 이 토큰의 전달자에 대한 액세스 권한을 부여할 수 있습니다. |
Azure ID 클라이언트 라이브러리를 사용하여 토큰 가져오기
Azure ID 클라이언트 라이브러리를 사용하는 것이 관리 ID를 사용하는 권장 방법입니다. 모든 Azure SDK는 DefaultAzureCredential에 대한 지원을 제공하는 라이브러리와 Azure.Identity
통합됩니다. 이 클래스를 사용하면 Azure SDK에서 관리 ID를 쉽게 사용할 수 있습니다.자세한 정보
Azure.Identity 패키지 및 기타 필수 Azure SDK 라이브러리 패키지(예: Azure.Security.KeyVault.Secrets)를 설치합니다.
아래 샘플 코드를 사용합니다. 토큰을 가져오는 것에 대해 걱정할 필요가 없습니다. Azure SDK 클라이언트를 직접 사용할 수 있습니다. 이 코드는 필요한 경우 토큰을 가져오는 방법을 보여주기 위한 것입니다.
using Azure.Core; using Azure.Identity; string managedIdentityClientId = "<your managed identity client Id>"; var credential = new ManagedIdentityCredential(managedIdentityClientId); var accessToken = await credential.GetTokenAsync(new TokenRequestContext(["https://vault.azure.net"])); // To print the token, you can convert it to string var accessTokenString = accessToken.Token; // You can use the credential object directly with Key Vault client. var client = new SecretClient(new Uri("https://myvault.vault.azure.net/"), credential);
C를 사용하여 토큰 가져오기#
using System;
using System.Net.Http;
using Newtonsoft.Json.Linq;
// Construct HttpClient
var httpClient = new HttpClient
{
DefaultRequestHeaders =
{
{ "Metadata", Boolean.TrueString }
}
};
// Construct URI to call
var resource = "https://management.azure.com/";
var uri = $"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource={resource}";
// Make call
var response = await httpClient.GetAsync(uri);
try
{
response.EnsureSuccessStatusCode();
}
catch (HttpRequestException)
{
var error = await response.Content.ReadAsStringAsync();
Console.WriteLine(error);
throw;
}
// Parse response using Newtonsoft.Json
var content = await response.Content.ReadAsStringAsync();
var obj = JObject.Parse(content);
var accessToken = obj["access_token"];
Console.WriteLine(accessToken);
Java를 사용하여 토큰 가져오기
이 JSON 라이브러리 를 사용하여 Java를 사용하여 토큰을 검색합니다.
import java.io.*;
import java.net.*;
import com.fasterxml.jackson.core.*;
class GetMSIToken {
public static void main(String[] args) throws Exception {
URL msiEndpoint = new URL("http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/");
HttpURLConnection con = (HttpURLConnection) msiEndpoint.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("Metadata", "true");
if (con.getResponseCode()!=200) {
throw new Exception("Error calling managed identity token endpoint.");
}
InputStream responseStream = con.getInputStream();
JsonFactory factory = new JsonFactory();
JsonParser parser = factory.createParser(responseStream);
while(!parser.isClosed()){
JsonToken jsonToken = parser.nextToken();
if(JsonToken.FIELD_NAME.equals(jsonToken)){
String fieldName = parser.getCurrentName();
jsonToken = parser.nextToken();
if("access_token".equals(fieldName)){
String accesstoken = parser.getValueAsString();
System.out.println("Access Token: " + accesstoken.substring(0,5)+ "..." + accesstoken.substring(accesstoken.length()-5));
return;
}
}
}
}
}
Go를 사용하여 토큰 가져오기
package main
import (
"fmt"
"io/ioutil"
"net/http"
"net/url"
"encoding/json"
)
type responseJson struct {
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
ExpiresIn string `json:"expires_in"`
ExpiresOn string `json:"expires_on"`
NotBefore string `json:"not_before"`
Resource string `json:"resource"`
TokenType string `json:"token_type"`
}
func main() {
// Create HTTP request for a managed services for Azure resources token to access Azure Resource Manager
var msi_endpoint *url.___URL
msi_endpoint, err := url.Parse("http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01")
if err != nil {
fmt.Println("Error creating URL: ", err)
return
}
msi_parameters := msi_endpoint.Query()
msi_parameters.Add("resource", "https://management.azure.com/")
msi_endpoint.RawQuery = msi_parameters.Encode()
req, err := http.NewRequest("GET", msi_endpoint.String(), nil)
if err != nil {
fmt.Println("Error creating HTTP request: ", err)
return
}
req.Header.Add("Metadata", "true")
// Call managed services for Azure resources token endpoint
client := &http.Client{}
resp, err := client.Do(req)
if err != nil{
fmt.Println("Error calling token endpoint: ", err)
return
}
// Pull out response body
responseBytes,err := ioutil.ReadAll(resp.Body)
defer resp.Body.Close()
if err != nil {
fmt.Println("Error reading response body : ", err)
return
}
// Unmarshall response body into struct
var r responseJson
err = json.Unmarshal(responseBytes, &r)
if err != nil {
fmt.Println("Error unmarshalling the response:", err)
return
}
// Print HTTP response and marshalled response body elements to console
fmt.Println("Response status:", resp.Status)
fmt.Println("access_token: ", r.AccessToken)
fmt.Println("refresh_token: ", r.RefreshToken)
fmt.Println("expires_in: ", r.ExpiresIn)
fmt.Println("expires_on: ", r.ExpiresOn)
fmt.Println("not_before: ", r.NotBefore)
fmt.Println("resource: ", r.Resource)
fmt.Println("token_type: ", r.TokenType)
}
PowerShell을 사용하여 토큰 가져오기
다음 예제에서는 PowerShell 클라이언트에서 Azure 리소스 REST 엔드포인트에 대한 관리 ID를 사용하는 방법을 보여 줍니다.
- 액세스 토큰을 획득합니다.
- 액세스 토큰을 사용하여 Azure Resource Manager REST API를 호출하고 VM에 대한 정보를 가져옵니다. 구독 ID, 리소스 그룹 이름 및 가상 머신 이름을 각각
<SUBSCRIPTION-ID>
,<RESOURCE-GROUP>
,<VM-NAME>
로 대체해야 합니다.
Invoke-RestMeth -Method GET -Uri 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fmanagement.azure.com%2F' -Headers @{Metadata="true"}
응답에서 액세스 토큰을 구문 분석하는 방법의 예시는 다음과 같습니다:
# Get an access token for managed identities for Azure resources
$resource = 'https://management.azure.com'
$response = Invoke-RestMeth -Method GET `
-Uri 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=$resource' `
-Headers @{ Metadata="true" }
$content = $response.Content | ConvertFrom-Json
$accessToken = $content.access_token
Write-Host "Access token using a User-Assigned Managed Identity is $accessToken"
# Use the access token to get resource information for the VM
$secureToken = $accessToken | ConvertTo-SecureString -AsPlainText
$vmInfoRest = Invoke-RestMeth -Method GET `
-Uri 'https://management.azure.com/subscriptions/<SUBSCRIPTION-ID>/resourceGroups/<RESOURCE-GROUP>/providers/Microsoft.Compute/virtualMachines/<VM-NAME>?api-version=2017-12-01' `
-ContentType 'application/json' `
-Authentication Bearer `
-Token $secureToken
Write-Host "JSON returned from call to get VM info: $($vmInfoRest.content)"
CURL을 사용하여 토큰 가져오기
curl 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fmanagement.azure.com%2F' -H Metadata:true -s
응답에서 액세스 토큰을 구문 분석하는 방법의 예시는 다음과 같습니다:
response=$(curl 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fmanagement.azure.com%2F' -H Metadata:true -s)
access_token=$(echo $response | python -c 'import sys, json; print (json.load(sys.stdin)["access_token"])')
echo Access token using a User-Assigned Managed Identity is $access_token
토큰 캐싱
관리 ID 하위 시스템은 토큰을 캐시하지만 코드에서 토큰 캐싱을 구현하는 것이 좋습니다. 리소스가 토큰이 만료되었음을 나타내는 시나리오를 준비해야 합니다.
Microsoft Entra ID에 대한 온-더-와이어 호출은 다음 경우에만 결과를 생성합니다.
- Azure 리소스 하위 시스템 캐시의 관리 ID에 토큰이 없기 때문에 캐시 누락이 발생합니다.
- 캐시된 토큰이 만료되었습니다.
오류 처리
관리 ID 엔드포인트는 HTTP 응답 메시지 헤더의 상태 코드 필드를 통해 오류를 4xx 또는 5xx 오류로 신호합니다.
상태 코드 | 오류 원인 | 처리 방법 |
---|---|---|
404 찾을 수 없습니다. | IMDS 엔드포인트가 업데이트되고 있습니다. | 지수 백오프를 사용하여 다시 시도합니다. 아래 지침을 참조하세요. |
410 | IMDS가 업데이트를 진행합니다. | IMDS는 70초 이내에 사용할 수 있습니다. |
429 요청이 너무 많습니다. | IMDS 스로틀 제한에 도달했습니다. | 지수 백오프를 사용하여 다시 시도합니다. 아래 지침을 참조하세요. |
요청의 4xx 오류입니다. | 요청 매개 변수 중 하나 이상이 올바르지 않습니다. | 다시 시도하지 마세요. 자세한 내용은 오류 세부 정보를 확인하세요. 4xx 오류는 디자인 타임 오류입니다. |
서비스에서 5xx 일시적인 오류입니다. | Azure 리소스 하위 시스템 또는 Microsoft Entra ID에 대한 관리 ID가 일시적인 오류를 반환했습니다. | 1초 이상 기다린 후 다시 시도해도 안전합니다. 너무 빨리 또는 너무 자주 다시 시도하는 경우 IMDS 및/또는 Microsoft Entra ID는 속도 제한 오류(429)를 반환할 수 있습니다. |
시간 초과 | IMDS 엔드포인트가 업데이트되고 있습니다. | 지수 백오프를 사용하여 다시 시도합니다. 나중에 지침을 참조하세요. |
오류가 발생하면 해당 HTTP 응답 본문에 오류 세부 정보가 포함된 JSON이 포함됩니다.
요소 | 설명 |
---|---|
오류 | 오류 식별자 |
오류 설명 | 오류의 자세한 설명입니다. 오류 설명은 언제든지 변경할 수 있습니다. 오류 설명의 값을 기반으로 분기하는 코드를 작성하지 마세요. |
HTTP 응답 참조
이 섹션에서는 가능한 오류 응답을 문서화합니다. "200 OK" 상태는 성공적인 응답이며 액세스 토큰은 access_token 요소의 응답 본문 JSON에 포함됩니다.
상태 코드 | 오류 | 오류 설명 | 해결 방법 |
---|---|---|---|
400 잘못된 요청 | 잘못된_리소스 | AADSTS50001: <URI>라는 애플리케이션을 <TENANT-ID>라는 테넌트에서 찾을 수 없습니다. 이 메시지는 테넌트 관리자가 애플리케이션을 설치하지 않았거나 테넌트 사용자가 동의하지 않았는지를 보여줍니다. 잘못된 테넌트에 인증 요청을 보냈을 수 있습니다.\ | (Linux에만 해당) |
400 잘못된 요청 | 잘못된 요청_102 | 필수 메타데이터 헤더가 지정되지 않음 |
Metadata 요청 헤더 필드가 요청에서 누락되었거나 형식이 잘못 지정되었습니다. 값은 모두 소문자로 true 지정해야 합니다. 예제는 이전 REST 섹션의 "샘플 요청"을 참조하세요. |
401 권한 없음 | unknown_source | 알 수 없는 원본 <URI> | HTTP GET 요청 URI의 형식이 올바르게 지정되었는지 확인합니다. 부분은 scheme:host/resource-path .로 http://localhost:50342/oauth2/token 지정해야 합니다. 예제는 이전 REST 섹션의 "샘플 요청"을 참조하세요. |
잘못된_요청 | 요청에 필수 매개 변수가 없거나, 잘못된 매개 변수 값을 포함하거나, 매개 변수를 두 번 이상 포함하거나, 그렇지 않으면 형식이 잘못되었습니다. | ||
승인되지 않은 클라이언트 | 클라이언트는 이 메서드를 사용하여 액세스 토큰을 요청할 권한이 없습니다. | Azure 리소스에 대한 관리 ID가 올바르게 구성되지 않은 VM에 대한 요청으로 인해 발생합니다. VM 구성에 도움이 필요한 경우 Azure Portal을 사용하여 VM에서 Azure 리소스에 대한 관리 ID 구성을 참조하세요. | |
액세스 거부 | 리소스 소유자 또는 권한 부여 서버가 요청을 거부했습니다. | ||
지원되지 않는 응답 유형 | 권한 부여 서버는 이 방법을 사용하여 액세스 토큰 가져오기를 지원하지 않습니다. | ||
잘못된 범위 | 요청된 범위가 잘못되었거나 알 수 없거나 형식이 잘못되었습니다. | ||
500 내부 서버 오류 | 알 수 없음 | Active Directory에서 토큰을 검색하지 못했습니다. 자세한 내용은 파일 경로의 로그를 <참조하세요>. | VM에 Azure 리소스에 대한 관리 ID가 사용하도록 설정되어 있는지 확인합니다.
VM 구성에 도움이 필요한 경우 Azure Portal을 사용하여 VM에서 Azure 리소스에 대한 관리 ID 구성을 참조하세요. 또한 HTTP GET 요청 URI의 형식이 올바르게 지정되었는지, 특히 쿼리 문자열에 지정된 리소스 URI인지 확인합니다. Microsoft Entra 인증을 지원하는 Azure 서비스 목록 및 해당 리소스 ID는 이전 REST 섹션의 "샘플 요청"을 참조하거나 확인하세요. |
중요합니다
- IMDS는 프록시 뒤에서 사용할 수 없으며 지원되지 않습니다. 프록시를 바이패스하는 방법의 예제는 Azure Instance 메타데이터 샘플을 참조하세요.
다시 시도 지침
404, 429 또는 5xx 오류 코드가 표시되면 다시 시도합니다( 오류 처리 참조). 410 오류가 발생하면 IMDS가 업데이트를 거치고 있으며 최대 70초 안에 사용할 수 있음을 나타냅니다.
제한 제한은 IMDS 엔드포인트에 대한 호출 수에 적용됩니다. 스로틀링 임계값을 초과하면 IMDS 엔드포인트는 스로틀링이 진행되는 동안 추가 요청을 제한합니다. 이 기간 동안 IMDS 엔드포인트는 HTTP 상태 코드 429("너무 많은 요청")를 반환하고 요청이 실패합니다.
다시 시도하려면 다음 전략을 사용하는 것이 좋습니다.
재시도 전략 | 설정 | 값 | 작동 방식 |
---|---|---|---|
지수 백오프 (ExponentialBackoff) | 재시도 횟수 최소 백오프 최대 백오프 델타 백오프 첫 번째 빠른 다시 시도 |
5 0초 60초 2초 거짓 |
시도 1 - 지연 0초 시도 2 - 최대 2초 지연 시도 3 - 최대 6초 지연 시도 4 - 최대 14초 지연 시도 5 - 최대 30초 지연 |
Azure 서비스의 리소스 ID
Azure 리소스에 대한 관리 ID를 지원하는 리소스 목록은 관리 ID 지원이 있는 Azure 서비스를 참조하세요.
다음 단계
- Azure VM에서 Azure 리소스에 대한 관리 ID를 사용하도록 설정하려면 Azure Portal을 사용하여 VM에서 Azure 리소스에 대한 관리 ID 구성을 참조하세요.