Microsoft AI-103

Microsoft AI-103 시험 노트개념 정리21 MIN

관리 ID·프라이빗 네트워킹·역할 정책

키를 코드에서 걷어내는 길과 그 뒤에 서는 것들입니다. 시스템·사용자 할당 관리 ID를 가르고, Foundry·Search·Storage에 배정할 역할을 짚고, 프라이빗 엔드포인트가 공개 접근을 못 막는 자리를 봅니다.

앞의 네 노트가 무엇으로 만들고 어떻게 올리고 얼마나 쓰는지를 다뤘다면, 이 노트는 누가 부를 수 있는가입니다. 문항은 대개 요구사항 한 줄로 옵니다 — 「키를 소스 코드에 두지 않는다」·「이 엔드포인트는 사내망에서만 열린다」·「개발팀은 모델을 부를 수만 있고 배포는 못 한다」. 셋의 답이 각각 관리 ID, 프라이빗 엔드포인트, 역할 배정인데 보기에는 늘 셋이 섞여 나옵니다.

키 인증과 토큰 인증

리소스를 부르는 길이 둘이고, 이 노트의 나머지가 전부 두 번째 길 위에 세워집니다.

API 키

API 키는 리소스를 만들 때 함께 나오는 문자열로, 헤더에 그대로 실어 보내면 인증이 끝납니다. 간단한 대신 그 값을 쥔 쪽이 리소스 전체를 쥡니다 — 키에는 「이 호출자는 읽기만」 같은 구분이 없고, 로그를 봐도 어느 키가 왔는지까지만 남습니다.

Entra ID 토큰

Microsoft Entra ID는 Azure의 신원 관리 서비스이고, 여기서 받은 액세스 토큰으로 리소스를 부르면 요청에 호출자가 누구인지가 함께 실립니다. 그 신원에 배정된 역할이 할 수 있는 일의 범위를 정합니다. 두 길의 차이는 결국 「비밀을 아는가」와 「누구인가」의 차이입니다.

재는 것 API 키 Entra ID 토큰
실어 보내는 것 미리 나눠 준 문자열 만료되는 액세스 토큰
권한 구분 없다 — 전부 아니면 전무 역할 배정으로 나뉜다
유출 뒤 대응 키 회전 역할 배정 제거
로그에 남는 것 어느 키인지 어느 신원인지

키 회전

키가 두 개 나오는 이유가 여기 있습니다. 키 회전은 쓰던 키를 새 값으로 갈아 끼우는 일인데, 키가 하나뿐이면 가는 순간 서비스가 끊깁니다. 둘이면 순서를 이렇게 잡습니다 — 앱이 키1을 쓰는 동안 키2를 재생성하고, 앱 설정을 키2로 바꿔 배포하고, 트래픽이 다 넘어간 것을 확인한 뒤 키1을 재생성합니다. 이 네 걸음은 시험에서 순서를 묻는 문항으로 그대로 나옵니다.

키리스(keyless)는 한 걸음 더 나가 키를 아예 안 쓰는 구성입니다. 리소스에서 로컬 인증을 꺼 두면 키를 실은 요청이 거절되므로 「키가 유출되면」이라는 질문 자체가 성립하지 않습니다. 회전은 사고를 수습하는 절차이고 키리스는 사고가 날 자리를 없애는 구성이라, 둘은 대안이 아니라 층이 다릅니다.

관리 ID

토큰으로 부르려면 앱에도 신원이 있어야 합니다. 사람은 로그인해서 받지만 App Service나 Function에서 도는 코드는 그럴 수 없습니다. 관리 ID는 Azure가 자원에 붙여 주는 신원으로, 비밀을 어디에도 저장하지 않고 플랫폼이 토큰을 대신 받아 줍니다.

시스템 할당

시스템 할당 관리 ID는 자원 하나에 딸린 신원입니다. App Service에서 켜면 그 App Service의 신원이 생기고, 그 App Service를 지우면 신원도 함께 사라집니다. 자원과 신원이 1:1이고 수명이 같습니다.

사용자 할당

사용자 할당 관리 ID는 독립된 Azure 자원으로 따로 만들어 여러 자원에 붙이는 신원입니다. 자원 셋이 같은 신원을 공유할 수 있고, 붙어 있던 자원을 지워도 신원은 남습니다.

고르는 기준

상황 고르는 것
자원 하나가 제 몫만 부른다 시스템 할당
스케일 아웃되는 인스턴스 여럿이 같은 권한으로 부른다 사용자 할당
자원을 만들기 전에 역할을 먼저 배정해 두어야 한다 사용자 할당
자원을 지울 때 신원도 같이 지워지기를 바란다 시스템 할당

세 번째 줄이 시험이 좋아하는 자리입니다. 시스템 할당은 자원이 생겨야 신원이 생기므로 역할 배정이 배포 뒤로 밀리는데, 사용자 할당은 신원을 먼저 만들어 역할을 다 배정해 두고 자원에 붙이기만 하면 됩니다. 「새로 배포한 인스턴스의 첫 호출만 403으로 실패한다」는 증상이 이 차이에서 나옵니다.

코드에서는 자격 증명 객체 한 줄만 바뀝니다.

from azure.identity import ManagedIdentityCredential, get_bearer_token_provider
from openai import AzureOpenAI

credential = ManagedIdentityCredential(
    client_id="00000000-0000-0000-0000-000000000000")   # 시스템 할당이면 이 인자를 생략한다

client = AzureOpenAI(
    azure_endpoint="https://contoso-foundry.openai.azure.com/",
    azure_ad_token_provider=get_bearer_token_provider(
        credential, "https://cognitiveservices.azure.com/.default"),
    api_version="2024-10-21",
)

api_key 자리가 통째로 비어 있는 것이 이 조각의 요점입니다. 그리고 한 자원에 사용자 할당 신원이 둘 이상 붙어 있으면 client_id를 빼는 순간 어느 것으로 토큰을 받을지 정하지 못해 실패하므로, 그때는 반드시 짚어 줍니다.

역할 배정

신원이 생겼다고 부를 수 있는 것은 아닙니다. 역할 배정은 「어느 신원이 · 어느 역할로 · 어느 범위에서」 셋을 묶는 일이고, 셋 중 하나만 어긋나도 403이 납니다.

모델을 부르는 역할

역할 할 수 있는 일
Cognitive Services OpenAI User 배포된 모델을 부른다
Cognitive Services OpenAI Contributor 부르는 것에 더해 배포를 만들고 파인튜닝한다
Cognitive Services User 리소스를 읽고 키를 조회한다
Azure AI Developer 프로젝트 안에서 에이전트·인덱스·평가를 만든다

세 번째 줄이 함정입니다. 이름이 「User」라서 가장 낮아 보이지만 이 역할은 키를 읽어 갈 수 있습니다. 키를 못 쓰게 하려고 관리 ID로 옮겨 놓고 이 역할을 배정하면, 그 신원이 키를 조회해 예전 방식으로 부를 길이 그대로 남습니다. 추론만 시킬 생각이면 OpenAI User입니다.

Search와 Storage 역할

자원 역할 가르는 선
Search Search Service Contributor 인덱스·인덱서 같은 객체를 만들고 고친다. 문서 내용은 못 읽는다
Search Search Index Data Contributor 색인의 문서를 넣고 지운다
Search Search Index Data Reader 색인에 질의만 한다
Storage Storage Blob Data Reader blob 내용을 읽는다
Storage Storage Blob Data Contributor blob을 쓰고 지운다

Search가 두 층으로 갈려 있는 것이 핵심입니다 — 서비스 객체를 다루는 권한과 그 안의 문서를 다루는 권한이 다른 역할입니다. 그래서 인덱스를 만들 수 있는 신원이 그 인덱스의 문서는 못 읽는 구성이 정상이고, 질의만 하는 RAG 앱에는 Search Index Data Reader 하나면 충분합니다.

여기서 한 번 더 갈리는 자리가 어느 신원에 배정하는가입니다. 인덱서가 스토리지에서 문서를 끌어올 때 부르는 것은 앱의 신원이 아니라 Search 서비스 자신의 관리 ID이므로, Storage Blob Data Reader는 그쪽에 붙습니다. 「인덱서가 403으로 실패한다」는 문항의 답이 거의 항상 이 자리입니다.

범위

역할은 구독·리소스 그룹·리소스 어느 층에도 배정할 수 있고 위에서 준 것은 아래로 상속됩니다. 그래서 같은 역할이라도 범위를 어디에 잡았는지에 따라 실제 권한이 크게 달라집니다. 리소스 그룹에 배정하면 그 안에 나중에 생기는 자원까지 덮으므로, 편하다는 이유로 위층에 거는 것이 과잉 권한이 생기는 가장 흔한 길입니다.

