Secrets Backends — облачные провайдеры
В прошлом уроке мы разобрали HashiCorp Vault как self-hosted secret store. Этот урок — про managed alternatives от облаков: AWS Secrets Manager, GCP Secret Manager, Azure Key Vault. У каждого свой trade-off по cost / features / integration с native IAM.
AWS Secrets Manager
Provider package:
pip install apache-airflow-providers-amazon
Конфигурация в airflow.cfg:
[secrets]
backend = airflow.providers.amazon.aws.secrets.secrets_manager.SecretsManagerBackend
backend_kwargs = {
"connections_prefix": "airflow/connections",
"variables_prefix": "airflow/variables",
"config_prefix": "airflow/config",
"region_name": "eu-west-1",
"profile_name": null
}
Pathing convention — точка / в имени secret (AWS Secrets Manager поддерживает hierarchy через /):
airflow/connections/pg_prod_warehouse
airflow/connections/snowflake_prod
airflow/variables/api_endpoint
Secret value — JSON для Connection, plain string для Variable:
# AWS CLI: create connection secret
aws secretsmanager create-secret \
--name airflow/connections/pg_prod_warehouse \
--secret-string '{
"conn_type": "postgres",
"login": "airflow",
"password": "secretPwd",
"host": "db.internal",
"port": 5432,
"schema": "warehouse",
"extra": "{\"sslmode\":\"require\"}"
}'
# Variable secret (plain string)
aws secretsmanager create-secret \
--name airflow/variables/api_endpoint \
--secret-string "https://api.example.com/v2"
Authentication
SecretsManagerBackend использует boto3 default credential chain. Это даёт несколько options:
Best practice для EKS — IRSA:
# k8s Service Account для Airflow
apiVersion: v1
kind: ServiceAccount
metadata:
name: airflow
namespace: airflow
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::123456789:role/airflow-secrets-reader
IAM Role airflow-secrets-reader:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue",
"secretsmanager:DescribeSecret"
],
"Resource": "arn:aws:secretsmanager:eu-west-1:123456789:secret:airflow/*"
}
]
}
ResourceARN с airflow/* ограничивает IAM Role только Airflow secrets — нельзя случайно прочитать app secrets других teams.
AWS Secrets Manager pricing
- $0.40 per secret per month
- $0.05 per 10k API calls
Для типичного deployment с 50 secrets:
- Storage: 50 × 20/month**
- API calls (с
use_cache=True, ttl=900): 50 secrets × 4 reads/hour × 720h × N pods. Для 20 pods это ~3M calls/month = $15 - Total: $35/month — обычно negligible vs total infra cost
Без caching API calls могут пробить $100+/month easily.
Automatic rotation
AWS Secrets Manager имеет builtin automatic rotation через Lambda:
aws secretsmanager rotate-secret \
--secret-id airflow/connections/pg_prod_warehouse \
--rotation-lambda-arn arn:aws:lambda:eu-west-1:123:function:rotate-pg-password \
--rotation-rules AutomaticallyAfterDays=30
Lambda function отвечает за фактическое generate нового password + update Postgres. Это comparable с Vault dynamic secrets, но через managed Lambda → меньше operations overhead.
Airflow получит rotated secret автоматически на следующий cache miss (или process restart).
GCP Secret Manager
Provider:
pip install apache-airflow-providers-google
Config:
[secrets]
backend = airflow.providers.google.cloud.secrets.secret_manager.CloudSecretManagerBackend
backend_kwargs = {
"connections_prefix": "airflow-connections",
"variables_prefix": "airflow-variables",
"config_prefix": "airflow-config",
"gcp_key_path": null,
"project_id": "my-gcp-project",
"sep": "-"
}
Pathing — GCP Secret Manager не имеет hierarchy через /, секреты flat. Backend использует sep='-':
airflow-connections-pg_prod_warehouse
airflow-connections-snowflake_prod
airflow-variables-api_endpoint
Note underscore vs dash: GCP Secret names regex [a-zA-Z0-9_-]{1,255} — underscores допустимы.
gcloud secrets create airflow-connections-pg_prod_warehouse \
--data-file=- <<EOF
{
"conn_type": "postgres",
"login": "airflow",
"password": "secretPwd",
"host": "db.internal",
"port": 5432,
"schema": "warehouse"
}
EOF
gcloud secrets create airflow-variables-api_endpoint \
--data-file=- <<EOF
https://api.example.com/v2
EOF
Auth — Workload Identity (GKE gold standard)
В GKE предпочтительный pattern — Workload Identity:
# k8s SA
apiVersion: v1
kind: ServiceAccount
metadata:
name: airflow
namespace: airflow
annotations:
iam.gke.io/gcp-service-account: [email protected]
GCP Service Account airflow-secrets@:
gcloud projects add-iam-policy-binding my-gcp-project \
--member="serviceAccount:[email protected]" \
--role="roles/secretmanager.secretAccessor"
Внутри pod GCP client libraries detect Workload Identity и автоматически получают access tokens.
GCP Secret Manager pricing
- $0.06 per active secret per month
- $0.03 per 10k operations
50 secrets:
- Storage: 50 × 3/month**
- Operations: ~3M/month = $9
- Total: $12/month — cheapest из трёх cloud providers
GCP заметно cheaper than AWS Secrets Manager в storage (6.6× difference на secret).
Versioning
GCP Secret Manager имеет immutable versions. Каждый gcloud secrets versions add создаёт новую version, старые сохраняются. По default backend читает latest, но можно reference конкретную version:
backend_kwargs = {
"connections_prefix": "airflow-connections",
"version": "5" # читать конкретную версию
}
Используется редко — обычно latest. Versioning полезен для rollback при инциденте.
Azure Key Vault
Provider:
pip install apache-airflow-providers-microsoft-azure
Config:
[secrets]
backend = airflow.providers.microsoft.azure.secrets.key_vault.AzureKeyVaultBackend
backend_kwargs = {
"connections_prefix": "airflow-connections",
"variables_prefix": "airflow-variables",
"config_prefix": "airflow-config",
"vault_url": "https://my-airflow-kv.vault.azure.net",
"sep": "-"
}
Azure Key Vault имеет ограничения на secret name: [0-9a-zA-Z-]{1,127}. Underscores и слэши НЕ работают! Это создаёт проблему — airflow-connections/pg_prod_warehouse невалидно. Поэтому sep='-' обязателен (вместо /), и conn_id не должен содержать underscores (или они трансформируются).
В реальности конвертация: conn_id pg_prod_warehouse → Key Vault secret name airflow-connections-pg-prod-warehouse (Airflow меняет _ → -). Это must know при настройке.
az keyvault secret set \
--vault-name my-airflow-kv \
--name airflow-connections-pg-prod-warehouse \
--value '{"conn_type":"postgres","login":"airflow","password":"secretPwd","host":"db.internal","port":5432,"schema":"warehouse"}'
Auth — Managed Identity (AKS gold standard)
Azure Key Vault интегрируется с Azure AD Managed Identity. AKS pods могут иметь User-Assigned Managed Identity:
apiVersion: v1
kind: ServiceAccount
metadata:
name: airflow
namespace: airflow
annotations:
azure.workload.identity/client-id: <managed-identity-client-id>
Grant Managed Identity роль:
az role assignment create \
--role "Key Vault Secrets User" \
--assignee <managed-identity-client-id> \
--scope /subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.KeyVault/vaults/my-airflow-kv
В Airflow используется DefaultAzureCredential из azure-identity (auto-detect chain), которая поддерживает Workload Identity, Managed Identity, SP credentials, az CLI.
Pricing
- $0.03 per 10k operations (read-heavy operations)
- No charge per secret stored (within limit)
- HSM-backed secrets — significantly more expensive ($1+ per key)
For 50 secrets:
- Storage: $0 (under quota)
- Operations: ~3M/month = $9
- Total: $9/month — самый дешёвый из трёх
Сравнение
Multi-cloud strategy
Realistic enterprise scenario — Airflow на AWS читает secrets из GCP project (потому что GCP ML team owns dataset). Two options:
Option 1: Multiple Backends в chain
[secrets]
backend = airflow.providers.amazon.aws.secrets.secrets_manager.SecretsManagerBackend,airflow.providers.google.cloud.secrets.secret_manager.CloudSecretManagerBackend
backend_kwargs = '{"aws":{...}, "gcp":{...}}'
Airflow попробует AWS first, потом GCP. Trade-off: каждый lookup делает 2 round-trips для secrets, которых не существует в AWS.
Option 2: Vault как unified gateway
Vault sets up secret engines для AWS Secrets Manager и GCP Secret Manager, Airflow читает только из Vault. Vault internally proxies к cloud. Trade-off: + Vault complexity, но единая audit + RBAC.
Option 3: Replication
Workflow в external system периодически копирует secrets из source provider в target. Airflow читает только из one provider. Trade-off: stale data до next sync run.
Production reality — обычно option 2 (Vault) для enterprise или option 1 (chain) для simple cases.
Common pitfalls — все три провайдера
- Region mismatch: Airflow в
eu-west-1, secrets вus-east-1. AWS возвращаетResourceNotFoundException. Always setregion_nameexplicitly. - Prefix typo:
airflow/connections/vsairflow-connections/— путь не совпадает, lookup возвращает None silently, потом fallback на DB → unexpected credentials. - JSON malformed: extra field как nested JSON string (escaped quotes!) — должно быть валидным JSON для
extra_dejson. - IAM/RBAC underspec: missing
secretsmanager:DescribeSecret(AWS требует дляGetSecretValueбезVersionId) — backend получитAccessDenied. - Naming restrictions: Azure не любит
_. AWS —/OK. GCP — flat без/. Тестируйте на edge case naming перед production deploy.
When to choose what
HashiCorp Vault: multi-cloud / on-prem / dynamic secrets / fine-grained policies / when compliance требует self-hosted.
AWS Secrets Manager: AWS-only workload, builtin RDS rotation важна, есть AWS Premium Support contract.
GCP Secret Manager: GCP-only workload, нужен cheap-est storage, comfortable с lighter rotation tooling.
Azure Key Vault: Azure-only workload, нужен HSM-backed secrets для compliance, OK с naming restrictions.
None (DB-only): dev / local environments, < 10 secrets, no audit requirements. Никогда production.