mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-22 00:31:44 +00:00
fix(azure_ai): mint an oidc Entra token only from the agent's own ids
The OIDC branch of the agent token mint handed a missing tenant_id or client_id to the shared helper, which fills them from the host's AZURE_TENANT_ID and AZURE_CLIENT_ID, so an agent carrying only an oidc/ token could be authenticated with the host's identity. The branch now needs both ids on the agent and otherwise fails with the credential help, which names the requirement
This commit is contained in:
parent
d4b5f05f97
commit
e5744c5d88
2 changed files with 39 additions and 4 deletions
|
|
@ -52,8 +52,8 @@ AZURE_ENTRA_LITELLM_PARAM_KEYS: Final = AZURE_ENTRA_CREDENTIAL_PARAM_KEYS | froz
|
|||
{"tenant_id", "client_id", "azure_username", "azure_scope"}
|
||||
)
|
||||
AZURE_ENTRA_CREDENTIAL_HELP: Final = (
|
||||
"Set `tenant_id` + `client_id` + `client_secret`, `azure_ad_token`, or "
|
||||
"`client_id` + `azure_username` + `azure_password` in the agent's `litellm_params`"
|
||||
"Set `tenant_id` + `client_id` + `client_secret`, `azure_ad_token` (an `oidc/` token also needs "
|
||||
"`tenant_id` + `client_id`), or `client_id` + `azure_username` + `azure_password` in the agent's `litellm_params`"
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -95,11 +95,12 @@ def get_azure_ai_agent_entra_token(litellm_params: Mapping[str, object]) -> str:
|
|||
return get_azure_ad_token_from_username_password(
|
||||
client_id=client_id, azure_username=azure_username, azure_password=azure_password, scope=scope
|
||||
)()
|
||||
if azure_ad_token and azure_ad_token.startswith("oidc/"):
|
||||
federated: Final = azure_ad_token is not None and azure_ad_token.startswith("oidc/")
|
||||
if azure_ad_token and federated and tenant_id and client_id:
|
||||
return get_azure_ad_token_from_oidc(
|
||||
azure_ad_token=azure_ad_token, azure_client_id=client_id, azure_tenant_id=tenant_id, scope=scope
|
||||
)
|
||||
if azure_ad_token:
|
||||
if azure_ad_token and not federated:
|
||||
return azure_ad_token
|
||||
raise ValueError(f"Azure AI agent Entra ID credentials did not resolve to a token. {AZURE_ENTRA_CREDENTIAL_HELP}")
|
||||
|
||||
|
|
|
|||
|
|
@ -263,6 +263,40 @@ def test_agent_entra_token_failure_names_the_credential_fields():
|
|||
get_azure_ai_agent_entra_token({"azure_scope": "https://ai.azure.com/.default"})
|
||||
|
||||
|
||||
def test_agent_oidc_token_without_agent_ids_never_borrows_the_host_identity(monkeypatch):
|
||||
"""The shared OIDC helper fills a missing client and tenant id from AZURE_CLIENT_ID and AZURE_TENANT_ID,
|
||||
which would exchange the host's federated token for the host's identity at that agent's URL."""
|
||||
monkeypatch.setenv("AZURE_TENANT_ID", "host-tenant")
|
||||
monkeypatch.setenv("AZURE_CLIENT_ID", "host-client")
|
||||
|
||||
with patch("litellm.llms.azure.common_utils.get_azure_ad_token_from_oidc") as mock_oidc: # test-quality-ok: stubs the OIDC exchange so a host-identity leak would show up as a call instead of a network round trip
|
||||
mock_oidc.return_value = "host-minted-token"
|
||||
|
||||
with pytest.raises(ValueError, match="oidc/"):
|
||||
get_azure_ai_agent_entra_token({"azure_ad_token": "oidc/github"})
|
||||
with pytest.raises(ValueError, match="oidc/"):
|
||||
get_azure_ai_agent_entra_token({"azure_ad_token": "oidc/github", "tenant_id": "agent-tenant"})
|
||||
|
||||
mock_oidc.assert_not_called()
|
||||
|
||||
|
||||
def test_agent_oidc_token_exchanges_with_the_agent_ids_and_scope():
|
||||
with patch("litellm.llms.azure.common_utils.get_azure_ad_token_from_oidc") as mock_oidc: # test-quality-ok: stubs the OIDC exchange to assert the agent's own ids and the Foundry scope reach it
|
||||
mock_oidc.return_value = "agent-minted-token"
|
||||
|
||||
token = get_azure_ai_agent_entra_token(
|
||||
{"azure_ad_token": "oidc/github", "tenant_id": "agent-tenant", "client_id": "agent-client"}
|
||||
)
|
||||
|
||||
assert token == "agent-minted-token"
|
||||
mock_oidc.assert_called_once_with(
|
||||
azure_ad_token="oidc/github",
|
||||
azure_client_id="agent-client",
|
||||
azure_tenant_id="agent-tenant",
|
||||
scope="https://ai.azure.com/.default",
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_agent_auth_header_is_the_entra_bearer():
|
||||
headers = await resolve_azure_ai_agent_auth_header({"azure_ad_token": "entra-token"})
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue