Skip to content

Support file-based secret references ($file:) in config substitution #26509

@zshihang

Description

@zshihang

Summary

Add $file:/path/to/secret as a new reference format in ArgoCD's $-prefixed secret substitution, allowing config values to be resolved from files on disk.

Motivation

ArgoCD's $variable substitution currently only reads from Kubernetes Secrets ($key from argocd-secret, or $secretName:key from labeled secrets). There is no way to reference a secret value from a file.

This forces users who manage secrets outside of Kubernetes Secret objects into workarounds like bypassing argocd-dex rundex entirely with wrapper scripts, or using Kustomize patches to override the dex-server command — both fragile and hard to maintain across upgrades.

A file-based reference covers a wide range of secret delivery mechanisms:

  • Secrets Store CSI Driver (GCP Secret Manager, AWS Secrets Manager, Azure Key Vault, HashiCorp Vault) — mounts external secrets as files without creating K8s Secret objects in etcd
  • Projected volumes — assembling secrets from multiple sources
  • Init containers — fetching secrets at startup and writing to a shared volume
  • Any orchestration that places a secret on the filesystem before the main container starts

Proposal

Extend ReplaceStringSecret in util/settings/settings.go to recognize a $file: prefix:

// File-based secret reference: $file:/path/to/secret
if strings.HasPrefix(val, "$file:") {
    filePath := val[len("$file:"):]
    data, err := os.ReadFile(filePath)
    if err != nil {
        log.Warnf("config referenced file '%s', but could not read: %v", filePath, err)
        return val
    }
    return strings.TrimSpace(string(data))
}

Since ReplaceStringSecret is the central substitution function used by ReplaceMapSecrets, this automatically works everywhere $ references are currently supported — dex.config, oidc.config, and any other config value.

Usage

# argocd-cm ConfigMap
dex.config: |
  connectors:
    - type: oidc
      name: Google
      config:
        issuer: https://accounts.google.com
        clientID: $file:/etc/dex-secrets/client-id
        clientSecret: $file:/etc/dex-secrets/client-secret

The volume source is up to the user — CSI, projected volume, init container, etc. For example, with Secrets Store CSI Driver:

dex:
  volumes:
    - name: dex-secrets
      csi:
        driver: secrets-store.csi.k8s.io
        readOnly: true
        volumeAttributes:
          secretProviderClass: gcp-dex-config
  volumeMounts:
    - name: dex-secrets
      mountPath: /etc/dex-secrets
      readOnly: true

No wrapper scripts, no command overrides, no Kustomize patches. Standard argocd-dex rundex handles everything. Fully backwards compatible — existing $key and $secretName:key syntax unchanged

Related

  • #17875 — CSI Driver integration with ArgoCD
  • #5725 — Fallback to environment value when loading config

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requesttriage/pendingThis issue needs further triage to be correctly classified

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions