한 줄로 말하면

온비홀프(on-behalf-of, OBO) 토큰 교환은 에이전트가 사용자의 일을 대신 처리하되 사용자의 신원은 보존하고, 각 하위 서비스에 쓸 토큰은 그 서비스에만 묶어 새로 발급받는 방식이야. 다중 테넌트 에이전트에서는 “누가 요청했나”와 “어느 테넌트의 어느 API를 부르나”를 한 토큰에 뭉개지 않는 게 핵심이야.1

비유로 이해하기

여러 회사의 예약을 처리하는 여행 비서에게 원래 손님의 만능 출입증을 건네는 상황을 생각해 보자. 비서가 그 출입증을 그대로 들고 다니면, 어느 회사의 문이든 열어 달라고 할 수 있어. 반대로 비서 자신의 사원증만 내면, 문을 연 사람이 손님인지 비서인지 기록이 흐려져.

OBO는 비서가 매번 특정 회사의 특정 문에만 맞는 새 출입증을 받는 방식이야. 출입증에는 손님이 누구인지가 남고, 누가 대신 발급받았는지도 기록돼. 이 비유의 한계도 분명해. 실제 시스템은 출입증의 문자열이 아니라 서명된 토큰의 sub, aud, act 같은 클레임과 발급자 신뢰 관계로 접근을 검증해.

정확한 정의

OAuth 2.0 Token Exchange(RFC 8693)는 한 토큰을 권한 서버에 제시하고, 다른 대상(audience)과 권한 범위에 맞는 새 토큰을 받는 표준이야. AWS의 구현 안내에서는 이 교환을 에이전트 코드가 직접 처리하지 않고, 에이전트 게이트웨이와 신원 서비스가 하도록 구성해. 게이트웨이는 들어온 JWT를 검증하고 어느 테넌트의 도구를 부를지 고른 뒤, 신원 서비스가 해당 테넌트 권한 서버에 교환을 요청하게 해.1

토큰이 바뀔 때 중요한 것은 세 가지야.

  • sub는 원래 사용자를 가리키도록 보존해. 하위 API는 이 값을 기준으로 사용자의 권한과 자기 데이터만 판단할 수 있어.
  • aud는 호출할 하위 API로 바뀌어. 토큰이 특정 테넌트의 특정 서비스에만 유효하도록 만드는 경계야.
  • 교환을 수행한 주체는 별도 actor 정보로 남겨. RFC 8693의 act와 Okta의 cid처럼 ID 제공자마다 이름과 모양은 다를 수 있어.

그래서 하위 API는 “누구를 대신하나”를 sub에서, “누가 대신 행동했나”를 actor 정보에서 읽을 수 있어. 권한 결정은 사용자에게, 감사 기록과 호출량 제한은 대리 주체에게 연결하는 식이지.2

flowchart LR
    U["사용자"] --> P["제공자 권한 서버"]
    P -->|"Gateway 대상 토큰\naud=Gateway"| G["에이전트 Gateway"]
    G -->|"테넌트별 교환 요청"| I["신원 서비스"]
    I -->|"새 토큰\nsub=사용자\naud=테넌트 API"| T["테넌트 권한 서버"]
    T --> A["테넌트 API"]
    A --> L["업무 로직"]

왜 중요한가

다중 테넌트 에이전트에는 두 가지 쉬운 길이 있어. 하나는 에이전트 서비스 계정으로 모든 호출을 하는 거야. 그러면 하위 시스템은 에이전트를 무조건 믿어야 하고, 침해된 에이전트가 어느 테넌트의 사용자로든 행동할 수 있어. 다른 하나는 사용자가 처음 보낸 토큰을 그대로 전달하는 거야. 이 방식은 그 토큰의 audience가 하위 API와 정확히 맞을 때만 안전하게 쓸 수 있고, 에이전트가 여러 테넌트의 도구를 앞에 두는 구조에서는 그 조건이 잘 맞지 않아.3

이 문제를 confused deputy라고 불러. 대리인은 더 큰 권한을 갖고 있지만, 실제 요청자의 권한을 정확히 구분하지 못해 사용자의 의도보다 넓은 행동을 해 버리는 문제야. OBO는 이 권한을 한 번에 넓게 주는 대신, 사용자 신원은 이어 붙이고 사용처와 범위는 매 호출마다 좁히는 쪽으로 푼다. 하위 API는 에이전트를 무조건 믿지 않고, 자신이 신뢰하는 권한 서버가 발급한 audience-bound 토큰을 독립적으로 검증할 수 있어.4

다만 OBO가 자동으로 보안을 완성해 주는 건 아니야. 에이전트 런타임, 권한 서버, 하위 API가 모두 같은 신뢰 관계와 클레임 규칙을 이해해야 해. 하나라도 잘못 구성되면 권한 경계가 조용히 약해질 수 있어.5

실제 예시

AWS의 TravelBot 예시는 Acme와 Globex라는 두 테넌트의 예약 API를 앞에 둔 다중 테넌트 예약 도우미야. 사용자가 Gateway를 호출할 때는 Gateway용 audience와 gateway/invoke 범위를 가진 토큰을 제시해. Gateway가 Acme 도구를 고르면, 신원 서비스는 사용자의 들어온 토큰을 Acme 권한 서버에 보내고 Acme 예약 API를 audience로 지정한 새 토큰을 받아 와. 그 토큰은 Acme API의 JWT 검증기를 통과한 뒤 Lambda로 전달돼.6

Lambda는 OBO 토큰의 클레임을 읽어 테넌트별 결정을 내리고, 사용자 sub로 나뉜 DynamoDB 파티션에서 예약을 조회해. 이렇게 하면 토큰이 통과한 뒤의 업무 로직에서도 “이 요청이 어느 테넌트의 누구에게 속했나”를 다시 확인할 수 있어.7

여기서 권한 범위도 두 층으로 나뉘어. 교환 요청이 booking/readbooking/write를 요구하더라도, 사용자에게 실제로 허용된 authorized_scopesbooking/read만 될 수 있어. 토큰에 적힌 요청 범위와 사용자에게 계산된 유효 권한을 같은 것으로 취급하면 안 된다는 뜻이야.8

헷갈리지 말아야 할 점

  • OBO는 단순한 토큰 전달이 아니야. 들어온 토큰을 그대로 하위 API에 보내는 게 아니라, 하위 API의 audience와 필요한 범위에 맞춘 새 토큰을 발급받는 교환이야.
  • OBO와 impersonation은 같지 않아. impersonation처럼 사용자의 이름만 헤더에 적는 방식은 하위 API가 에이전트를 무조건 믿어야 해. OBO는 사용자와 대리 주체를 토큰의 서로 다른 정보로 남겨.
  • 테넌트 격리는 audience 하나로 끝나지 않아. 발급자, audience, 필수 scope, 사용자별 유효 권한을 하위 API가 함께 검증해야 해. AWS 예시에서는 테넌트별 API Gateway JWT authorizer가 마지막 방어선으로 이 검증을 맡아.9
  • 모든 ID 제공자가 같은 요청을 받는 건 아니야. AWS 글은 Okta가 subject_token_type=access_token과 정확한 audience를 요구하고, Microsoft Entra ID는 다른 grant 형태의 OBO를 사용한다고 설명해. RFC라는 공통 표준이 있어도 실제 요청 모양과 설정은 제공자별로 확인해야 해.10
  • 단일 테넌트와 같은 조건도 아니야. 들어온 토큰의 audience가 이미 하위 서비스와 맞는 단일 테넌트 에이전트라면 직접 전달이 충분할 수 있지만, 여러 테넌트나 여러 하위 서비스 앞에 선 에이전트는 별도의 교환 경계가 필요해.11

관련 문서

남은 질문들

  • RFC 8693의 subject token과 actor token은 서로 어떤 신뢰 경계를 만들고, ID 제공자별 차이를 어디까지 표준화할 수 있을까?
  • 테넌트가 늘어날 때 권한 서버 간 신뢰 관계와 클레임 검증 규칙을 어떻게 자동으로 테스트할까?
  • 토큰 교환 실패·만료·재시도 상황에서 에이전트가 권한을 넓히지 않고 복구하려면 어떤 관측값이 필요할까?

각주

  1. AWS, 「Implement on-behalf-of token exchange for multi-tenant agents with Amazon Bedrock AgentCore Gateway」(2026-07-13) 원문. ↩︎ ↩︎2

  2. AWS, 같은 글, 토큰 변환과 sub·aud·actor 클레임 설명. ↩︎

  3. AWS, 같은 글, 서비스 계정 가장·사용자 토큰 직접 전달과 confused deputy 비교. ↩︎

  4. AWS, 같은 글, audience 경계와 하위 API의 독립 검증 설명. ↩︎

  5. AWS, 같은 글, 에이전트 런타임·권한 서버·하위 API 설정 정렬 설명. ↩︎

  6. AWS, 같은 글, TravelBot의 Acme·Globex 다중 테넌트 요청 흐름. ↩︎

  7. AWS, 같은 글, Lambda와 DynamoDB의 사용자·테넌트별 업무 로직 설명. ↩︎

  8. AWS, 같은 글, scpauthorized_scopes의 차이 설명. ↩︎

  9. AWS, 같은 글, 테넌트별 API Gateway JWT authorizer 설명. ↩︎

  10. AWS, 같은 글, Okta·Microsoft Entra ID 등 ID 제공자별 교환 요청 차이 설명. ↩︎

  11. AWS, 같은 글, 단일 테넌트와 다중 테넌트에서 audience 조건 비교. ↩︎