Skip to content

feat(server): add credential storage drivers for Provider v2#2454

Draft
varshaprasad96 wants to merge 16 commits into
NVIDIA:mainfrom
varshaprasad96:feat/credential-storage-drivers
Draft

feat(server): add credential storage drivers for Provider v2#2454
varshaprasad96 wants to merge 16 commits into
NVIDIA:mainfrom
varshaprasad96:feat/credential-storage-drivers

Conversation

@varshaprasad96

@varshaprasad96 varshaprasad96 commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Summary

Add pluggable credential storage drivers so provider secrets are stored in external backends instead of inline in the gateway database. This implements the credential storage driver system described in issue #1931.

Three backends are supported:

  • Default encrypted DB credstore — AES-256-GCM envelope encryption with two-layer key wrapping (per-credential DEK wrapped by a KEK), stored in the gateway's existing object store
  • Kubernetes Secrets — credentials stored as Opaque Secrets in a configurable namespace with ownership validation
  • Vault — credentials stored in a Vault-compatible KV v1/v2 backend with Kubernetes or token-file authentication

Key design decisions

  • Opaque credential handles: Provider records store credential_handles (driver + handle reference) instead of inline secrets. API responses redact both inline and handle-based credentials.
  • CAS (Compare-And-Swap) lifecycle: Credentials are pre-stored externally before the CAS write to the gateway DB. On CAS failure, best-effort cleanup deletes stored handles with structured orphan warnings.
  • Dual-path coexistence: Provider.credentials (inline) and Provider.credential_handles (driver-managed) coexist for backward compatibility. Existing inline credentials remain readable; new operations use handles when a driver is configured.
  • Single driver enforcement: At most one external credential driver can be enabled at a time, validated at both Helm and runtime levels.

Improvements over PR #1986

This implementation is based on PR #1986 by @TaylorMutch with the following improvements:

  1. Parallel RPC dispatchstore_provider_credentials and delete_provider_credential_handles use futures::future::join_all instead of sequential loops
  2. Vault auth token caching — RwLock-based double-checked locking with TTL from lease_duration, avoiding re-authentication on every RPC
  3. Namespace enforcementallow_reference_namespace is now actually enforced at runtime in store/delete/resolve paths (was parsed but never checked)
  4. Additional credentials routingapply_minted_credential routes additional_credentials (e.g. AWS STS session tokens) through the driver instead of writing them inline as plaintext
  5. CAS failure cleanup in refresh — Stored handles are cleaned up on CAS failure in apply_minted_credential instead of being orphaned
  6. Enriched orphan warnings — Structured logging with handle_count, per-handle (key, driver, handle) tuples, and provider name
  7. RBAC documentation — YAML comment on the Role template and security note in docs explaining broad secrets access and dedicated namespace recommendation
  8. GitOps KEK supportdefaultKeyEncryptionKey Helm value for helm template workflows where lookup/randBytes are unavailable

Related Issue

Closes #1931

Changes

New crates

  • crates/openshell-driver-db-credstore/ — Default encrypted DB credential store (AES-256-GCM)
  • crates/openshell-driver-kubernetes-secrets/ — Kubernetes Secrets credential driver
  • crates/openshell-driver-vault/ — Vault credential driver

Server

  • crates/openshell-server/src/credentials.rs — Credential runtime, driver registry, parallel RPC dispatch
  • crates/openshell-server/src/grpc/provider.rs — CAS-aware credential handle lifecycle in create/update/delete
  • crates/openshell-server/src/provider_refresh.rs — Route refreshed credentials through driver with CAS cleanup
  • crates/openshell-server/src/inference.rs — Resolve credential handles for inference routes
  • crates/openshell-server/src/grpc/validation.rs — Credential handle field validation

Helm

  • KEK Secret template with lookup > user-supplied value > randBytes priority
  • Kubernetes Secrets RBAC (Role + RoleBinding) with namespace scoping
  • Gateway config rendering for all three driver backends
  • Helm unit tests for all configurations

Docs

  • docs/reference/gateway-config.mdx — Full credential drivers reference section
  • docs/sandboxes/providers-v2.mdx — User-facing credential storage documentation
  • architecture/gateway.md — Architecture documentation

E2E

  • e2e/rust/tests/credential_drivers.rs — End-to-end tests for K8s Secrets and Vault backends
  • CI workflow integration with test:e2e-kubernetes label

Testing

  • mise run pre-commit — lint, format, clippy all pass
  • mise run test — all unit tests pass (including new credential driver tests)
  • mise run helm:test — Helm unit tests pass (9 credential driver test cases)
  • test:e2e-kubernetes — E2E tests for K8s Secrets and Vault backends (CI)

Checklist

  • Conventional Commits format
  • Signed-off commits (DCO)
  • No secrets or credentials committed
  • Documentation updated (gateway-config.mdx, providers-v2.mdx, architecture/gateway.md)
  • AGENTS.md updated with new crate entries
  • CI.md and TESTING.md updated with new e2e test documentation

Co-authored-by: Taylor Mutch taylormutch@gmail.com

varshaprasad96 and others added 16 commits July 23, 2026 21:28
Add CredentialDriver gRPC service in openshell.credentials.v1 with
Store, Delete, Resolve, List, and GetCapabilities RPCs. Add
CredentialHandle message and credential_handles field to Provider.
Add credential_drivers and default_credential_driver to Config.

Refs: NVIDIA#1931

Co-authored-by: Taylor Mutch <taylormutch@gmail.com>
Signed-off-by: Varsha Prasad Narsing <varshaprasad96@gmail.com>
AES-256-GCM envelope encryption with per-credential DEK wrapped by
a KEK loaded from file or env var. Stores encrypted credential
envelopes in the gateway database via a DbCredstoreObjectStore trait
abstraction. Handle format: v1:<64-char-hex-id>.

Refs: NVIDIA#1931

Co-authored-by: Taylor Mutch <taylormutch@gmail.com>
Signed-off-by: Varsha Prasad Narsing <varshaprasad96@gmail.com>
Kubernetes Secrets driver: standalone UDS binary, deterministic
SHA-256 secret naming, managed-by labels, create-or-patch semantics.
Vault driver: standalone UDS binary, KV v1/v2 support, Kubernetes
JWT and token_file auth, path traversal prevention.

Refs: NVIDIA#1931

Co-authored-by: Taylor Mutch <taylormutch@gmail.com>
Signed-off-by: Varsha Prasad Narsing <varshaprasad96@gmail.com>
Add CredentialRuntime with driver registry, UDS transport management,
and ServerDbCredstoreObjectStore adapter. Wire into ServerState and
cli.rs config. Add credential_drivers and credential_storage config
fields. Add credential_handles field to all Provider struct literals.

Refs: NVIDIA#1931

Co-authored-by: Taylor Mutch <taylormutch@gmail.com>
Signed-off-by: Varsha Prasad Narsing <varshaprasad96@gmail.com>
Add credential handle validation, storage, and resolution to provider
create/update/delete/resolve flows. Reject user-supplied handles,
offload inline credentials to configured storage drivers, clean up
handles on failure, and resolve handles for provider environment.

Refs: NVIDIA#1931

Co-authored-by: Taylor Mutch <taylormutch@gmail.com>
Signed-off-by: Varsha Prasad Narsing <varshaprasad96@gmail.com>
…fresh

Add _with_credentials variants for inference bundle resolution and
route upsert. Thread credential runtime through provider refresh to
store refreshed tokens via credential driver when configured. Add
resolve_provider_credentials helper for handle-to-value resolution.

Refs: NVIDIA#1931

Co-authored-by: Taylor Mutch <taylormutch@gmail.com>
Signed-off-by: Varsha Prasad Narsing <varshaprasad96@gmail.com>
Add Helm values, templates, and validation for credential storage
drivers. Includes K8s Secrets RBAC role/rolebinding, retained KEK
secret for default DB credstore, gateway config TOML rendering,
CI values overlays, skaffold profiles, and Helm unit tests.

Refs: NVIDIA#1931

Co-authored-by: Taylor Mutch <taylormutch@gmail.com>
Signed-off-by: Varsha Prasad Narsing <varshaprasad96@gmail.com>
Add credential_drivers.rs e2e test covering K8s Secrets and Vault
backends. Add CI workflow job, e2e script support for credential
driver suites, OpenBao fixture deployment, and mise task.

Refs: NVIDIA#1931

Co-authored-by: Taylor Mutch <taylormutch@gmail.com>
Signed-off-by: Varsha Prasad Narsing <varshaprasad96@gmail.com>
Document credential driver configuration in gateway-config.mdx,
credential handle lifecycle in providers-v2.mdx, and architecture
notes. Update AGENTS.md, CI.md, and TESTING.md references.

Refs: NVIDIA#1931

Co-authored-by: Taylor Mutch <taylormutch@gmail.com>
Signed-off-by: Varsha Prasad Narsing <varshaprasad96@gmail.com>
Apply rustfmt formatting across server and e2e crates. Add
clippy allow for too_many_arguments on upsert_inference_route.
Fix CAS provider tests that failed because cloned providers now
carry credential_handles from the test-static driver — clear
handles before update requests and check both credentials and
credential_handles in concurrent update assertions.

Co-authored-by: Taylor Mutch <taylormutch@gmail.com>
Signed-off-by: Varsha Prasad Narsing <varshaprasad96@gmail.com>
Add YAML comment to credential-secrets-role.yaml explaining why
resourceNames cannot be used and recommending a dedicated namespace.
Add security note to gateway-config.mdx for the Kubernetes Secrets driver.

Support user-supplied defaultKeyEncryptionKey in values.yaml for
helm template / GitOps workflows where randBytes is not available.
Priority: existing Secret (lookup) > user-supplied value > random.

Co-authored-by: Taylor Mutch <taylormutch@gmail.com>
Signed-off-by: Varsha Prasad Narsing <varshaprasad96@gmail.com>
… context

Add handle_count, per-handle (key, driver, handle) tuples, and the
provider name to the warning emitted when pre-stored credentials
cannot be cleaned up after a failed provider update.

Co-authored-by: Taylor Mutch <taylormutch@gmail.com>
Signed-off-by: Varsha Prasad Narsing <varshaprasad96@gmail.com>
… resolve

Add validate_handle_namespace check after resolve_handle in store,
delete, and resolve paths. Returns permission_denied when a handle
targets a namespace other than the configured one and
allow_reference_namespace is false.

Co-authored-by: Taylor Mutch <taylormutch@gmail.com>
Signed-off-by: Varsha Prasad Narsing <varshaprasad96@gmail.com>
Add RwLock-based double-checked locking to avoid re-authenticating on
every credential RPC. TTL is derived from the Vault lease_duration
response with a 30-second safety buffer. TokenFile auth caches with
a fixed 30-second TTL to pick up file rotations.

Co-authored-by: Taylor Mutch <taylormutch@gmail.com>
Signed-off-by: Varsha Prasad Narsing <varshaprasad96@gmail.com>
Replace sequential for-loops in store_provider_credentials and
delete_provider_credential_handles with futures::future::join_all
for concurrent dispatch. Replaced-handle deletion is batched after
all stores succeed.

Co-authored-by: Taylor Mutch <taylormutch@gmail.com>
Signed-off-by: Varsha Prasad Narsing <varshaprasad96@gmail.com>
… on CAS failure

Store minted additional_credentials (e.g. AWS STS session tokens)
through the credential driver when one is active, instead of writing
them inline. On CAS failure, best-effort cleanup deletes all stored
handles with a structured orphan warning.

Co-authored-by: Taylor Mutch <taylormutch@gmail.com>
Signed-off-by: Varsha Prasad Narsing <varshaprasad96@gmail.com>
@copy-pr-bot

copy-pr-bot Bot commented Jul 24, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@varshaprasad96
varshaprasad96 marked this pull request as draft July 24, 2026 04:33
@varshaprasad96

Copy link
Copy Markdown
Contributor Author

Leaving this in draft mode, this is the rebased PR with some fixes on top of #1931.

Only one of #2437 or #2454 will be merged, so leaving it in drat mode for now.

@sjenning could you please take a look

@johntmyers

johntmyers commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Is this a dupe of #2437? Can we just pick one?

@varshaprasad96

Copy link
Copy Markdown
Contributor Author

Is this a dupe of #2437? Can we just pick one?

Yes, we are reviewing the changes in both, and will pick up. It was journey of huge rebase in 2 different ways. Which is why this is in draft. Will proceed with only one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: add credential drivers for provider secret storage

2 participants