mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-14 23:21:35 +00:00
fix(oidc): guard naive STS expiration and wrap AWS ClientError as ValueError
This commit is contained in:
parent
a983177a4f
commit
af6ebf07ea
2 changed files with 61 additions and 5 deletions
|
|
@ -126,7 +126,8 @@ def _get_aws_sts_client(region: str) -> "STSClient":
|
|||
def _aws_oidc_cache_ttl(expiration: datetime | None) -> int | None:
|
||||
if expiration is None:
|
||||
return None
|
||||
remaining = int((expiration - datetime.now(timezone.utc)).total_seconds()) - 60
|
||||
aware_expiration = expiration if expiration.tzinfo is not None else expiration.replace(tzinfo=timezone.utc)
|
||||
remaining = int((aware_expiration - datetime.now(timezone.utc)).total_seconds()) - 60
|
||||
return remaining if remaining > 0 else None
|
||||
|
||||
|
||||
|
|
@ -145,12 +146,17 @@ def _get_aws_oidc_token(
|
|||
if isinstance(cached_token, str):
|
||||
return cached_token
|
||||
|
||||
from botocore.exceptions import ClientError
|
||||
|
||||
build_client = sts_client_factory or _get_aws_sts_client
|
||||
sts_client = build_client(_resolve_aws_region())
|
||||
response = sts_client.get_web_identity_token(
|
||||
Audience=[oidc_aud],
|
||||
SigningAlgorithm="RS256",
|
||||
)
|
||||
try:
|
||||
response = sts_client.get_web_identity_token(
|
||||
Audience=[oidc_aud],
|
||||
SigningAlgorithm="RS256",
|
||||
)
|
||||
except ClientError as e:
|
||||
raise ValueError(f"AWS OIDC provider failed: {e}") from e
|
||||
oidc_token = response["WebIdentityToken"]
|
||||
|
||||
ttl = _aws_oidc_cache_ttl(response.get("Expiration"))
|
||||
|
|
|
|||
|
|
@ -339,6 +339,56 @@ def test_oidc_aws_no_expiration_skips_caching():
|
|||
mock_cache.set_cache.assert_not_called()
|
||||
|
||||
|
||||
def test_oidc_aws_handles_naive_expiration():
|
||||
"""A naive Expiration from boto3 must not crash ttl computation."""
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
from litellm.secret_managers.main import _get_aws_oidc_token
|
||||
|
||||
naive_expiration = (datetime.now(timezone.utc) + timedelta(seconds=3600)).replace(tzinfo=None)
|
||||
fake_client = _FakeSTSClient(token="aws_jwt", expiration=naive_expiration)
|
||||
mock_cache = Mock()
|
||||
mock_cache.get_cache.return_value = None
|
||||
|
||||
with patch("litellm.secret_managers.main.oidc_cache", mock_cache):
|
||||
with patch("litellm.secret_managers.main._resolve_aws_region", return_value="us-east-1"):
|
||||
token = _get_aws_oidc_token(
|
||||
oidc_aud="aud",
|
||||
cache_key="oidc/aws/aud",
|
||||
sts_client_factory=Mock(return_value=fake_client),
|
||||
)
|
||||
|
||||
assert token == "aws_jwt"
|
||||
(cache_kwargs,) = mock_cache.set_cache.call_args_list
|
||||
assert 3500 <= cache_kwargs.kwargs["ttl"] <= 3540
|
||||
|
||||
|
||||
def test_oidc_aws_wraps_client_error():
|
||||
"""A boto3 ClientError is surfaced as a descriptive ValueError."""
|
||||
from botocore.exceptions import ClientError
|
||||
|
||||
from litellm.secret_managers.main import _get_aws_oidc_token
|
||||
|
||||
class _RaisingSTSClient:
|
||||
def get_web_identity_token(self, **kwargs):
|
||||
raise ClientError(
|
||||
{"Error": {"Code": "AccessDenied", "Message": "not authorized"}},
|
||||
"GetWebIdentityToken",
|
||||
)
|
||||
|
||||
mock_cache = Mock()
|
||||
mock_cache.get_cache.return_value = None
|
||||
|
||||
with patch("litellm.secret_managers.main.oidc_cache", mock_cache):
|
||||
with patch("litellm.secret_managers.main._resolve_aws_region", return_value="us-east-1"):
|
||||
with pytest.raises(ValueError, match="AWS OIDC provider failed"):
|
||||
_get_aws_oidc_token(
|
||||
oidc_aud="aud",
|
||||
cache_key="oidc/aws/aud",
|
||||
sts_client_factory=Mock(return_value=_RaisingSTSClient()),
|
||||
)
|
||||
|
||||
|
||||
def test_get_aws_sts_client_pins_regional_endpoint():
|
||||
from litellm.secret_managers.main import _get_aws_sts_client
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue