[KV-Offloading] Support workload identity for objectstore secondary tier (#47063)

Signed-off-by: Pierangelo Di Pilato <pierdipi@redhat.com> Co-authored-by: Or Ozeri <oro@il.ibm.com>

Pierangelo Di Pilato committed Jul 7, 2026 at 15:30 UTC 65a7b4628409a77cc9d89246397e793ce41367fe
3 files changed +76 -11
tests/v1/kv_offload/tiering/test_obj_tier.py
+47
@@ -25,6 +25,7 @@ from vllm.v1.kv_offload.base import (
25 make_offload_key,
26 )
27 from vllm.v1.kv_offload.tiering.base import JobMetadata, JobResult
28 +from vllm.v1.kv_offload.tiering.obj.config import ObjStoreConfig
29 from vllm.v1.kv_offload.tiering.obj.manager import ObjectStoreSecondaryTierManager
30
31 # ---------------------------------------------------------------------------
@@ -418,3 +419,49 @@ class TestMockObjTierShutdown:
419 tier, _ = _make_tier(num_blocks=4)
420 tier.shutdown()
421 tier.shutdown() # must not raise
422 +
423 +
424 +class TestObjStoreConfig:
425 + def test_explicit_credentials_included(self):
426 + cfg = ObjStoreConfig(
427 + bucket="b",
428 + endpoint_override="ep",
429 + access_key="ak",
430 + secret_key="sk",
431 + )
432 + params = cfg.to_nixl_params()
433 + assert params["access_key"] == "ak"
434 + assert params["secret_key"] == "sk"
435 +
436 + def test_credentials_omitted_when_empty(self):
437 + cfg = ObjStoreConfig(bucket="b", endpoint_override="ep")
438 + params = cfg.to_nixl_params()
439 + assert "access_key" not in params
440 + assert "secret_key" not in params
441 + assert "session_token" not in params
442 + assert "region" not in params
443 + assert params["bucket"] == "b"
444 + assert params["endpoint_override"] == "ep"
445 +
446 + def test_session_token_and_region_included(self):
447 + cfg = ObjStoreConfig(
448 + bucket="b",
449 + endpoint_override="ep",
450 + access_key="ak",
451 + secret_key="sk",
452 + session_token="tok",
453 + region="us-east-1",
454 + )
455 + params = cfg.to_nixl_params()
456 + assert params["session_token"] == "tok"
457 + assert params["region"] == "us-east-1"
458 +
459 + def test_ca_bundle_included_when_set(self):
460 + cfg = ObjStoreConfig(
461 + bucket="b",
462 + endpoint_override="ep",
463 + ca_bundle="/path/to/ca.pem",
464 + )
465 + params = cfg.to_nixl_params()
466 + assert params["ca_bundle"] == "/path/to/ca.pem"
467 + assert "access_key" not in params
vllm/v1/kv_offload/tiering/obj/config.py
+25 -9
@@ -2,29 +2,45 @@
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 """Connection configuration for the object store secondary tier."""
4
5 -from dataclasses import dataclass
5 +from dataclasses import dataclass, field
6
7
8 @dataclass
9 class ObjStoreConfig:
10 - """Connection parameters for an object store backend."""
10 + """Connection parameters for an object store backend.
11 +
12 + When ``access_key`` and ``secret_key`` are left empty the NIXL OBJ
13 + plugin falls back to the AWS SDK default credential provider chain
14 + (IAM roles, environment variables, credential files, etc.), which
15 + enables workload-identity based auth on Kubernetes.
16 + """
17
18 bucket: str
19 endpoint_override: str
14 - access_key: str
15 - secret_key: str
20 + access_key: str = field(default="", repr=False)
21 + secret_key: str = field(default="", repr=False)
22 + session_token: str = field(default="", repr=False)
23 + region: str = ""
24 scheme: str = "http"
25 ca_bundle: str = ""
26
27 def to_nixl_params(self) -> dict[str, str]:
20 - """Build the NIXL backend params dict."""
28 + """Build the NIXL backend params dict.
29 +
30 + Credential and optional fields are only included when non-empty
31 + so that the AWS SDK default credential chain can activate.
32 + """
33 params: dict[str, str] = {
34 "bucket": self.bucket,
35 "endpoint_override": self.endpoint_override,
36 "scheme": self.scheme,
25 - "access_key": self.access_key,
26 - "secret_key": self.secret_key,
37 }
28 - if self.ca_bundle:
29 - params["ca_bundle"] = self.ca_bundle
38 + # Omit empty optional fields so the NIXL OBJ plugin's underlying
39 + # AWS SDK can fall back to its default credential provider chain
40 + # (IAM roles, env vars, credential files, etc.).
41 + # https://github.com/ai-dynamo/nixl/blob/main/src/plugins/obj/README.md
42 + for key in ("access_key", "secret_key", "session_token", "region", "ca_bundle"):
43 + value = getattr(self, key)
44 + if value:
45 + params[key] = value
46 return params
vllm/v1/kv_offload/tiering/obj/manager.py
+4 -2
@@ -157,8 +157,10 @@ class ObjectStoreSecondaryTierManager(SecondaryTierManager):
157 except Exception as e:
158 raise RuntimeError(
159 f"Object store tier connectivity probe failed — check bucket, "
160 - f"endpoint_override, access_key, secret_key, and scheme. "
161 - f"Error: {e}"
160 + f"endpoint_override, and scheme. If using explicit credentials "
161 + f"verify access_key and secret_key; otherwise ensure the AWS "
162 + f"SDK default credential chain is configured (IAM role, env "
163 + f"vars, credential file). Error: {e}"
164 ) from e
165
166 def _exists(self, obj_key: str) -> bool: