Kubernetes Secrets Backend¶
This topic describes how to configure Airflow to use Kubernetes Secrets as a secrets backend for retrieving connections, variables, and configuration.
This backend discovers secrets using Kubernetes labels, so the secret name does not matter. This makes it a natural fit when Airflow is running on Kubernetes and integrates well with tools like External Secrets Operator (ESO), Sealed Secrets, or any tool that creates Kubernetes secrets – regardless of naming conventions.
Before you begin¶
Before you start, make sure you have performed the following tasks:
Include the
cncf.kubernetesprovider as part of your Airflow installation:pip install apache-airflow-providers-cncf-kubernetes
Ensure Airflow is running inside a Kubernetes cluster (in-cluster mode).
Ensure the pod’s service account has permission to list secrets in the target namespace (by default, the namespace where Airflow runs).
Enabling the secret backend¶
To enable the Kubernetes secrets backend, specify
KubernetesSecretsBackend
as the backend in the [secrets] section of airflow.cfg.
Here is a sample configuration:
[secrets]
backend = airflow.providers.cncf.kubernetes.secrets.kubernetes_secrets_backend.KubernetesSecretsBackend
You can also set this with environment variables:
export AIRFLOW__SECRETS__BACKEND=airflow.providers.cncf.kubernetes.secrets.kubernetes_secrets_backend.KubernetesSecretsBackend
You can verify the correct setting of the configuration options with the airflow config get-value command:
$ airflow config get-value secrets backend
airflow.providers.cncf.kubernetes.secrets.kubernetes_secrets_backend.KubernetesSecretsBackend
Backend parameters¶
The following parameters can be passed via backend_kwargs as a JSON dictionary:
namespace: Kubernetes namespace to query for secrets. If not set, auto-detected from the pod’s service account. Default: auto-detectconnections_label: Label key used to discover connection secrets. Default:"airflow.apache.org/connection-id"variables_label: Label key used to discover variable secrets. Default:"airflow.apache.org/variable-key"config_label: Label key used to discover config secrets. Default:"airflow.apache.org/config-key"connections_data_key: The data key in the Kubernetes secret that holds the connection value. Default:"value"variables_data_key: The data key in the Kubernetes secret that holds the variable value. Default:"value"config_data_key: The data key in the Kubernetes secret that holds the config value. Default:"value"
For example, if you want to use custom label keys:
[secrets]
backend = airflow.providers.cncf.kubernetes.secrets.kubernetes_secrets_backend.KubernetesSecretsBackend
backend_kwargs = {"connections_label": "my-org.io/connection", "variables_label": "my-org.io/variable"}
Authentication¶
The backend uses in-cluster Kubernetes authentication directly via
kubernetes.config.load_incluster_config(). By default, the namespace is auto-detected
from the pod’s service account metadata
(/var/run/secrets/kubernetes.io/serviceaccount/namespace). You can override this by
setting the namespace parameter in backend_kwargs to query secrets from a different
namespace. No additional authentication configuration is required.
The backend does not use an Airflow connection or KubernetesHook, since the secrets backend itself is used to resolve connections (using a connection would create a circular dependency).
Optional lookup¶
Optionally connections, variables, or config may be looked up exclusive of each other or in any combination. This will prevent requests being sent to the Kubernetes API for the excluded type.
If you want to look up some and not others, set the relevant *_label parameter to null.
For example, if you only want to look up connections and not variables or config:
[secrets]
backend = airflow.providers.cncf.kubernetes.secrets.kubernetes_secrets_backend.KubernetesSecretsBackend
backend_kwargs = {"variables_label": null, "config_label": null}
Performance¶
The backend queries the Kubernetes API with resource_version="0", which tells the API server to
serve results from its in-memory watch cache. This makes lookups very fast without requiring any
Airflow-side caching.
If multiple secrets match the same label, the backend will use the first one and log a warning.
Storing and Retrieving Connections¶
To store a connection, create a Kubernetes secret with a label whose key matches connections_label
(default: airflow.apache.org/connection-id) and whose value is the connection id.
The actual secret value goes in the value data key (or whatever connections_data_key is set to).
The value should be the connection URI representation or the JSON format of the connection object.
Example secret YAML for a connection named smtp_default:
apiVersion: v1
kind: Secret
metadata:
name: my-smtp-secret # name can be anything
labels:
airflow.apache.org/connection-id: smtp_default
data:
value: <base64-encoded-connection-uri>
You can create a connection secret with kubectl:
kubectl create secret generic my-smtp-secret \
--from-literal=value='smtp://user:password@smtp.example.com:587' \
--namespace=airflow
kubectl label secret my-smtp-secret \
airflow.apache.org/connection-id=smtp_default \
--namespace=airflow
Or using a JSON connection format:
kubectl create secret generic my-postgres-secret \
--from-literal=value='{"conn_type": "postgres", "host": "db.example.com", "login": "user", "password": "pass", "port": 5432, "schema": "mydb"}' \
--namespace=airflow
kubectl label secret my-postgres-secret \
airflow.apache.org/connection-id=my_postgres_db \
--namespace=airflow
Storing and Retrieving Variables¶
To store a variable, create a Kubernetes secret with a label whose key matches variables_label
(default: airflow.apache.org/variable-key) and whose value is the variable key.
Example secret YAML for a variable named my_var:
apiVersion: v1
kind: Secret
metadata:
name: my-var-secret # name can be anything
labels:
airflow.apache.org/variable-key: my_var
data:
value: <base64-encoded-variable-value>
You can create a variable secret with kubectl:
kubectl create secret generic my-var-secret \
--from-literal=value='my_secret_value' \
--namespace=airflow
kubectl label secret my-var-secret \
airflow.apache.org/variable-key=my_var \
--namespace=airflow
Using with External Secrets Operator¶
The External Secrets Operator (ESO) can synchronize secrets from external stores (AWS Secrets Manager, HashiCorp Vault, GCP Secret Manager, Azure Key Vault, etc.) into Kubernetes secrets. This backend works seamlessly with ESO – simply configure ESO to add the appropriate Airflow label to the generated Kubernetes secret, and Airflow will discover it automatically. The secret name does not matter, only the label.
For example, an ESO ExternalSecret resource can use metadata.labels in its target template
to set airflow.apache.org/connection-id: <conn-id>.
This pattern allows you to use a single secrets backend configuration in Airflow while managing the actual secret values in your preferred external secret store.
Checking configuration¶
You can use the airflow connections get command to check if the connection is correctly read from
the backend secret:
$ airflow connections get smtp_default
Id: null
Connection Id: smtp_default
Connection Type: smtp
Host: smtp.example.com
Schema: ''
Login: user
Password: password
Port: 587
Is Encrypted: null
Is Extra Encrypted: null
Extra: {}
URI: smtp://user:password@smtp.example.com:587
To check that variables are correctly read from the backend secret, you can use
airflow variables get:
$ airflow variables get my_var
my_secret_value