Why Airflow needs a Fernet key and when to rotate it
A self-hosted Airflow 3 deployment keeps connection and variable passwords in its metadata database, and the Fernet key is what keeps those values unreadable at rest. The key is set through the AIRFLOW__CORE__FERNET_KEY setting, and every component that reads an encrypted value needs it: the scheduler, the API server, the DAG processor and any worker that resolves a connection or variable. Rotating the key is therefore a planned maintenance task, not an emergency response. You change it on a schedule your change process approves, usually when key custody changes, when someone with access to the key leaves the team, or when your security policy calls for periodic rotation.
Before you plan a rotation, confirm three things in your own environment: where the current key is stored, which components read it from that location, and whether any of them run in a separate container image, virtual machine or namespace that would need the new value at the same moment. Ask your platform team to list every consumer, because a component still holding the old key after the cutover will fail to decrypt stored passwords. Also confirm whether your organization already keeps credentials in a secrets backend, since that changes how many encrypted values remain in the metadata database and how large the rotation scope is.
The rotation itself follows a documented sequence that the steps below walk through. It works because Airflow can hold several keys at once during the transition, so you should treat the window between adding the new key and removing the old one as a controlled change with a named owner and a rollback path. Before you start, back up the metadata database, since a failed rotation that you cannot reverse would leave encrypted values unreadable. The exact procedure and its prerequisites are in the Fernet documentation, which should be the reference your change ticket cites.
How to generate, store and set the Fernet key
This sequence produces a Fernet key that lives in your secret store, is set identically on every Airflow component, and is proven to decrypt the connections and variables you already have. Nothing is rotated until those checks pass.
Confirm the generation command
Before generating anything, open the Fernet section of the Airflow security documentation and confirm the current key generation command and the Python package it depends on. The documented approach uses the cryptography library, and the platform team should run the command in a controlled workstation or build environment rather than on a shared host. Record the Airflow version you are running so the documentation you check matches it. The step is complete when the team has a written command it has verified against the documentation.
Generate a new key in isolation
Run the confirmed command to produce a single base64 key of 32 bytes. Generate it on a machine that is not used for ad hoc debugging, and avoid pasting the output into tickets, chat or shell history. Keep the terminal output in memory only until it is written to the secret store in the next step. The check is that the output is one non-empty line and that it decodes to a 32-byte value, which you can confirm with a short test script that does not print the key.
Store the key in your secret store
Save the key in the organization's approved secret manager, such as the one used for other production credentials, with access limited to the people and service identities that deploy Airflow. Record the secret path, owner, and access policy in your configuration inventory. Keep a second copy under the same controls if your recovery process requires it, because losing the key makes every stored connection and variable password unreadable. The check is that a test identity with the deployment role can read the secret, and an identity without it cannot.
Expose the key to Airflow components
Inject the key as the environment variable AIRFLOW__CORE__FERNET_KEY, sourced from the secret store rather than from a values file or image layer. Use a Kubernetes Secret or your platform's equivalent, mounted into the scheduler, API server, DAG processor, triggerer and every worker pod or host. Do not commit the value to Git, and confirm that your deployment templates reference the secret by name. The check is that each component's running environment contains the variable, verified without printing its value, for example by checking that the variable is set and of the expected length.
Confirm every component uses the same key
Restart or roll each component so it reads the new environment, then confirm that all of them were started from the same secret version. Mismatched keys across components produce decryption errors that appear only when a task reads a connection or variable, so a healthy scheduler alone is not enough. Check the rollout status of each workload and note the secret version or revision in your change record. The check is that every component reports the same secret revision and that no component is still running an older pod or process.
Verify existing credentials still decrypt
Before any rotation, read a representative set of existing encrypted connections and variables through a test DAG or an authorized CLI session running on a worker, and confirm the stored passwords are returned in usable form. Include connections for each external system and at least one variable marked as sensitive, since these are the values that depend on the key. Run the check in a non-production instance first if you have one. The step is complete when every sampled credential decrypts, and any failure is resolved by finding the component or secret revision that holds the wrong key, not by regenerating credentials.
Handling the Fernet key in Kubernetes and VM deployments
In a Kubernetes deployment, the Fernet key should live in a Kubernetes Secret that the scheduler, API server, DAG processor and worker pods all reference through environment variables or mounted files. Every component that decrypts connection and variable passwords needs the same key set during rotation, so the Secret is the single place to change it. Keep the key out of Helm values files, ConfigMaps and manifests committed to Git, because those copies persist in repository history even after the Secret is updated.
- Create the Secret outside Git: Generate the key and create the Secret with your standard secret tooling or a sealed or external secret workflow, so the plain value never appears in a committed file.
- Reference it from every Airflow component: Wire the scheduler, API server, DAG processor and worker pods to the same Secret, and confirm each one reads the key you rotated to.
- Restrict RBAC to read it: Grant
geton the Secret only to the service accounts that run Airflow, and review who holds cluster-wide permissions to list or read Secrets. - Check encryption at rest: Kubernetes Secrets are base64-encoded, not encrypted by default. Confirm with your platform team whether your cluster encrypts Secrets at rest in etcd and whether backups of etcd are also encrypted.
- Scrub history after exposure: If a key was ever committed, treat it as exposed, rotate it, and plan how to remove it from Git history.
Before you finish, confirm which Secret each pod mounts and that no values file or manifest in your repository contains the key.
On virtual machines, the Fernet key usually reaches Airflow through the environment or a configuration file, and the risk comes from who can read that file or inspect the process. Choose one injection method for the whole installation and apply it to the scheduler, API server, DAG processor and every worker host, since a mismatched key on any host breaks decryption. The configuration file should be readable only by the Airflow service account, and the environment should come from a file that the service manager loads at start.
- Set strict file permissions: Limit the environment file or
airflow.cfgto the Airflow service user and root, with no group or world read access. - Inject through the service manager: Load
AIRFLOW__CORE__FERNET_KEYfrom an environment file referenced by your systemd unit or equivalent, so the key is not typed on the command line or saved in shell history. - Keep it out of shell history and logs: Avoid passing the key as a command argument, because process listings and audit tools can capture it.
- Synchronize every host: Update the key on each worker host and restart the affected services in the same change window during rotation.
- Control backups: Confirm that configuration backups and VM snapshots are protected to the same standard as the key itself.
Before you finish, check the file mode and owner on each host and confirm that the running processes load the key you expect.
Both environments store the same key material, so the verification steps should be identical in principle even though the commands differ. The aim is to show that every running component uses the new key, that no copy of the old key remains in a place an operator or pipeline can reach, and that the record of the change is available to auditors. Run these checks in staging before production, and again after the final key is removed from the environment.
- Confirm the running key: After restarts, check that connections and variables still decrypt in the UI or with the CLI, which shows the components agree on the key.
- Find stale copies: Search repositories, CI variables, container images and backup archives for the old key value.
- Record the change: Keep a dated change record that names the components restarted and who approved the change.
- Limit access to the key store: Review who can read the Secret or environment file, and remove access from people who no longer run Airflow.
- Test the restore path: Confirm that a restore from backup works with the key that matches the restored metadata database.
Confirm with your security and platform teams which of these checks your change process already requires.
Where rotation goes wrong
Fernet key rotation is simple on paper but touches every component that reads encrypted values. The risks below share one root cause: the set of keys that can decrypt stored data changes in steps, and any component, backup or copy that falls out of step can break reads or leak the key.
Components running with different keys
Schedulers, workers, the API server and the DAG processor each load AIRFLOW__CORE__FERNET_KEY from their own configuration. If one component still runs with only the old key after the new key is written to the database, it cannot decrypt values encrypted under the new key and tasks that read connections or variables fail. Check every deployment, Helm values file and secret that sets the key before starting the rotation, and confirm that each one receives the same comma-separated list.
Rotating without a metadata database backup
The rotation step re-encrypts stored passwords in place. If it fails partway, or a later change needs a rollback, the only way back to readable connections is a database snapshot taken before the rotation began. Take and verify a backup of the metadata database immediately before running airflow rotate-fernet-key, and record where it is stored so the restore path is known before anyone needs it.
Removing the old key too early
The old key must stay in the list until the rotation command has finished and every component has picked up the new configuration. Dropping it early leaves some encrypted values that were never re-encrypted unreadable, and the failure often appears only when a rarely used connection is next used. Keep both keys in place through the rotation, then remove the old key in a separate change once a test task has read a connection successfully.
Key committed to a repository or logged
Because the Fernet key decrypts every stored password, anyone who obtains it and the database together can read all connection credentials. Keys pasted into Helm values, CI variables, shell history or deployment manifests are a common source of exposure. Store the key in a Kubernetes Secret or the platform's secret manager, reference it by name rather than by value, and scan repositories and pipeline logs for the key pattern before and after rotation.
Multiple schedulers and API servers restarted at different times
Airflow supports more than one scheduler at once, and each API server and DAG processor instance also reads the key at startup. Restarting them in a rolling sequence while some still hold the old list can produce a window where some instances decrypt values and others fail. Plan the rollout so the new key list reaches every instance before the rotation runs, then restart the fleet in a defined order and watch for decryption errors in each component's logs.
Stored credentials kept after a secrets backend move
Moving connections into a secrets backend does not remove the encrypted copies already in the metadata database. Those rows still depend on the Fernet key, so a team that considers the key retired may still keep it alive for years. Once a backend serves the credentials, plan a cleanup of stored connections and variables, then decide when the Fernet key itself can be retired. Ask the team which secrets still live only in the database before setting that date.
When a secrets backend should replace stored credentials
A secrets backend is the better design once connection and variable passwords need to live in a central store that your security team already audits, rotates and backs up. Airflow checks an alternative secrets backend first, then environment variables, then the metastore, and this order is fixed, so a backend that returns a value takes precedence over anything stored in the database. Before you rely on that, confirm with your own testing that a backend lookup for each connection and variable name returns what you expect, because a name collision silently shadows the stored value. Central stores such as Vault, AWS, Azure, GCP and Kubernetes backends are the usual choices, and the secrets backend documentation describes how to configure each one.
Workers can use a separate backend through the [workers] secrets_backend setting, which matters when the scheduler and API server should not hold the same credentials as the task processes. Decide this per deployment: a single backend for everything is simpler to operate, while a split design lets you keep worker credentials scoped to the systems tasks actually call. Record which component reads from which backend, because a misconfigured worker can fail at runtime long after a DAG passes parsing.
A backend reduces the number of Fernet-encrypted values in the metadata database but does not remove the need to protect the Fernet key. Any connection or variable that remains in the metastore is still encrypted with that key, and anyone holding the key plus database access can decrypt it. So the rotation procedure in this guide still applies after you migrate: confirm that the remaining stored values are re-encrypted, that the old key is removed from every component, and that the key itself sits in a Kubernetes Secret or equivalent store with restricted read access.
Security considerations for the Fernet key
The Fernet key is the only thing standing between a leaked metadata database and the passwords stored in connections and variables. The cards below cover who holds the key, how it is stored and backed up, who can reach it, and how to keep it out of logs, so that the rotation steps above do not weaken the protection they are meant to maintain.
Key custody and ownership
Decide who owns the Fernet key before you generate it. Name a custodian role, record where the current key lives, and keep the old key until every metadata row has been re-encrypted. Losing the key makes stored connection and variable passwords unrecoverable, so the custodian should confirm that a second copy exists in an approved secret store. Check that every environment (development, staging, production) has its own key rather than sharing one.
Least-privilege access to the key
Only the Airflow scheduler, API server, and worker processes that decrypt connections need the key in their environment. Grant read access through the secret store to those workloads and nobody else, and avoid adding it to shared CI variables or developer laptops. Review who can read the Kubernetes Secret or the deployment template that carries AIRFLOW__CORE__FERNET_KEY, since anyone with that access can decrypt the metadata database.
Backups readable only with the key
Database backups contain encrypted passwords, so a dump is only protected if its key is kept separately. Store the Fernet key apart from the backup location and under its own access policy. Test a restore into an isolated environment with the key supplied only at restore time, and confirm that the restored connections decrypt correctly. Record which key version matches which backup so a rotation does not leave old backups unreadable.
Separation of duties
The people who administer the metadata database should not also hold the Fernet key by default. A database administrator can copy rows, but without the key the encrypted fields stay opaque. Assign the key to a security or platform custodian, and require two people for changes that expose it, such as editing the Secret or running the rotation command against production. Document this split so auditors can trace who approved each change.
Keeping the key out of logs and the UI
Set the key only through environment variables or a secret mount, never inline in a airflow.cfg file committed to Git, a Helm values file in plain text, or a DAG. Check that deployment logs, container inspection output, and CI job logs do not print the environment. Confirm that the key does not appear in the Airflow UI or task logs, and treat any appearance as a rotation event.
Plan for a compromised key
If you suspect the key has leaked, rotation alone does not protect data that an attacker already copied. Rotating replaces the key for stored values, but anyone holding the old key and an old database dump can still read the passwords in it. Respond by rotating the credentials behind the stored connections as well, then reviewing who had access to the key. Ask your team to write this procedure before go-live.
Questions teams ask before rotating the Fernet key
How much effort does a Fernet key rotation take?
The effort depends less on the key than on how many places encrypted values live and how many components must restart with the new key set. The rotation itself is short: list the new and old keys comma-separated in AIRFLOW__CORE__FERNET_KEY, run airflow rotate-fernet-key, then keep only the new key. The larger effort comes from counting connections and variables with passwords, identifying every component that reads the metadata database (scheduler, API server, DAG processor, workers), and rehearsing the change in a non-production copy. Ask any provider to break the estimate into inventory, rehearsal, change window and verification.
Can our in-house team rotate the key without outside help?
Yes, if the team already runs Airflow in production and has a tested backup of the metadata database. The procedure is documented and uses one CLI command, so the hard part is coordination: every component must see the same key configuration at the right moment, and the team must confirm that old ciphertext decrypts after the rotation. Teams without Kubernetes or database operations experience usually benefit from an outside rehearsal, or from a fixed-scope engagement that includes a written rollback path.
What access does the rotation require from us?
Plan for access to four things: the Airflow deployment in Kubernetes (to read and update the Secret that holds the key and to restart pods), the metadata database (to take a backup and confirm encrypted rows), the secret store where the key is kept, and the change calendar for the window. Access should be scoped to the namespace and database involved, with the operator who runs the command recorded. Confirm with your platform team whether the Kubernetes Secret is managed by GitOps tooling, since a sync can overwrite a manual change.
How long does the rotation window last, and what drives it?
The window is driven by how many components must be restarted, how large the metadata database is for the backup and verification steps, and how many teams must agree to a pause in DAG changes. The supplied documentation does not give a duration, so ask for the window length in writing and confirm it against a rehearsal in your own environment. Also agree on a rollback point: if decryption fails after the new key is applied, you need the previous key and a restore plan ready before you start.
Does a secrets backend remove the need for a Fernet key?
Not entirely. A secrets backend changes where connection and variable credentials are stored, so they no longer sit in the metadata database and the Fernet key matters less for them. Airflow still looks for a backend first, then environment variables, then the metastore, and that order is fixed, so values left in the metastore remain encrypted with the key. Moving credentials to a backend is therefore a separate project, and you should migrate and remove stored values before deciding the key can be retired or rotated on a lighter schedule.
What should we ask for in a fixed-scope quote?
Ask for a written scope that lists the deployments and namespaces covered, the inventory of encrypted connections and variables, the rehearsal in a non-production copy, the change plan with rollback steps, the verification checks after rotation, and the handover of the runbook. Ask which items are one-time and which recur at the next rotation, what the client must provide (access, backups, change approvals), and what is excluded, such as a later secrets backend migration. Compare quotes on those lines rather than on a headline total.
How do we check that encrypted values still work after the rotation?
Test decryption rather than assuming it. After the first step, confirm that existing connections and variables still open from the scheduler, the API server and a worker, then run a DAG that reads a password-bearing connection. Only after several successful runs should you remove the old key from the configuration. Keep the database backup taken before the change until the team has signed off, and record the verification results with the change ticket.
Limits to confirm in your environment
Fernet key rotation touches the metadata database, every component that reads the key, and the place where the key is stored. The items below are the ones most likely to differ between your environment and the documented procedure, so confirm each one before you schedule a rotation window.
Airflow version and support status
Confirm which Airflow release you run and where it sits in the version life cycle. Airflow 2 reached end of life on April 22, 2026, so a rotation on that line will not receive upstream fixes if something goes wrong. Limited-maintenance releases get security and critical fixes only. Plan any Fernet work together with the upgrade decision, since the key handling you practice now should match the version you intend to run next.
Rotation behavior in your installed version
Read the Fernet documentation for the exact release you run and compare it with your runbook before touching production. The procedure relies on listing the new and old keys comma-separated, running airflow rotate-fernet-key, then removing the old key. Confirm that the command exists in your installed build, how it reports progress, and whether it has to run from a host that can reach the metadata database.
Metadata database engine
Confirm whether your metadata database is PostgreSQL or MySQL, and which major version it runs. The re-encryption step writes to every table that stores encrypted values, so the database must accept the update load within your window. Check your backup and restore path for that engine, and confirm that a restore taken before rotation can still be decrypted with the old key. SQLite is not an option for production use.
Key injection in your deployment
Find out how your Helm chart or deployment tool supplies AIRFLOW__CORE__FERNET_KEY to the scheduler, API server, DAG processor, triggerer and workers. A single component that still reads an old value can fail to decrypt connections after the switch. Check whether the key is set through an environment variable, a config file or a chart value, and whether a rolling restart picks up the new value on every pod.
Encryption at rest for Kubernetes Secrets
The Fernet key lives in a Kubernetes Secret, and the Secret is only as protected as the cluster stores it. Confirm that encryption at rest is enabled for Secret objects in etcd, and check who can read Secrets in the Airflow namespace. Also confirm that backups of etcd and of your GitOps repositories do not hold the key in plain text, because a copy of the old key defeats the rotation.
Secrets backend coverage
Decide whether an external secrets backend will hold every connection and variable you use, or whether some still live in the metastore. Stored entries stay encrypted with the Fernet key, so each one must be re-encrypted during rotation or moved out first. Confirm the lookup order for your release, and whether workers use a separate backend through [workers] secrets_backend, since that setting changes which credentials a task can reach.
Official Airflow documentation for Fernet and secrets backends
The next read for anyone rotating the Fernet key is the official Fernet page in the Airflow security documentation, which covers how the key is set through AIRFLOW__CORE__FERNET_KEY and the rotation steps this topic summarizes. Read it before you touch production, because it is the source that the Airflow project maintains for that procedure. Keep a copy of the page you read, with its version, in your change record so that the steps you ran can be traced back to the documentation they came from.
The second read is the secrets backend documentation, which explains how Airflow looks up connections and variables and how a backend such as Vault, AWS, Azure, GCP or Kubernetes can take over that role. Use it to decide whether moving credentials out of the metadata database is a better fit for your environment than maintaining Fernet rotation indefinitely. The lookup order and the separate [workers] backend setting are described there in detail, so confirm them against the page before you design the change. Both pages are versioned, so treat the release you run as the reference for every command and setting.
Before you rely on either page, confirm which Airflow release your environment runs, then open the version-specific copy of each document for that release. Settings, command behavior and the Airflow 2 and Airflow 3 differences can change between releases, and the version life cycle page shows which releases still receive fixes. Record the release, the page version and the date you checked in your runbook, and ask your platform team to repeat the check at every upgrade, since a rotation plan that matches an older release can fail on a newer one.
How DeployOpen scopes and delivers Fernet key work
DeployOpen approaches Fernet key rotation as a planned change to a self-hosted Airflow environment, not a one-line command. Engagements are fixed-scope, so the key inventory, rotation window, verification steps and handover are agreed in writing before any change runs in your infrastructure.
How we scope
- Inventory every Airflow environment, metadata database and worker that holds encrypted connections and variables
- Confirm where the current Fernet key is stored and who can read it today
- Agree in writing whether rotation, a secrets backend move, or both are in scope
How we build
- Prepare the new key in your secret store and the comma-separated key list for each environment
- Run airflow rotate-fernet-key against a staging copy of the metadata database first
- Test connections and variables that depend on encrypted values before production rotation
How we hand over
- Document the key locations, owners, rotation steps and rollback path for your operations team
- Record which components were restarted and in what order during the change
- Walk your engineers through removing the old key from every environment once verified
How we support
- Offer ongoing support and periodic key rotation reviews as a retainer, if your team wants it
- Review Fernet key handling again when Airflow or the secrets backend changes version
- Keep runbooks current with your environments as platform components are upgraded