프라이빗 네트워킹

프라이빗 엔드포인트

프라이빗 엔드포인트는 가상 네트워크의 서브넷에 사설 IP를 하나 잡아 그 IP로 리소스에 닿게 하는 장치입니다. 트래픽이 공용 인터넷을 타지 않고 Azure 백본으로만 흐릅니다. 같이 서야 하는 것이 프라이빗 DNS 영역입니다 — 앱은 여전히 원래 호스트 이름을 부르므로, 그 이름이 공인 IP 대신 사설 IP로 풀리도록 privatelink로 시작하는 DNS 영역을 VNet에 연결해 둡니다. 「프라이빗 엔드포인트를 만들었는데 여전히 공인 IP로 나간다」는 대개 이 연결이 빠진 것입니다.

공개 네트워크 액세스

가장 자주 틀리는 자리입니다. 프라이빗 엔드포인트를 만들어도 공개 네트워크 액세스는 그대로 열려 있습니다. 사설 길을 하나 낸 것이지 공개된 길을 닫은 것이 아니기 때문입니다. 바깥을 막으려면 그 설정을 「사용 안 함」이나 「선택한 네트워크만 허용」으로 따로 바꿔야 합니다. 「프라이빗 엔드포인트를 구성했는데 인터넷에서 키로 호출이 된다」는 버그가 아니라 걸음이 하나 남은 것입니다.

서비스 간 접근

바깥을 닫으면 우리 서비스끼리도 막힙니다. Search 인덱서가 프라이빗 엔드포인트 뒤의 스토리지를 읽어야 하는 구성이 대표적인데, 인덱서는 Search 서비스 안에서 도는 코드라 우리 VNet에 있지 않습니다. 그래서 Search 쪽에 그 스토리지로 가는 링크를 따로 승인해 두어야 합니다. Foundry도 같은 모양으로 관리되는 가상 네트워크를 두고 나가는 곳을 규칙으로 허용합니다. 시험이 「망을 잠갔더니 인덱싱이 멈췄다」를 물으면 답은 공개 접근을 되열기가 아니라 이 승인입니다.

최소 권한

최소 권한 원칙은 신원마다 그 일에 필요한 만큼만 주고 그 이상은 주지 않는 것입니다. 말은 간단한데 실제로 어기는 자리가 정해져 있습니다.

과잉 권한의 유형

  • 역할을 고민하기 싫어 리소스 그룹에 Contributor를 준다 — 역할과 범위가 한꺼번에 넓어집니다.
  • 키를 못 쓰게 막아 놓고 키를 조회할 수 있는 역할을 준다 — 막은 것이 없습니다.
  • 앱 여럿이 신원 하나를 돌려 쓴다 — 권한이 모든 앱의 합집합이 되고 로그에서 누가 불렀는지 안 갈립니다.
  • 개발자 계정에 배포 권한을 그대로 둔다 — 추론만 필요한데 모델 배포와 파인튜닝까지 열립니다.

403 진단 순서

순서가 있습니다. 먼저 어느 신원으로 불렀는지를 확인하고(사용자 할당이 여럿이면 여기서 이미 어긋납니다), 그 신원에 배정된 역할이 그 동작을 덮는지 보고, 배정한 범위가 지금 부르는 리소스를 덮는지 보고, 마지막으로 배정이 퍼질 시간이 지났는지 봅니다. 네 번째가 배포 직후에만 나타나는 증상이라 가장 헷갈립니다 — 구성은 맞는데 아직 반영이 안 된 상태와 구성이 틀린 상태는 로그에서 똑같이 403으로 보입니다.

연습 문제

  1. App Service에서 도는 앱이 Foundry의 모델을 부릅니다. 키를 코드와 설정 어디에도 두지 않아야 하고, 앱은 오토스케일로 인스턴스가 늘었다 줄었다 합니다. 가장 알맞은 구성은?
    ① 키를 Key Vault에 넣고 앱이 시작할 때 읽는다
    ② 사용자 할당 관리 ID를 만들어 App Service에 붙이고 Cognitive Services OpenAI User를 배정한다
    ③ 인스턴스마다 시스템 할당 관리 ID를 켜고 인스턴스마다 역할을 배정한다
    ④ 키 둘을 번갈아 쓰도록 앱에 회전 로직을 넣는다
    ②. ①은 키가 여전히 존재하므로 「키를 두지 않는다」를 못 지킵니다. ③은 성립하지 않습니다 — 시스템 할당 신원은 App Service 하나에 하나이고 인스턴스마다 생기지 않습니다. ④는 키를 계속 씁니다.
  2. 본문의 파이썬 조각에서 client_id 인자를 지웠습니다. 그 자원에 사용자 할당 관리 ID가 두 개 붙어 있을 때 일어나는 일은?
    ① 먼저 붙인 신원이 자동으로 쓰인다
    ② 시스템 할당 신원으로 자동으로 넘어간다
    ③ 어느 신원으로 토큰을 받을지 정하지 못해 인증이 실패한다
    ④ 두 신원의 권한을 합친 토큰을 받는다
    ③. 신원이 둘 이상일 때 client_id는 생략할 수 있는 값이 아닙니다. ④처럼 권한이 합쳐지는 일은 없습니다.
  3. RAG 앱이 Azure AI Search 색인에 질의만 합니다. 색인과 인덱서는 데이터 팀이 따로 관리합니다. 앱의 관리 ID에 배정할 역할은?
    ① Search Service Contributor
    ② Search Index Data Contributor
    ③ Search Index Data Reader
    ④ Storage Blob Data Reader
    ③. ①은 인덱스 객체를 만들고 고치는 역할이라 질의에는 과합니다. ②는 문서를 쓰고 지울 수 있어 역시 과합니다. ④는 대상 자원이 다릅니다.
  4. 인덱서가 Blob Storage에서 문서를 끌어오는데 실행마다 403으로 실패합니다. Search 서비스에는 시스템 할당 관리 ID가 켜져 있습니다. 확인할 곳은?
    ① 앱의 관리 ID에 Storage Blob Data Reader가 있는지
    ② Search 서비스의 관리 ID에 Storage Blob Data Reader가 있는지
    ③ 인덱서에 Search Index Data Contributor가 있는지
    ④ 스토리지 계정의 키가 회전되었는지
    ②. 스토리지를 부르는 것은 앱이 아니라 Search 서비스 자신입니다. ③은 색인에 쓰는 권한이라 읽어 오는 단계의 403과는 자리가 다르고, ④는 키를 안 쓰는 구성이므로 상관이 없습니다.
  5. Foundry 리소스에 프라이빗 엔드포인트를 만들고 프라이빗 DNS 영역까지 연결했습니다. 그런데 사무실 밖에서 키로 호출하면 여전히 응답이 옵니다. 원인은?
    ① DNS 영역이 잘못된 VNet에 연결되었다
    ② 프라이빗 엔드포인트가 아직 승인되지 않았다
    ③ 공개 네트워크 액세스가 열린 채로 남아 있다
    ④ 키가 회전되지 않았다
    ③. 프라이빗 엔드포인트는 사설 길을 내는 장치이지 공개된 길을 닫지 않습니다. ①과 ②라면 사내에서 사설 IP로 안 닿는 증상이 났을 것이고, 바깥에서 되는 것과는 무관합니다.
  6. 무중단으로 키를 회전해야 합니다. 앱은 지금 키1을 쓰고 있습니다. 올바른 순서는?
    ① 키1 재생성 → 앱을 키2로 변경 → 키2 재생성
    ② 키2 재생성 → 앱을 키2로 변경 → 키1 재생성
    ③ 앱을 키2로 변경 → 키2 재생성 → 키1 재생성
    ④ 키1과 키2를 함께 재생성 → 앱을 키2로 변경
    ②. 쓰고 있지 않은 키를 먼저 새로 만들고, 앱을 그쪽으로 옮기고, 트래픽이 다 넘어간 뒤 옛 키를 무효화합니다. ①은 첫 걸음에서 쓰던 키가 끊기고, ③은 앱을 옮긴 직후 그 키를 재생성해 다시 끊깁니다. ④는 두 키가 동시에 끊깁니다.

이 절의 문항은 「무엇을 켜면 되는가」보다 어느 신원에 붙는 설정인가를 묻습니다. 앱인지, 서비스 자신인지, 리소스인지를 먼저 가르면 보기 넷 중 둘은 그 자리에서 빠집니다.

Microsoft AI-103 시험 노트 전체 보기