Airflow hides secrets in task logs and shows *** instead. It hides connection passwords, and Variables whose names contain words such as password, secret, token or api_key.
It hides the exact secret text, even inside a longer string. But it cannot spot a changed form of the secret:
What the task log showedworked example
print(f"password={c.password}")
print(f"dsn=postgres://{c.login}:{c.password}@{c.host}/shop")
print("b64=" + base64.b64encode(c.password.encode()).decode())
print("api_key=" + Variable.get("api_key"))
print("region=" + Variable.get("region"))
Result · 5 rows
| log line |
|---|
| password=*** |
| dsn=postgres://meta_user:***@meta-host/shop |
| b64=bWV0YV9zZWNyZXRfcHc= |
| api_key=*** |
| region=eu-west |
The base64 line is the password, only encoded, and anyone can decode it. region is not a secret word, so it is shown.
So never print secrets, in any form. Task logs are often readable by many more people than the secret store.
In production, keep connections in a secrets backend. It gives you access rules, an audit log and password rotation in one place.
After a rotation, a task that already read the connection keeps the old password. The next task reads the new one. So rotate when few tasks run, or keep the old password valid for a short time.