AgentID용 Microsoft Entra SDK와 함께 서명된 SHR(HTTP 요청)을 사용하여 PoP(소유 증명) 토큰 보안을 구현합니다. PoP 토큰은 토큰을 공개 키에 암호화적으로 바인딩하여 다운스트림 API를 호출할 때 토큰 도난 및 재생 공격을 방지합니다.
필수 조건
- 활성 구독이 있는 Azure 계정. 무료로 계정을 만듭니다.
- 소유 증명 지원을 사용하도록 설정된 상태로 배포되고 실행되는 AgentID용 Microsoft Entra SDK입니다. 설치 지침은 설치 가이드 를 참조하세요.
- RSA 키 쌍 - 암호화 서명을 위한 퍼블릭/프라이빗 키 쌍을 생성합니다. 공개 키는 SDK에서 구성되지만 프라이빗 키는 애플리케이션에서 안전하게 유지됩니다.
- PoP 토큰을 지원하는 다운스트림 API - 대상 API는 소유 증명 토큰의 유효성을 검사하고 공개 키를 사용하여 서명을 확인해야 합니다.
- Microsoft Entra ID의 적절한 권한 - 계정에 애플리케이션을 등록하고 PoP 설정을 구성할 수 있는 권한이 있어야 합니다.
키 쌍 생성
PoP 토큰을 구현하기 전에 RSA 키 쌍을 생성합니다. 프라이빗 키는 서명 요청을 위해 애플리케이션에 남아 있지만 공개 키는 AgentID용 Microsoft Entra SDK에서 구성됩니다.
# Generate RSA private key
openssl genrsa -out private.pem 2048
# Extract public key
openssl rsa -in private.pem -pubout -out public.pem
# Base64 encode public key for configuration
base64 -w 0 public.pem > public.pem.b64
# View base64-encoded key
cat public.pem.b64
구성 / 설정
RSA 공개 키 및 다운스트림 API 설정을 사용하여 AgentID용 Microsoft Entra SDK를 구성합니다. 보안 구성 저장소에 중요한 키를 저장합니다.
SDK 구성
apiVersion: v1
kind: Secret
metadata:
name: shr-keys
type: Opaque
data:
public-key: <base64-encoded-public-key>
---
apiVersion: v1
kind: ConfigMap
metadata:
name: sidecar-config
data:
# ... other configuration ...
DownstreamApis__SecureApi__BaseUrl: "https://api.contoso.com"
DownstreamApis__SecureApi__Scopes: "api://secureapi/.default"
DownstreamApis__SecureApi__AcquireTokenOptions__PopPublicKey: "<base64-public-key>"
사용 예제
애플리케이션에서 PoP 토큰을 사용하려면 공개 키를 지정하여 AgentID용 Microsoft Entra SDK에서 PoP 토큰을 요청한 다음 API 요청에 포함합니다.
TypeScript
// Request PoP token
async function getPopToken(incomingToken: string, publicKey: string): Promise<string> {
const sidecarUrl = process.env.SIDECAR_URL!;
const response = await fetch(
`${sidecarUrl}/AuthorizationHeader/SecureApi?` +
`optionsOverride.AcquireTokenOptions.PopPublicKey=${encodeURIComponent(publicKey)}`,
{
headers: {
'Authorization': incomingToken
}
}
);
const data = await response.json();
return data.authorizationHeader; // Returns "PoP <pop-token>"
}
// Use PoP token with signed request
async function callSecureApi(incomingToken: string, publicKey: string, privateKey: string) {
// Get PoP token from the SDK
const popToken = await getPopToken(incomingToken, publicKey);
// Make request to API with PoP token
const response = await fetch('https://api.contoso.com/secure/data', {
headers: {
'Authorization': popToken
}
});
return await response.json();
}
파이썬
import base64
import requests
import os
def get_pop_token(incoming_token: str, public_key: str) -> str:
"""Get a PoP token from the SDK."""
sidecar_url = os.getenv('SIDECAR_URL', 'http://localhost:5000')
response = requests.get(
f"{sidecar_url}/AuthorizationHeader/SecureApi",
params={
'optionsOverride.AcquireTokenOptions.PopPublicKey': public_key
},
headers={'Authorization': incoming_token}
)
response.raise_for_status()
data = response.json()
return data['authorizationHeader']
def call_secure_api(incoming_token: str, public_key_b64: str):
"""Call API with PoP token."""
pop_token = get_pop_token(incoming_token, public_key_b64)
response = requests.get(
'https://api.contoso.com/secure/data',
headers={'Authorization': pop_token}
)
return response.json()
요청당 SHR
다른 API 또는 범위에 대해 다른 공개 키를 지정하여 요청별로 PoP 설정을 재정의할 수 있습니다.
// Enable SHR for specific request
const response = await fetch(
`${sidecarUrl}/AuthorizationHeader/Graph?` +
`optionsOverride.AcquireTokenOptions.PopPublicKey=${encodeURIComponent(publicKey)}`,
{
headers: { 'Authorization': incomingToken }
}
);
암호 키 관리
RSA 키를 보호하고 필요한 경우 키 회전을 사용하도록 설정하는 보안 키 관리 방법을 구현합니다.
키 스토리지 보호
Kubernetes 비밀을 사용하여 RSA 키를 안전하게 저장합니다.
# Store keys in Kubernetes Secret
apiVersion: v1
kind: Secret
metadata:
name: shr-keys
type: Opaque
data:
public-key: <base64-encoded-public-key>
private-key: <base64-encoded-private-key>
---
# Mount keys in application
volumes:
- name: shr-keys
secret:
secretName: shr-keys
defaultMode: 0400
containers:
- name: app
volumeMounts:
- name: shr-keys
mountPath: /keys
readOnly: true
키 회전
OpenSSL을 사용하여 주기적으로 서명 키를 회전하고 구성을 업데이트합니다.
#!/bin/bash
# Script to rotate SHR keys
# Generate new key pair
openssl genrsa -out private-new.pem 2048
openssl rsa -in private-new.pem -pubout -out public-new.pem
base64 -w 0 public-new.pem > public-new.pem.b64
# Update Kubernetes secret
kubectl create secret generic shr-keys-new \
--from-file=public-key=public-new.pem.b64 \
--from-file=private-key=private-new.pem \
--dry-run=client -o yaml | kubectl apply -f -
# Update deployment to use new keys
kubectl rollout restart deployment myapp
PoP 토큰 유효성 검사
다운스트림 API는 PoP 토큰의 유효성을 검사하여 올바르게 서명되고 요청에 바인딩되었는지 확인해야 합니다.
- 토큰에서 추출된 공개 키를 사용하여 JWT 서명 확인
- 표준 JWT 클레임 유효성 검사(발급자, 대상 그룹, 만료)
- 클레임에
cnf예상된 공개 키가 포함되어 있는지 확인합니다. - 클레임의 키를 사용하여 HTTP 요청 서명이 일치하는지 확인합니다.
cnf
혜택
소유 증명 토큰을 사용하여 서명된 HTTP 요청을 구현하면 다음과 같은 몇 가지 보안 이점이 있습니다.
- 토큰 바인딩: 각 토큰은 특정 공개 키에 암호화적으로 바인딩되어 가로채더라도 무단 사용을 방지합니다.
- 재생 방지: 공격자는 해당 프라이빗 키를 보유하지 않고 캡처된 토큰을 재생할 수 없습니다.
- 향상된 보안: 토큰 도난에 대한 보호를 제공하며, 특히 중요한 작업 및 높은 보안 환경에 중요합니다.
- 소유 증명: 클라이언트가 토큰에 해당하는 프라이빗 키를 보유한다는 것을 암호화적으로 증명합니다.
모범 사례
서명된 HTTP 요청을 구현할 때 보안 및 운영 안정성을 유지하려면 다음 방법을 따르세요.
- 프라이빗 키 보호: 로그, 구성 파일 또는 코드 리포지토리에 프라이빗 키를 노출하지 않습니다. 키 볼트 또는 구성 관리 시스템을 사용하여 안전하게 저장합니다.
- 정기적으로 키 회전: 키 회전 일정을 구현하여 잠재적인 키 손상의 영향을 최소화합니다. 회전하는 동안 SDK 및 다운스트림 API를 모두 업데이트합니다.
- Per-API 키 사용: 다른 API 또는 보안 영역에 서로 다른 키 쌍을 사용하여 하나의 키가 손상된 경우 영향을 제한합니다.
- 사용량 모니터링: PoP 토큰 사용량을 감사하고 모니터링하여 의심스러운 패턴 또는 무단 액세스 시도를 검색합니다.
- 철저히 테스트: PoP 토큰 유효성 검사가 프로덕션에 배포하기 전에 올바르게 작동하는지 확인하여 서명 유효성 검사와 요청 바인딩 검사가 모두 통과했는지 확인합니다.
다음 단계
PoP 토큰을 구현한 후: