Skip to main content

Reference existing Secrets

TL;DR

Keep credentials out of your Helm values file—point the Self-Deployed Runtime charts at Kubernetes Secrets you already manage.

Your AI can read this via Docs MCPInstall MCP →Connect

Many organizations require that credentials never appear in a values file, a Helm release, or a Git repository. On Kubernetes, the Self-Deployed Runtime charts support this: every sensitive value takes either a literal or a reference to a Kubernetes Secret you already manage, and you choose which.

This applies to both lifecycle modes—the SDR Orchestrator chart and each connector chart. The guided install wizard asks which you want and assembles the matching values file.

note

This is a Kubernetes capability. On Docker, the runtime reads its credentials from the generated config file and .env on the host, so protecting them is a host filesystem and access-control concern rather than a chart option.

What you can reference

ValueWhere you set the reference
Atlan OAuth clientId and clientSecretsdr.credentials.existingSecret (orchestrator chart) or global.credentialsSecret (connector chart)
Object store and secret store credentialsA secretKeyRef on any Dapr component metadata entry
Any other environment variablevalueFrom on an env entry, or a whole Secret via envFrom

Any tool that produces a Kubernetes Secret works—External Secrets Operator, the Secrets Store CSI driver, Sealed Secrets, or kubectl. The charts only read the Secret; they never create or modify it.

Before you begin

Make sure you have:

  • Permission to create Secrets in the namespace you install into.
  • The Atlan OAuth clientId and clientSecret for this deployment.
  • The name of the namespace you install into. For the orchestrator, this is also the namespace it deploys apps into.

Step 1: Create your secret

Create it in the install namespace, before you install the chart:

kubectl create secret generic atlan-sdr-oauth \
--namespace atlan \
--from-literal=client-id=YOUR_CLIENT_ID \
--from-literal=client-secret=YOUR_CLIENT_SECRET

Kubernetes Secrets are namespaced, so a Secret in another namespace can't be referenced.

Step 2: Reference it from your values file

Name the Secret and map your key names onto the two the runtime reads. The key names are yours to choose—omit either one to fall back to its default.

For the SDR Orchestrator chart:

sdr:
credentials:
existingSecret:
name: atlan-sdr-oauth
clientIdKey: client-id # default: ATLAN_AUTH_CLIENT_ID
clientSecretKey: client-secret # default: ATLAN_AUTH_CLIENT_SECRET

For a connector chart in single-app mode:

global:
credentialsSecret:
name: atlan-sdr-oauth
clientIdKey: client-id # default: ATLAN_AUTH_CLIENT_ID
clientSecretKey: client-secret # default: ATLAN_AUTH_CLIENT_SECRET

Leave the literal clientId and clientSecret fields empty, or remove them.

What changes when you do this

  • The chart creates no Secret of its own.
  • The literal clientId and clientSecret fields are ignored. The referenced Secret always wins, so a leftover literal can't quietly override it.
  • Nothing sensitive appears in your values file, in the Helm release, or in helm get values. Only the Secret name and the two key names are stored.
  • Orchestrator only: every app the orchestrator deploys references the same Secret. The orchestrator passes down the reference, not the credential, so no app pod carries it either.

Reference secrets from Dapr components

Object store and secret store credentials work the same way. Any metadata entry in a Dapr component can be a secretKeyRef instead of a literal value:

objectstore:
type: bindings.azure.blobstorage
version: v1
metadata:
- name: accountName
value: "mystorageaccount"
- name: containerName
value: "atlan-data"
- name: accountKey
secretKeyRef:
name: atlan-blob-creds
key: account-key

Omit key to default it to name.

A secretKeyRef is only a pointer, so the runtime also has to know which store resolves it:

  • By default, references resolve against the pod's environment. This is the route the OAuth reference in Step 2 uses, and it needs no extra configuration. It only works for values that already reach the pod's environment, so it isn't a route for your own cloud credentials.

  • For your own credentials, name the store that holds them—AWS Secrets Manager, Azure Key Vault, Vault, or the Kubernetes secret store:

    objectstore:
    type: bindings.azure.blobstorage
    version: v1
    metadata:
    - name: accountKey
    secretKeyRef:
    name: atlan-blob-creds
    key: account-key
    auth:
    secretStore: kubernetes-secrets

    The named store must itself be configured as a component.

Consider workload identity first

For cloud object and secret stores, the simplest way to keep credentials out of your values file is to not have credentials at all. IRSA on EKS, Workload Identity on GKE, and managed identities on AKS all let you omit accessKey and secretKey entirely. The orchestrator gives every app it deploys the same ServiceAccount it runs as, so you annotate one ServiceAccount and every app inherits the access.

App image version

For object store components, the runtime resolves the reference itself rather than through the Dapr sidecar. Resolving one from a cloud secret store therefore needs a current app image. If a component fails to start with an unresolved reference, update the app to its latest version, or use the environment-backed default instead. Secret store components are unaffected.

Rotate credentials

Update the Secret's contents, then restart the workloads. Kubernetes doesn't re-inject environment variables into a running pod when a Secret changes:

kubectl rollout restart deployment --namespace atlan

For the orchestrator, this restarts both the orchestrator and the apps it deploys, since they read the same Secret.

Troubleshooting

SymptomCause and fix
Pods stay in CreateContainerConfigErrorThe Secret doesn't exist in the install namespace, or a key name doesn't match. Check kubectl get secret atlan-sdr-oauth -n atlan -o jsonpath='{.data}' against the key names in your values file.
Authentication fails with the reference setConfirm you mapped the right keys: clientIdKey must name the key holding the client ID, not the client ID itself.
The runtime still shows a literal credentialA literal left in the values file is ignored, not used—check that the Secret name is set, and that you're looking at the right release with helm get values.
A component fails to initialize with an unresolved referenceThe store that resolves the reference isn't reachable. Either omit auth.secretStore to resolve from the pod environment, or confirm the named store is configured as a component and the app image is current.

See also