Skip to content

feat(providers): support Kubernetes Secret credential sources for provider credentials #1882

Closed as not planned

Description

@rohancmr

Problem Statement

In multi-tenant Kubernetes deployments, platform teams commonly use External Secrets Operator to sync approved credentials from HashiCorp Vault, OpenBao, or another enterprise secret manager into Kubernetes Secrets.

In that model, the enterprise secret manager remains the source of truth. The Kubernetes Secret is the in-cluster handoff object that lets Kubernetes workloads consume approved credential material.

OpenShell providers currently store concrete credential values in OpenShell provider records. That works for local and simple deployments, but it creates friction for Kubernetes platforms because credentials must be copied into OpenShell instead of being resolved from the platform’s existing secret workflow.

OpenShell should support provider credentials backed by Kubernetes Secrets while preserving the current controlled supervisor/provider credential injection model.

Proposed Design

Add Kubernetes Secret as a provider credential source.

OpenShell should support two modes.

1. Explicit Secret key mapping

A provider credential can map one OpenShell credential key to one Kubernetes Secret key.

Example:

provider:
  name: nvbugs-gitlab
  type: gitlab
  credentials:
    GITLAB_TOKEN:
      source:
        type: kubernetesSecret
        namespace: tenant-nvbugs-prod
        name: nvbugs-provider-credentials
        key: gitlab-token

2. Secret extraction

A provider can reference a Kubernetes Secret and let OpenShell load multiple credential values from it.

Example:

provider:
  name: nvbugs-agent-secrets
  type: custom
  credentialsFrom:
    - source:
        type: kubernetesSecret
        namespace: tenant-nvbugs-prod
        name: nvbugs-provider-credentials
      mode: providerProfileKeys

providerProfileKeys imports Secret keys that match credentials declared by the provider profile.

A broader mode can allow importing all keys from the Secret:

credentialsFrom:
  - source:
      type: kubernetesSecret
      namespace: tenant-nvbugs-prod
      name: nvbugs-provider-credentials
    mode: allKeys

allKeys imports every key from the referenced Secret into the provider environment.

Runtime Behavior

Preferred flow:

  1. Platform syncs approved credentials from Vault/OpenBao/etc. into a Kubernetes Secret using ESO.
  2. Platform creates or references an OpenShell provider that points to the Kubernetes Secret.
  3. OpenShell Gateway validates that the caller is allowed to use that Secret reference.
  4. When a sandbox starts or refreshes provider environment, OpenShell resolves the Secret value.
  5. The supervisor receives provider credential material through the existing provider environment flow.
  6. The child agent receives placeholders, and OpenShell supervisor/proxy performs credential injection or rewrite according to provider policy.

A secondary implementation option is mounting the Kubernetes Secret into a supervisor-only path and letting the supervisor resolve provider credentials from that mounted Secret. This should only be used if OpenShell can guarantee the child agent process cannot read the mounted Secret directly. If supervisor and child agent share the same container filesystem/user boundary, gateway-side Secret resolution is safer.

Security Requirements

  • Kubernetes Secret references must be authorized before use.
  • Secret namespace, name, and key access must be scoped by caller identity or OpenShell policy.
  • Cross-tenant Secret reads must be denied by default.
  • Secret values must not appear in provider get/list output, logs, events, or audit records.
  • Audit records should include provider name, credential key, Secret reference, sandbox identity, and caller identity, but not the Secret value.
  • Missing, unauthorized, or unreadable Secrets should fail closed.
  • credentialsFrom extraction should support provider-profile-declared keys and full Secret extraction.

Alternatives Considered

Store credentials directly in OpenShell provider records

This works for simple deployments but does not fit Kubernetes platforms that already manage credential ownership, sync, rotation, and audit through Vault/OpenBao plus ESO.

Mount arbitrary Kubernetes Secrets directly into sandbox pods

This is Kubernetes-native but risky if the child agent can read the Secret file or env var directly. Provider credentials should continue to flow through OpenShell’s controlled supervisor/provider model.

Support only Vault/OpenBao directly

Vault/OpenBao should be a possible future backend, but many Kubernetes platforms already standardize on ESO as the bridge. Supporting Kubernetes Secret as a backend lets OpenShell integrate with multiple external secret managers through the Kubernetes-native handoff object.

Agent Investigation

I inspected the current provider and sandbox credential flow:

  • docs/sandboxes/providers-v2.mdx says Providers v2 combines provider credentials with provider-owned policy and that credential delivery still uses placeholder environment variables plus proxy rewrite.
  • proto/datamodel.proto defines Provider.credentials as map<string, string>, so provider records currently carry concrete credential values.
  • proto/openshell.proto has SandboxSpec.providers, and GetSandboxProviderEnvironment returns provider environment variables to the sandbox supervisor.
  • crates/openshell-sandbox/src/lib.rs fetches provider environment from the gateway during sandbox startup and refresh.
  • crates/openshell-sandbox/src/secrets.rs builds placeholder-based secret resolution from provider environment values.
  • crates/openshell-server/src/grpc/provider.rs resolves provider environment from stored provider records.
  • I did not find a dedicated Kubernetes Secret provider credential backend issue. The closest broader issue is Support platform-managed Kubernetes sandboxes with namespace, Secret, and SandboxClaim controls #1678.

Checklist

  • I've reviewed existing issues and the architecture docs
  • This is a design proposal, not a "please build this" request

Activity

  1. github-actions commented on Jun 27, 2026

    @github-actions

    This issue has had no activity for 14 days and is now marked stale. It may be closed in 7 days if there is no further activity. Comment or remove the state:stale label to keep it open.

  2. jackjin1997 commented on Jun 27, 2026

    @jackjin1997

    One security framing that may help keep this design tight: treat the Kubernetes Secret reference as a new credential authority boundary, not only as an alternate storage backend.

    Concrete acceptance tests I would add before this ships:

    Boundary Failure mode Test / guardrail
    Tenant / namespace binding caller in tenant A references tenant-b-prod Secret by name policy test denies cross-namespace and cross-tenant reads before any Secret fetch
    credentialsFrom: allKeys unrelated Secret keys become provider env and are later injectable make providerProfileKeys the default; require explicit policy for allKeys; snapshot test imported key names only
    Provider profile contract Secret has GITHUB_TOKEN but provider profile only declares GITLAB_TOKEN extraction drops undeclared keys unless policy opts into broad extraction
    Gateway vs mounted Secret child agent can read mounted Secret files directly e2e test proves child process only sees placeholders and cannot access the raw Secret path/env
    Audit / events / get-list APIs opaque token values appear in metadata, errors, or provider reads serialize every response/event path in a test and assert no raw Secret value or Authorization-shaped string appears
    Rotation / stale reads supervisor keeps using a deleted or rotated Secret indefinitely include Secret resourceVersion/resolvedAt in redacted evidence and define refresh/fail-closed behavior on not found/forbidden
    TOCTOU caller is authorized, then policy or Secret binding changes before sandbox refresh re-authorize at every resolve/refresh; do not rely only on provider creation-time approval
    Kubernetes RBAC OpenShell gateway service account can read every Secret in the cluster document least-privilege RBAC shape, ideally constrained by namespace/label/owner reference pattern

    The highest-risk design choice is the secondary mounted-Secret option. If supervisor and child share the same pod filesystem/user boundary, I would keep gateway-side resolution as the only supported v1 path; otherwise the controlled supervisor/provider injection model can be bypassed by ordinary file reads.

    Disclosure: I run fixed-scope no-secrets Agent Auth / credential-boundary reviews. If an outside pass on just this provider credential source would help, the focused USD $299 intake is here: https://github.com/jackjin1997/agent-audit-sprint/issues/new?template=agent-auth-review.yml. Payment only after written scope acceptance; no private repo access or secrets needed.

  3. github-actions commented on Aug 30, 2026

    @github-actions

    This issue has had no activity for 14 days and is now marked stale. It may be closed in 7 days if there is no further activity. Comment or remove the state:stale label to keep it open.

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions