Safeguard
Security Guides•

How do you keep passwords out of airflow.cfg?

Airflow lets sensitive config options be resolved at run time with a _cmd or _secret suffix. Here is how each works, the precedence, and what to watch.

Safeguard Security Team
4 min read

Append _cmd or _secret to a sensitive option name in airflow.cfg, or to its environment variable, and Airflow resolves the value at run time. _cmd runs a command and uses its output. _secret reads the value from your configured secrets backend. Neither keeps a plain text password in the file.

Which options support it

The Airflow configuration docs list the options that accept the suffixes. They include the metadata database connection string (sql_alchemy_conn), the Fernet key, the Celery broker URL and result backend, the Flower basic auth value, the SMTP password and the API secret key and JWT secret. Other options do not get this treatment, so do not assume every setting can be externalised.

The docs state the intent plainly: not to store passwords on boxes in plain text files. That is a modest goal, and worth understanding as such. It moves the secret out of a file that gets committed, backed up and copied between hosts. It does not make the secret invisible to the process that uses it.

How the two suffixes differ

SuffixWhat Airflow doesWhat you must trust
_cmdRuns the shell command you give it and uses the outputWhoever can edit the config or the environment can run a command as the Airflow user
_secretLooks the key up in the secrets backendThe backend, its access policy and its naming convention

The _cmd route deserves a short review. A command in a config file is code execution at startup. If the file is writable by anyone beyond your deployment tooling, that is a way to run commands. Keep the file read only for the service account and change it only through reviewed deployment.

With _secret, the docs note that the key must follow the config prefix naming convention defined within the secrets backend. For example, sql_alchemy_conn is looked up under a config path such as airflow/config/sql_alchemy_conn, not under the connection prefix. A common mistake is storing the value under the connections prefix and then wondering why it never resolves.

Precedence trips people up

The docs give a fixed order of precedence for any option: an environment variable, then the command environment variable, then the secret environment variable, then the airflow.cfg value, then the command key in the file, then the secret key in the file, then the built in default.

Two practical consequences follow. A leftover plain environment variable will win over a _secret setting, so a stale value can silently override your vault lookup. And a plain value in airflow.cfg will win over a _cmd or _secret key in the same file. When you migrate, delete the plain value, do not just add the suffixed one next to it.

A short migration path

  1. List which of the supported options you currently set in plain text.
  2. Store each value in your secrets backend under the config prefix.
  3. Set the matching _secret key and remove the plain value everywhere it could appear: the file, the container environment, the deployment manifest.
  4. Restart the components and confirm they start with the value resolved.
  5. Rotate the old secret, since it lived in plain text for as long as it was there.

For connections and variables, the lookup order is a different topic; see Airflow secrets backend lookup order and pitfalls.

Where Safeguard fits

Config hygiene does not tell you whether the packages your scheduler and workers run are vulnerable. Safeguard's SBOM and dependency scanning covers that side, and you can run a free scan at gold.safeguard.sh/scan.

Quick check

Does _secret make the password invisible to Airflow admins?

No. It keeps the value out of plain text files. The process still holds the resolved value in memory, and anyone who can run code as that process can read it.

If I set both a plain value and a _secret key, which wins?

The plain value. Per the documented precedence, a plain environment variable or plain airflow.cfg entry is read before the _cmd and _secret forms in the same layer, so remove the plain value.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.