Author, debug and configure Apache Airflow 3 DAGs: TaskFlow API, scheduling and assets, XCom, sensors, dynamic task mapping, and multi-layer test suites
75
94%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Airflow connections store credentials and configuration for external systems. Operators and hooks use connections via conn_id — never hardcode credentials.
# GOOD: Credentials from Airflow connection
hook = PostgresHook(postgres_conn_id="my_postgres")
# BAD: Hardcoded credentials
import psycopg2
conn = psycopg2.connect(host="db.example.com", password="secret123")| Field | Purpose | Example |
|---|---|---|
conn_id | Unique identifier | aws_default |
conn_type | Connection type | postgres, aws, http |
host | Hostname or URL | db.example.com |
port | Port number | 5432 |
schema | Database name | mydb |
login | Username | admin |
password | Password | *** |
extra | JSON with additional params | {"region": "us-east-1"} |
Admin → Connections → Add. Best for manual/ad-hoc setup.
# URI format
export AIRFLOW_CONN_MY_POSTGRES="postgresql://user:pass@host:5432/mydb"
# JSON format (preferred for complex connections)
export AIRFLOW_CONN_MY_AWS='{"conn_type": "aws", "extra": {"region_name": "us-east-1"}}'Naming convention: AIRFLOW_CONN_ + CONN_ID (uppercase).
Fetch from external secrets manager at runtime. See Secrets Backends.
curl -X POST "http://localhost:8080/api/v1/connections" \
-H "Content-Type: application/json" \
-d '{"connection_id": "my_conn", "conn_type": "postgres", "host": "db.example.com"}'airflow:
connections:
- conn_id: my_postgres
conn_type: postgres
conn_host: localhost
conn_port: 5432
conn_schema: mydb
conn_login: admin
conn_password: password123Loaded automatically by astro dev start.
conn-type://login:password@host:port/schema?param1=val1¶m2=val2Examples:
# PostgreSQL
export AIRFLOW_CONN_MY_PG="postgresql://user:pass@host:5432/mydb"
# MySQL
export AIRFLOW_CONN_MY_MYSQL="mysql://user:pass@host:3306/mydb"
# HTTP
export AIRFLOW_CONN_MY_API="http://api.example.com"
# S3 (no host needed — uses AWS config)
export AIRFLOW_CONN_MY_S3="aws://"URL-encode special characters in password: p@ss → p%40ss
Preferred for complex connections with extra parameters:
export AIRFLOW_CONN_MY_AWS='{
"conn_type": "aws",
"login": "AKIAIOSFODNN7EXAMPLE",
"password": "secret_access_key",
"extra": {
"region_name": "us-east-1",
"role_arn": "arn:aws:iam::123456789:role/my-role"
}
}'
export AIRFLOW_CONN_MY_PG='{
"conn_type": "postgres",
"host": "db.example.com",
"port": 5432,
"schema": "mydb",
"login": "admin",
"password": "secret123",
"extra": {
"sslmode": "require"
}
}'Fetch credentials from external secrets managers. More secure than storing in Airflow metadata DB or env vars.
| Backend | Provider Package | Config Class |
|---|---|---|
| AWS Secrets Manager | apache-airflow-providers-amazon | SecretsManagerBackend |
| AWS Systems Manager | apache-airflow-providers-amazon | SystemsManagerParameterStoreBackend |
| Azure Key Vault | apache-airflow-providers-microsoft-azure | AzureKeyVaultBackend |
| Google Secret Manager | apache-airflow-providers-google | CloudSecretManagerBackend |
| HashiCorp Vault | apache-airflow-providers-hashicorp | VaultBackend |
# AWS Secrets Manager
AIRFLOW__SECRETS__BACKEND=airflow.providers.amazon.aws.secrets.secrets_manager.SecretsManagerBackend
AIRFLOW__SECRETS__BACKEND_KWARGS='{"connections_prefix": "airflow/connections", "variables_prefix": "airflow/variables"}'
# Azure Key Vault
AIRFLOW__SECRETS__BACKEND=airflow.providers.microsoft.azure.secrets.key_vault.AzureKeyVaultBackend
AIRFLOW__SECRETS__BACKEND_KWARGS='{"connections_prefix": "airflow-connections", "vault_url": "https://my-vault.vault.azure.net/"}'First match wins. This allows secrets backend for production while using env vars for local development.
# Hide password and extra fields in UI and logs (default: True)
AIRFLOW__CORE__HIDE_SENSITIVE_VAR_CONN_FIELDS=Truepassword and extra fields using Fernet keyAirflow encrypts sensitive connection fields. Generate a key:
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"Set via: AIRFLOW__CORE__FERNET_KEY=your_generated_key
Connection testing is disabled by default. Enable it:
AIRFLOW__CORE__TEST_CONNECTION=Enabledairflow connections test my_postgres
# Output: Connection successfully tested
astro dev run connections test my_postgres # Astro CLITest button available on the Connections page when enabled.
from airflow.hooks.base import BaseHook
conn = BaseHook.get_connection("my_postgres")
print(f"Host: {conn.host}, Port: {conn.port}")