多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Apache Airflow 接入 AWS Secrets Manager 完整指南:SecretsManagerBackend 配置、连接存储与多团队隔离

Apache Airflow 接入 AWS Secrets Manager 完整指南:SecretsManagerBackend 配置、连接存储与多团队隔离 Apache Airflow 接入 AWS Secrets Manager 完整指南SecretsManagerBackend 配置、连接存储与多团队隔离【免费下载链接】airflowApache Airflow - A platform to programmatically author, schedule, and monitor workflows项目地址: https://gitcode.com/GitHub_Trending/ai/airflowApache Airflow 内置的 Secrets Backend 抽象允许将连接Connections、变量Variables与配置项Configurations从数据库迁移到外部密钥管理系统。本文以 Apache Airflow 仓库中providers/amazon的 AWS Secrets Manager 集成文档aws-secrets-manager.rst为骨架结合 SecretsManagerBackend 源码 与单元测试test_secrets_manager.py系统讲解如何启用该后端、以 URI 或 JSON 两种方式存储连接、按前缀与正则模式过滤查找范围以及多团队模式下基于--分隔符的密钥隔离机制读完即可在真实 Airflow 环境中落地配置。一、SecretsManagerBackend 是什么AWS Secrets Manager 是 AWS 提供的托管密钥服务支持密钥轮换、细粒度 IAM 权限与审计。Airflow 通过BaseSecretsBackend抽象定义于 airflow-core/src/airflow/secrets/base_secrets.py统一了连接、变量与配置的获取接口任何实现该基类的后端都可以挂载到[secrets]配置节。SecretsManagerBackend正是这一抽象在 AWS Secrets Manager 上的实现类定义于 providers/amazon/src/airflow/providers/amazon/aws/secrets/secrets_manager.py。它实现了三个核心查询方法对应 Airflow 的三类敏感数据get_conn_value(conn_id)按连接 ID 读取连接支持 URI 与 JSON 两种存储格式get_variable(key)按变量名读取 Variable 值get_config(key)按配置键读取 Airflow 配置项例如将sql_alchemy_conn这类敏感配置托管到 Secrets Manager。从源码可以看到这三个方法均先检查对应前缀是否为None再检查密钥 ID 是否命中了保留的多团队命名空间最后统一走_get_secret()完成实际的 Secret 读取整体链路清晰且职责单一。二、在 airflow.cfg 中启用后端启用方式是在airflow.cfg的[secrets]节将backend指定为 SecretsManagerBackend 的完整类路径并通过backend_kwargs传入参数。需要注意backend_kwargs按 JSON 解析因此 Python 侧的False或None等字面量会被忽略这些参数将回退到后端的默认值。正确的写法是使用 JSON 的false、null。基础示例配置如下[secrets] backend airflow.providers.amazon.aws.secrets.secrets_manager.SecretsManagerBackend backend_kwargs { connections_prefix: airflow/connections, connections_lookup_pattern: null, variables_prefix: airflow/variables, variables_lookup_pattern: null, config_prefix: airflow/config, config_lookup_pattern: null, profile_name: default }该配置启用连接、变量、配置三类密钥的查找并使用本地默认 AWS 配置文件进行认证。认证方式SecretsManagerBackend本身不实现 AWS 认证而是复用 Amazon Provider 的连接体系。从源码 client 属性 可以看到它内部以SecretsManagerBackend__connection为连接 ID 构造AwsConnectionWrapper再经SessionFactory创建 boto3 session 与secretsmanagerclient。因此可以通过两种途径认证传入 AWS Connection Extra 配置参数backend_kwargs中直接写入region_name、role_arn、use_ssl、verify、endpoint_url等 AWS 连接参数详见仓库文档 configuring-the-connection设置 AWS 标准环境变量如AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY、AWS_DEFAULT_REGION等由 boto3 的默认凭证链解析。使用角色扮演role assumption的示例[secrets] backend airflow.providers.amazon.aws.secrets.secrets_manager.SecretsManagerBackend backend_kwargs { connections_prefix: airflow/connections, variables_prefix: airflow/variables, config_prefix: airflow/config, role_arn: arn:aws:iam::123456789098:role/role-name }单元测试 test_passing_client_kwargs 验证了这些参数确实被透传给了SessionFactory与 boto3 clientrole_arn与region_name会进入连接包装器use_sslFalse会体现在最终 client 调用中。backend_kwargs 参数总览以下参数在__init__中定义源码 L120-L158参数默认值说明connections_prefixairflow/connections连接密钥的前缀设为null则完全不向 Secrets Manager 发起连接查询connections_lookup_patternnull连接 ID 需匹配的正则仅当前缀非空时生效variables_prefixairflow/variables变量密钥的前缀设为null则不查询变量variables_lookup_patternnull变量名需匹配的正则config_prefixairflow/config配置密钥的前缀设为null则不查询配置config_lookup_patternnull配置键需匹配的正则sep/前缀与密钥 ID 之间的分隔符默认/extra_conn_wordsnull扩展连接字段别名JSON 对象键可选user、password、host、schema、conn_type**kwargs—透传给 AWS 连接体系的认证参数如profile_name、role_arn、region_name、use_ssl等源码对前缀做了rstrip(sep)处理L133-L144因此前缀末尾写不写/都等价。三、存储与读取连接Connections连接在 Secrets Manager 中有两种存储方式连接 URI与JSON 字段。方式一以连接 URI 存储将连接编码为 Airflow 连接 URI如postgresql://user:passhost:5432/db存入密钥即可注意以 URI 存储时每个字段默认按 URL 编码处理。例如要表示密码my passwordURI 中必须写作my%20password。对应的单测 test_get_conn_value_full_url_mode 展示了最小闭环以airflow/connections/test_postgres为密钥名存入postgresql://airflow:airflowhost:5432/airflow后get_conn_value(test_postgres)返回同一 URI。方式二以 JSON 字段存储也可以把连接的各个组成部分作为 JSON 的键值对存储。为了兼容不同的命名习惯后端允许为每个字段使用别名_standardize_secret_keys源码 L181-L202会把别名统一映射为 Airflow 标准字段连接字段允许的别名连接类型conn_type、conn_id、connection_type、engine用户名login、user、username、user_name密码password、pass、key主机host、remote_host、server端口port扩展信息extra必须是合法 JSON默认词表之外还可以通过extra_conn_words参数追加别名。该参数必须是字典键从user、password、host、schema、conn_type中选取值为字符串列表为兼容历史配置user会映射到login字段。命名规则与 CLI 实操连接 ID 为smtp_default、前缀为airflow/connections时密钥应存储在airflow/connections/smtp_default路径拼接逻辑见 build_pathf{path_prefix}{sep}{secret_id}。既可以在 AWS 控制台创建也可以用 AWS CLIaws secretsmanager put-secret-value \ --secret-id airflow/connections/smtp_default \ --secret-string {login: nice_user, password: this_is_the_password, host: ec2.8399.com, port: 999}随后验证密钥已写入❯ aws secretsmanager get-secret-value --secret-id airflow/connections/smtp_default { ARN: arn:aws:secretsmanager:us-east-2:314524341751:secret:airflow/connections/smtp_default-7meuul, Name: airflow/connections/smtp_default, VersionId: 34f90eff-ea21-455a-9c8f-5ee74b21be672, SecretString: {\n \login\:\nice_user\,\n \password\:\this_is_the_password\\n, \n \host\:\ec2.8399.com\\n,\n \port\:\999\\n}\n, VersionStages: [ AWSCURRENT ], CreatedDate: 2020-04-08T02:10:35.13200001:00 }如果不想使用任何连接前缀将connections_prefix设为空字符串即可——注意空字符串与null语义不同空字符串表示“前缀为空但依然查询”null表示“完全不查询”。关于 JSON 存储还有一个实现细节后端发现 Secret 内容以{开头时会反序列化 JSON、经_standardize_secret_keys统一字段名后再重新序列化源码 L222-L236这是为了兼容 Airflow 2.3 之前该后端对 JSON 别名的扩展支持。四、存储与读取变量Variables变量Airflow Variable的规则与连接完全对称设variables_prefix为airflow/variables后变量hello应存储在airflow/variables/hello。DAG 中Variable.get(hello)即可读到 Secrets Manager 中的值对应单测 test_get_variable。五、可选查找关闭某类查询或按正则过滤按类型关闭查询连接、变量、配置三类密钥可以独立开启或关闭从而避免为不需要的类型向 AWS 发送请求。将不需要类型的*_prefix设为null即可[secrets] backend airflow.providers.amazon.aws.secrets.secrets_manager.SecretsManagerBackend backend_kwargs { connections_prefix: airflow/connections, variables_prefix: null, config_prefix: null, profile_name: default }上面的配置只查询连接不再向 Secrets Manager 发送变量与配置请求。源码 L211-L213、L247-L248、L263-L264 三个方法在对应前缀为None时直接返回None单测 test_connection_prefix_none_value 还验证了此时_get_secret完全不会被调用。按正则过滤查询范围只想让部分 ID 走 Secrets Manager 时使用对应的*_lookup_pattern参数值为正则字符串。例如只查询以m开头的连接[secrets] backend airflow.providers.amazon.aws.secrets.secrets_manager.SecretsManagerBackend backend_kwargs { connections_prefix: airflow/connections, connections_lookup_pattern: ^m, profile_name: default }_get_secret中的匹配实现源码 L368-L374使用re.match(lookup_pattern, secret_id, re.IGNORECASE)——注意是re.match而非re.search因此模式需从头匹配且不区分大小写。参数化单测 test_connection_lookup_pattern 给出了一组可复现的行为矩阵模式为test、.*、T.*、null时各发起 1 次 client 调用模式为dummy-pattern时调用次数为 0即被过滤掉。六、多团队支持Multi-Team Support当 Airflow 以多团队模式运行时团队作用域的密钥使用--作为团队名与密钥 ID 之间的分隔符常量TEAM_SEP定义于 secrets_manager.py L33团队marketing拥有的连接smtp_default→ 存储于airflow/connections/marketing--smtp_default同一团队拥有的变量hello→ 存储于airflow/variables/marketing--hello。任务作者在 DAG 中依然按普通 ID 请求连接与变量无需感知团队前缀。查找顺序为先尝试团队作用域路径prefix/team--id若未命中再回退到全局路径如airflow/connections/smtp_default该回退逻辑见 源码 L375-L388。保留命名空间与防串团队设计两点安全约束需要特别留意含--的 ID 是保留命名空间多团队模式下任何无团队上下文、且 ID 本身包含--的请求会直接返回None以防止跨团队读取。原因在_names_a_team_namespace的注释中解释得很清楚team--id的拼接存在歧义团队a请求b--c与团队a--b请求c会拼出完全相同的字符串而 ID 中没有任何信息可以区分这两种解读因此所有 getter——连接、变量、配置——都会拒绝这类请求并记录 WARNING 日志_log_refusal。相关测试包括 test_global_caller_cannot_access_team_scoped_connection、test_another_teams_secret_is_not_reachable 等。该检查仅在多团队模式生效_names_a_team_namespace首先检查配置项core.multi_team是否为真未开启时普通含--的 ID 照常解析见 test_ambiguous_id_resolves_when_multi_team_is_disabled。多团队回退到全局路径的行为由 test_team_caller_falls_back_to_global_connection 覆盖即使指定了不存在的团队名只要全局路径存在密钥依然能取回连接。七、实战示例把 Google Cloud 连接存入 AWS Secrets Manager以 Google Cloud 连接为例说明如何把第三方云连接完整托管到 AWS Secrets Manager。由于 Google 连接的所有认证信息都必须放在extra字段中因此 JSON 存储时须把全部字段包裹进extra使用服务账号密钥文件{extra: {key_path: /opt/airflow/service_account.json, scope: https://www.googleapis.com/auth/devstorage.read_only}}使用服务账号密钥字典直接内嵌 JSON 内容{extra: {keyfile_dict: copy paste the service account json here, scope: https://www.googleapis.com/auth/devstorage.read_only}}两种方式都可以直接在 AWS 控制台以 Key/value 形式编辑extra下的各个子字段无需手写整段 JSON。八、FAQ 与排错要点为什么我传了 Python 的False/None却没生效因为backend_kwargs是 JSON 解析的请改用 JSON 字面量false/null。前缀末尾带不带/都可以源码会统一rstrip(/)。连接查不到如何定位后端对ResourceNotFoundException、InvalidParameterException、InvalidRequestException、DecryptionFailure、InternalServiceError五类异常均以 DEBUG 日志记录后返回None源码 L272-L320可以在 DEBUG 日志级别观察“Secret xxx not found”类信息多团队模式下的拒绝会输出 WARNING 级日志。本地调试需要真实 AWS 吗不需要。仓库测试使用moto的mock_aws装饰器模拟 Secrets Manager 服务例如 test_get_conn_value_full_url_mode可作为本地复现行为的参考。延伸阅读后端实现providers/amazon/src/airflow/providers/amazon/aws/secrets/secrets_manager.py单元测试providers/amazon/tests/unit/amazon/aws/secrets/test_secrets_manager.py姊妹后端AWS Systems Manager Parameter Storeproviders/amazon/docs/secrets-backends/aws-ssm-parameter-store.rstSecrets 后端索引providers/amazon/docs/secrets-backends/index.rst基类与查找路径airflow-core/src/airflow/secrets/base_secrets.py路径拼接工具airflow-core/src/airflow/_shared/secrets_backend/base.py【免费下载链接】airflowApache Airflow - A platform to programmatically author, schedule, and monitor workflows项目地址: https://gitcode.com/GitHub_Trending/ai/airflow创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表