diff --git a/tests/v1/kv_offload/tiering/test_obj_tier.py b/tests/v1/kv_offload/tiering/test_obj_tier.py index 3df9d30691d..f429d6cf62d 100644 --- a/tests/v1/kv_offload/tiering/test_obj_tier.py +++ b/tests/v1/kv_offload/tiering/test_obj_tier.py @@ -25,6 +25,7 @@ from vllm.v1.kv_offload.base import ( make_offload_key, ) from vllm.v1.kv_offload.tiering.base import JobMetadata, JobResult +from vllm.v1.kv_offload.tiering.obj.config import ObjStoreConfig from vllm.v1.kv_offload.tiering.obj.manager import ObjectStoreSecondaryTierManager # --------------------------------------------------------------------------- @@ -418,3 +419,49 @@ class TestMockObjTierShutdown: tier, _ = _make_tier(num_blocks=4) tier.shutdown() tier.shutdown() # must not raise + + +class TestObjStoreConfig: + def test_explicit_credentials_included(self): + cfg = ObjStoreConfig( + bucket="b", + endpoint_override="ep", + access_key="ak", + secret_key="sk", + ) + params = cfg.to_nixl_params() + assert params["access_key"] == "ak" + assert params["secret_key"] == "sk" + + def test_credentials_omitted_when_empty(self): + cfg = ObjStoreConfig(bucket="b", endpoint_override="ep") + params = cfg.to_nixl_params() + assert "access_key" not in params + assert "secret_key" not in params + assert "session_token" not in params + assert "region" not in params + assert params["bucket"] == "b" + assert params["endpoint_override"] == "ep" + + def test_session_token_and_region_included(self): + cfg = ObjStoreConfig( + bucket="b", + endpoint_override="ep", + access_key="ak", + secret_key="sk", + session_token="tok", + region="us-east-1", + ) + params = cfg.to_nixl_params() + assert params["session_token"] == "tok" + assert params["region"] == "us-east-1" + + def test_ca_bundle_included_when_set(self): + cfg = ObjStoreConfig( + bucket="b", + endpoint_override="ep", + ca_bundle="/path/to/ca.pem", + ) + params = cfg.to_nixl_params() + assert params["ca_bundle"] == "/path/to/ca.pem" + assert "access_key" not in params diff --git a/vllm/v1/kv_offload/tiering/obj/config.py b/vllm/v1/kv_offload/tiering/obj/config.py index 5507c6a198e..76a1ae29e55 100644 --- a/vllm/v1/kv_offload/tiering/obj/config.py +++ b/vllm/v1/kv_offload/tiering/obj/config.py @@ -2,29 +2,45 @@ # SPDX-FileCopyrightText: Copyright contributors to the vLLM project """Connection configuration for the object store secondary tier.""" -from dataclasses import dataclass +from dataclasses import dataclass, field @dataclass class ObjStoreConfig: - """Connection parameters for an object store backend.""" + """Connection parameters for an object store backend. + + When ``access_key`` and ``secret_key`` are left empty the NIXL OBJ + plugin falls back to the AWS SDK default credential provider chain + (IAM roles, environment variables, credential files, etc.), which + enables workload-identity based auth on Kubernetes. + """ bucket: str endpoint_override: str - access_key: str - secret_key: str + access_key: str = field(default="", repr=False) + secret_key: str = field(default="", repr=False) + session_token: str = field(default="", repr=False) + region: str = "" scheme: str = "http" ca_bundle: str = "" def to_nixl_params(self) -> dict[str, str]: - """Build the NIXL backend params dict.""" + """Build the NIXL backend params dict. + + Credential and optional fields are only included when non-empty + so that the AWS SDK default credential chain can activate. + """ params: dict[str, str] = { "bucket": self.bucket, "endpoint_override": self.endpoint_override, "scheme": self.scheme, - "access_key": self.access_key, - "secret_key": self.secret_key, } - if self.ca_bundle: - params["ca_bundle"] = self.ca_bundle + # Omit empty optional fields so the NIXL OBJ plugin's underlying + # AWS SDK can fall back to its default credential provider chain + # (IAM roles, env vars, credential files, etc.). + # https://github.com/ai-dynamo/nixl/blob/main/src/plugins/obj/README.md + for key in ("access_key", "secret_key", "session_token", "region", "ca_bundle"): + value = getattr(self, key) + if value: + params[key] = value return params diff --git a/vllm/v1/kv_offload/tiering/obj/manager.py b/vllm/v1/kv_offload/tiering/obj/manager.py index 4c3fa754bf6..6060370ea06 100644 --- a/vllm/v1/kv_offload/tiering/obj/manager.py +++ b/vllm/v1/kv_offload/tiering/obj/manager.py @@ -157,8 +157,10 @@ class ObjectStoreSecondaryTierManager(SecondaryTierManager): except Exception as e: raise RuntimeError( f"Object store tier connectivity probe failed — check bucket, " - f"endpoint_override, access_key, secret_key, and scheme. " - f"Error: {e}" + f"endpoint_override, and scheme. If using explicit credentials " + f"verify access_key and secret_key; otherwise ensure the AWS " + f"SDK default credential chain is configured (IAM role, env " + f"vars, credential file). Error: {e}" ) from e def _exists(self, obj_key: str) -> bool: