Airflow 安全模型

本文档从 Airflow 用户的角度描述了 Airflow 的安全模型。旨在帮助用户理解安全模型,并针对如何部署和管理 Airflow 做出明智的决策。

如果您想了解如何报告安全漏洞以及 Airflow 安全团队如何处理安全报告,请前往 Airflow 安全策略

Airflow 安全模型 - 用户类型

Airflow 安全模型涉及不同类型的用户,他们拥有不同的访问权限和功能。

虽然在小型安装中,Airflow 相关的操作可以由单个用户执行,但在大型安装中,很明显需要划分不同的职责、角色和权限。

这就是为什么 Airflow 包含以下用户类型:

  • 部署管理者 - 对 Airflow 的安装、安全性和配置负总责。

  • 已认证的 UI 用户 - 可以访问 Airflow UI 和 API 并与之交互的用户。

  • DAG 作者 - 负责创建 DAG 并将其提交给 Airflow。

您可以在 架构概览 中查看更多关于用户类型如何影响 Airflow 架构的内容,包括查看简单和复杂部署的图表。

部署管理者

他们拥有最高级别的访问权限和控制权。他们负责安装和配置 Airflow,并对技术选型和权限做出决策。他们有可能删除整个安装并拥有所有凭据的访问权限。部署管理者还可以决定在 Airflow 之外保留审计、备份和信息副本,这些内容不在 Airflow 的安全模型范围内。

DAG 作者

他们可以创建、修改和删除 DAG 文件。DAG 文件中的代码会在 Worker、DAG 文件处理器(Dag File Processor)和 Triggerer 中执行。因此,DAG 作者可以创建并更改在 Worker、DAG 文件处理器和 Triggerer 中执行的代码,并有可能获取 DAG 代码用于访问外部系统的凭据。

在 Airflow 3 中,数据库隔离级别取决于组件:

  • Worker:Worker 上的任务代码完全通过“执行 API”(Execution API)与 API 服务器通信。Worker 不会接收数据库凭据,且确实无法直接访问元数据数据库。

  • DAG 文件处理器和 Triggerer:Airflow 实现了软件防护机制,防止 DAG 作者的代码意外直接访问数据库。然而,由于 DAG 解析和触发器执行进程与其父进程(确实拥有数据库凭据)以相同的 Unix 用户身份运行,恶意 DAG 作者有可能从父进程中窃取凭据并获得直接访问数据库的权限。详细机制和部署加固措施,请参阅 JWT 认证与工作负载隔离

已认证的 UI 用户

他们有权访问 UI 和 API。有关已认证 UI 用户可具备的功能权限的详细信息,请参阅下文。

未认证的 UI 用户

Airflow 默认不支持未认证用户。如果允许,潜在漏洞必须由部署管理者评估并解决。但也有例外,例如负责获取健康检查更新的 /health 端点应该是公开可访问的,这是因为其他系统可能需要检索该信息。另一个例外是 /login 端点,因为用户在访问它时处于未认证状态是预期之中的。

已认证 UI 用户的功能权限

已认证 UI 用户的功能权限取决于部署管理者或管理员用户所配置的角色,以及这些角色拥有的权限。角色的权限范围可以精确到单个 DAG,也可以广泛到管理员级别。以下是四个通用类别,有助于概念化已认证用户可能具备的功能。

管理员用户

他们管理并授予其他用户权限,拥有所有 UI 功能的完全访问权限。他们可能通过配置连接在 Worker 上执行代码,因此必须信任他们不会滥用这些特权。他们拥有访问敏感凭据的权限并可以修改它们。默认情况下,他们没有系统级配置的访问权限。应信任他们不会滥用通过连接配置可访问的敏感信息。他们还有能力制造 API 服务器拒绝服务情况,因此应信任他们不会滥用此能力。

默认情况下,只有管理员用户可以访问审计日志。

运维用户

运维人员与管理员的主要区别在于管理和授予他人权限的能力,以及访问审计日志的能力——只有管理员能执行这些操作。除此之外,默认他们拥有与管理员相同的访问权限。

连接配置用户

他们配置连接,并可能在 DAG 执行期间在 Worker 上执行代码。需要建立信任以防止滥用这些特权。他们对存储在连接中的敏感凭据拥有完全的“只写”访问权限,可以修改它们但不能查看它们。对于通过连接配置写入敏感信息,应信任其不会被滥用。他们还有能力错误地配置连接,从而可能制造 API 服务器拒绝服务情况,或指定不安全的连接选项,这可能导致执行 DAG 时为某些提供商(无论是社区发布的还是自定义的)带来任意远程代码执行(RCE)。

应高度信任这些用户不会滥用此能力。

注意

在 Airflow 3 之前,连接配置用户角色也可以查看敏感信息,但在 Airflow 3 中已对此进行了更改,以提高安全性,防止连接配置用户无意中泄露凭据。此前(Airflow 2 中),连接配置用户被特意赋予查看敏感信息的权限,他们可以通过浏览器检查功能查看,或者在配置额外字段(extras)中直接以明文显示。Airflow 3 及更高版本在 API 层面屏蔽了这些敏感凭据,不会返回明文。

关于敏感信息

敏感信息包括连接详情、变量和配置。在 Airflow 3.0 之后的版本中,敏感信息不会通过 API、UI 和 airflowctl 暴露给用户。然而,task-sdk 仍然提供对敏感信息的访问(例如,使用 SDK API 客户端通过任务特定的 JWT 令牌获取变量)。本地 CLI 将仅返回键,除非使用 --show_values。敏感信息已在日志、UI 和 API 输出中进行脱敏处理。如果 DAG 作者以其他方式暴露了敏感信息(例如通过环境变量),这些值将不会被脱敏。

审计日志用户

他们可以查看整个 Airflow 安装的审计事件。

普通用户

他们可以查看并与 UI 和 API 进行交互。他们可以查看和编辑 DAG、任务实例(task instances)和 DAG 运行(Dag runs),并查看任务日志。

查看者用户

他们可以以只读方式查看与 DAG 相关的信息、任务日志和其他详细信息。此角色适用于仅需要只读访问权限且无需触发或修改 DAG 的用户。

查看者也没有访问审计日志的权限。

有关已认证 UI 用户功能的更多信息,请参阅 使用 FAB 认证管理器的访问控制

DAG 作者的功能权限

DAG 作者能够创建或编辑代码(通过放置在 DAG 包中的 Python 文件),这些代码将在多种情况下执行。Airflow 不会验证、检查或沙盒化这些代码(如果能做到也非常困难甚至不可能),因此实际上,DAG 作者可以在 Worker(Celery Executor 使用 Celery Worker,Local Executor 使用调度器运行的本地进程,Kubernetes Executor 使用 Kubernetes 任务 Pod)、DAG 处理器和 Triggerer 中执行任意代码。

DAG 作者应对他们编写并提交给 Airflow 的代码负责。我们假设他们会验证所实现的代码是安全的,不会对 Airflow 安装造成任何伤害,也不会开启安全漏洞。由于 DAG 作者编写的是 Python 代码,他们可以轻松编写出访问 Airflow 中敏感信息或将其发送到外部的代码,也可能引入新的安全漏洞。一个典型的例子是编写代码,将未经清理的 UI 用户输入(如参数、变量、连接配置)传递给 Operator 和 Hook 中的任何代码或第三方库,而不先进行适当的清理。这可能会开启远程代码执行(RCE)、拒绝服务攻击等漏洞的窗口。应信任 DAG 作者不会编写此类代码,并确信他们编写的代码是安全的且不会引入新的安全漏洞。

限制 DAG 作者对特定 DAG 子集的访问

在任务执行方面,Airflow 尚未在不同用户组之间提供完整的任务级隔离。虽然在 Airflow 3.0 及更高版本中,Worker 的任务代码无法直接访问元数据数据库(它们通过执行 API 通信),但在 DAG 文件处理器和 Triggerer 中运行的 DAG 作者代码仍然可能具备直接数据库访问权限。无论执行上下文如何,DAG 作者都有权访问 Airflow 安装中的所有 DAG,并且可以修改其中的任何 DAG——无论任务代码是为哪个 DAG 执行的。这意味着 DAG 作者可以修改任何 DAG 的任何任务实例的状态,并且没有更细粒度的访问控制来限制这种访问。

Airflow 中有一个实验性的多团队功能([core] multi_team),它提供了团队之间的 UI 级和 REST API 级 RBAC 隔离。但是,该功能尚未保证任务级隔离。在任务执行层面,来自不同团队的工作负载仍然共享同一个执行 API、签名密钥、连接和变量。一个团队的任务可以访问与另一个团队任务相同的共享资源。多团队功能仍在开发中——任务级隔离和对团队边界的执行 API 强制执行将在 Airflow 的未来版本中得到改进。在此之前,您应该假设所有 DAG 作者都可以访问所有 DAG 和共享资源,并且无论团队分配如何,都可以修改其状态。

DAG 作者提交代码的安全上下文

Airflow 选定的这种模型产生了一些后果,部署管理者需要了解 DAG 作者的这些能力如何映射到 Airflow 中不同安全上下文中执行的代码:

Local Executor

对于 Local Executor,DAG 作者可以在运行调度器的机器上执行任意代码。这意味着他们可以影响调度器进程本身,并可能影响整个 Airflow 安装——包括修改集群范围的策略和更改 Airflow 配置。如果您使用 Local Executor 运行 Airflow,部署管理者必须信任 DAG 作者不会滥用此能力。

Celery Executor

对于 Celery Executor,DAG 作者可以在 Celery Worker 上执行任意代码。这意味着他们可能影响在同一 Worker 上执行的所有任务。如果您使用 Celery Executor 运行 Airflow,部署管理者必须信任 DAG 作者不会滥用此能力,除非部署管理者通过集群策略(Cluster Policies)按队列分隔任务执行,否则应假设任务之间不存在隔离。

Kubernetes Executor

对于 Kubernetes Executor,DAG 作者可以在他们运行的 Kubernetes POD 上执行任意代码。每个任务都在单独的 POD 中执行,因此任务之间已经存在隔离,因为通常来说 Kubernetes 提供了 POD 之间的隔离。

Triggerer

对于 Triggerer,DAG 作者可以在 Triggerer 中执行任意代码。目前没有任何强制机制可以隔离使用“可延迟”(deferrable)功能的任务,来自不同任务的任意代码可以在同一个进程/机器上执行。默认部署运行一个单一的 Triggerer 实例来处理来自所有团队的触发器——没有对每个团队使用 Triggerer 实例的内置支持。此外,Triggerer 使用进程内执行 API 传输,这可能会绕过 JWT 认证,并且可能具有对元数据数据库的直接访问权限。对于多团队部署,部署管理者必须采取部署层面的措施,为每个团队运行单独的 Triggerer 实例,但即使如此,每个实例也可能保留直接数据库访问权限,且在其中运行触发器代码的 DAG 作者可能直接访问数据库——包括属于其他团队的数据。部署管理者必须信任 DAG 作者不会滥用此能力。

调度器和 API 服务器不需要 DAG 文件

部署管理者可以通过确保调度器和 API 服务器甚至没有 DAG 文件的访问权限,来隔离 DAG 作者提供的代码执行——特别是在调度器和 API 服务器中。总的来说,任何 DAG 作者提供的代码都不应该在调度器或 API 服务器进程中执行。这意味着部署管理者可以在调度器和 API 服务器上排除 DAG 包所需的凭据——但包仍必须在这些组件上进行配置。

允许 DAG 作者在调度器和 API 服务器中执行特定代码

有许多功能允许 DAG 作者使用预注册的自定义代码在调度器或 API 服务器进程中执行——例如,他们可以选择自定义时间表(Timetables)、UI 插件、连接 UI 字段、Operator 额外链接、宏(macros)、监听器等。所有这些功能都允许 DAG 作者选择在调度器或 API 服务器进程中执行的代码。然而,这不应该是 DAG 作者可以在 DAG 包中添加的任意代码。所有这些功能只能通过 pluginsproviders 机制获得,其中执行的代码只能由安装的包提供(或者在插件的情况下,也可以添加到 PLUGINS 文件夹,但 DAG 作者不应拥有该文件夹的写入权限)。PLUGINS_FOLDER 是来自 Airflow 1.10 的遗留机制,但我们建议使用入口点(entrypoint)机制,这允许部署管理者有效地选择和注册将在这些上下文中执行的代码。DAG 作者无权安装或修改安装在调度器和 API 服务器中的包,这是防止 DAG 作者在这些进程中执行任意代码的方法。

此外,如果您决定使用并配置 PLUGINS_FOLDER,部署管理者务必确保 DAG 作者对该文件夹没有写入权限。

部署管理者可能会决定引入额外的控制机制,以防止 DAG 作者执行任意代码。这完全掌握在部署管理者手中,并在下一章中进行讨论。

访问所有 DAG

所有 DAG 作者都有权访问 Airflow 部署中的所有 DAG。这意味着他们可以随时查看、修改和更新任何 DAG,且不受限制。

JWT 认证与工作负载隔离

Airflow 对其公共 REST API 和内部执行 API 均使用 JWT(JSON Web Token)认证。有关 JWT 认证流程、令牌结构和配置的详细描述,请参阅 JWT 令牌认证。关于工作负载隔离保护的现状及其局限性,请参阅 工作负载隔离与当前限制

当前的隔离限制

虽然 Airflow 3 通过防止 Worker 任务代码直接访问元数据数据库(Worker 现在仅通过执行 API 进行通信)显著改进了安全模型,但尚未实现 DAG 作者之间的完美隔离。DAG 作者的代码在 DAG 文件处理器和 Triggerer 中执行时,仍可能具备直接的数据库访问权限。

软件防护与蓄意访问

Airflow 实现了软件级防护,防止 DAG 作者代码的意外和非蓄意直接数据库访问。DAG 文件处理器在 fork 子进程解析 DAG 文件之前会移除数据库会话和连接信息,且 Worker 任务仅使用执行 API。

然而,这些软件防护无法抵御蓄意的恶意访问。解析 DAG 文件和执行触发器代码的子进程分别以与其父进程(分别是 DAG 文件处理器管理器和 Triggerer)相同的 Unix 用户身份运行。由于 POSIX 进程隔离的工作原理,以同一用户身份运行的子进程可以通过多种机制检索父进程的凭据:

  • 环境变量:在 Linux 上,默认情况下,任何进程都可以读取同一用户运行的其他进程的 /proc/<PID>/environ——因此通过环境变量(例如 AIRFLOW__DATABASE__SQL_ALCHEMY_CONN)传递的数据库凭据可以从父进程中读取。这可以通过设置进程的 dumpable 属性来防止,该属性在任务监控器中已实现。

  • 配置文件:如果配置存储在文件中,这些文件必须可被父进程读取,因此也可被以同一用户身份运行的子进程读取。

  • 基于命令的秘密_CMD 后缀选项):子进程可以执行相同的命令来检索秘密。

  • 秘密管理器访问:如果父进程使用秘密后端,子进程可以使用进程环境或文件系统中可用的凭据访问相同的秘密管理器。

这意味着一个蓄意恶意的 DAG 作者可以检索数据库凭据并获得对元数据数据库的完全读写访问权限——包括修改任何 DAG、任务实例、连接或变量的能力。软件防护解决了意外访问(例如,DAG 作者习惯性地从 Airflow 2 导入 airflow.settings.Session),但无法阻止坚定的行为者绕过它们。

在 Worker 上,当部署管理者配置 Worker 进程完全不接收数据库凭据(既不通过环境变量也不通过配置文件)时,隔离会更强。Worker 应仅通过执行 API 使用短期 JWT 令牌进行通信。当配置为没有任何凭据对其可见时,在 Worker 上运行的任务确实不应直接访问元数据数据库。

运行用户代码的 DAG 文件处理器和 Triggerer 仅有绕过 JWT 认证的“软”保护

运行用户代码的 DAG 文件处理器和 Triggerer 进程使用进程内传输来访问执行 API,这会绕过 JWT 认证。由于这些组件执行用户提交的代码(分别是 DAG 文件和触发器代码),在这些组件中运行代码的 DAG 作者如果绕过了软保护,将拥有对所有执行 API 操作的无限制访问权限——包括读取任何连接、变量或 XCom 的能力——而无需有效的 JWT 令牌。

此外,DAG 文件处理器可以直接访问元数据数据库(它需要此权限来存储序列化的 DAG)。如上所述,在 DAG 文件处理器上下文中执行的 DAG 作者代码可能能够从父进程检索数据库凭据并直接访问数据库,包括 JWT 签名密钥配置(如果它在进程环境中可用)。如果 DAG 作者获得了 JWT 签名密钥,他们就可以伪造任意令牌。

DAG 文件处理器和 Triggerer 在团队间共享

在默认部署中,单个 DAG 文件处理器实例解析所有 DAG 文件,而单个 Triggerer 实例处理所有触发器——无论团队分配如何。没有内置支持运行每个团队的 DAG 文件处理器或 Triggerer 实例。这意味着来自不同团队的 DAG 作者代码在同一个进程中执行,可能共享进程内的执行 API 和直接数据库访问权限。

对于需要隔离的多团队部署,部署管理者必须采取部署层面的措施,为每个团队运行单独的 DAG 文件处理器和 Triggerer 实例(例如,通过配置每个实例仅处理属于特定团队的包)。然而,即使有单独的实例,每个 DAG 文件处理器和 Triggerer 也可能保留对元数据数据库的直接访问权限——在这些组件中运行代码的 DAG 作者可能从父进程检索凭据并直接访问数据库,包括读取或修改属于其他团队的数据,除非部署管理者实施 Unix 用户级隔离(请参阅 用于改进隔离的部署加固)。

执行 API 中没有跨工作负载隔离

所有 Worker 工作负载均使用由同一密钥签名且共享同一受众(audience)的令牌向同一个执行 API 进行认证。虽然 ti:self 作用域强制执行阻止了 Worker 访问其他任务的特定端点(心跳、状态转换),但共享资源(如连接、变量和 XCom)对所有任务均可见。在执行 API 层面上,属于不同团队或 DAG 作者的任务之间没有隔离。

令牌签名密钥可能是共享秘密

在对称密钥模式([api_auth] jwt_secret)下,同一个秘密密钥既用于生成也用于验证令牌。任何能够访问此密钥的组件都可以伪造带有任意声明的令牌,包括用于其他任务实例或具有提升作用域的令牌。不过,如果秘密仅通过部署配置对 API 服务器和调度器可用,这不会影响系统的安全性。

敏感配置值可能会通过日志泄露

DAG 作者可以编写将环境变量或配置值打印到任务日志的代码(例如 print(os.environ))。Airflow 会在日志中脱敏已知的敏感值,但脱敏依赖于对数值模式的识别。有意或无意记录原始环境变量的 DAG 作者可能会在任务日志中暴露数据库凭据、JWT 签名密钥、Fernet 密钥或其他秘密。部署管理者应限制对任务日志的访问,并确保敏感配置仅提供给需要的组件(请参阅下方的敏感变量表)。

用于改进隔离的部署加固

需要 DAG 作者和团队之间实现更强隔离的部署管理者可以采取以下措施。请注意,这些是超越 Airflow 内置安全模型的部署特定操作——Airflow 不会原生强制执行这些措施。

DAG 文件的强制代码审查

为所有 DAG 提交到 DAG 包的过程实施审查流程。这可以包括:

  • 在部署 DAG 文件之前要求进行拉取请求(Pull Request)审查。

  • 对 DAG 代码进行静态分析,以检测可疑模式(例如,尝试直接访问数据库、读取环境变量、导入配置模块)。

  • 标记潜在危险代码的自动化 linting 规则。

将敏感配置限制在需要的组件中

不要在所有组件之间共享所有配置参数。特别是:

  • JWT 签名密钥([api_auth] jwt_secret[api_auth] jwt_private_key_path)应仅提供给需要生成令牌的组件(调度器/Executor、API 服务器)和需要验证令牌的组件(API 服务器)。Worker 不应拥有访问签名密钥的权限——他们只需要提供给他们的令牌。

  • 外部系统的连接凭据(通过秘密管理器)应仅提供给 API 服务器(它通过执行 API 将其提供给 Worker),而不是直接提供给调度器、DAG 文件处理器或 Triggerer 进程。但这会限制 Airflow 的某些功能——例如截止日期警报或需要与外部系统认证的触发器。

  • 数据库连接字符串应仅提供给需要直接数据库访问的组件(API 服务器、调度器、DAG 文件处理器、Triggerer),而不是提供给 Worker。

通过环境变量传递配置

为了更高的安全性,通过环境变量而不是配置文件传递敏感配置值。由于内置的保护机制,环境变量在 Airflow 的 Worker 进程中本质上比配置文件更安全:在 Linux 上,监控进程在 fork 任务进程之前调用 prctl(PR_SET_DUMPABLE, 0),此标志会被 fork 的子进程继承。这会将两个进程都标记为不可 dump(non-dumpable),从而防止同一 UID 的兄弟进程读取 /proc/<pid>/environ/proc/<pid>/mem 或通过 ptrace 进行挂载。相比之下,磁盘上的配置文件可以被以相同 Unix 用户身份运行的任何进程读取。环境变量也可以限定在单独的进程或容器中,从而更容易限制哪些组件有权访问哪些秘密。

下表列出了所有对安全敏感的配置变量(在 Airflow 的 config.yml 中标记为 sensitive: true)。部署管理者应审查每个变量,并确保它仅提供给需要的组件。“需要方”(Needed by)列指示了通常需要该变量的组件——但实际需求取决于所使用的特定部署拓扑和功能。

Core Airflow 敏感配置变量

环境变量

描述

需要方

AIRFLOW__API_AUTH__JWT_SECRET

JWT 签名密钥(对称模式)

API 服务器, 调度器

AIRFLOW__API__SECRET_KEY

用于日志令牌签名的 API 秘密密钥

API 服务器, 调度器, Worker, Triggerer

AIRFLOW__CORE__ASSET_MANAGER_KWARGS

资产管理器凭据

DAG 文件处理器

AIRFLOW__CORE__FERNET_KEY

静态连接/变量的 Fernet 加密密钥

API 服务器, 调度器, Worker, DAG 文件处理器, Triggerer

AIRFLOW__DATABASE__SQL_ALCHEMY_CONN

元数据数据库连接字符串

API 服务器, 调度器, DAG 文件处理器, Triggerer

AIRFLOW__DATABASE__SQL_ALCHEMY_CONN_ASYNC

异步元数据数据库连接字符串

API 服务器, 调度器, DAG 文件处理器, Triggerer

AIRFLOW__DATABASE__SQL_ALCHEMY_ENGINE_ARGS

SQLAlchemy 引擎参数(可能包含凭据)

API 服务器, 调度器, DAG 文件处理器, Triggerer

AIRFLOW__LOGGING__REMOTE_TASK_HANDLER_KWARGS

远程日志记录处理程序凭据

调度器, Worker, Triggerer

AIRFLOW__SECRETS__BACKEND_KWARGS

秘密后端凭据(非 Worker 模式)

调度器, DAG 文件处理器, Triggerer

AIRFLOW__SENTRY__SENTRY_DSN

Sentry 错误报告端点

调度器, Triggerer

AIRFLOW__WORKERS__SECRETS_BACKEND_KWARGS

Worker 特有的秘密后端凭据

Worker

注意,AIRFLOW__API_AUTH__JWT_PRIVATE_KEY_PATH(非对称签名的 JWT 私钥路径)在 config.yml 中未标记为 sensitive,因为它是一个文件路径,而非秘密值本身。但是,对它所指向文件的访问应仅限于调度器(生成令牌)和 API 服务器(验证令牌)。

提供商特定的敏感配置变量

以下变量由 Airflow 提供商定义,应仅在需要相应提供商功能的组件上设置。决定哪些组件需要这些变量,取决于部署管理者对每个组件中启用了哪些提供商和功能的决策。

环境变量

提供商

描述

AIRFLOW__CELERY_BROKER_TRANSPORT_OPTIONS__SENTINEL_KWARGS

celery

Sentinel 参数

AIRFLOW__CELERY_RESULT_BACKEND_TRANSPORT_OPTIONS__SENTINEL_KWARGS

celery

Sentinel 参数

AIRFLOW__CELERY__BROKER_URL

celery

Broker URL

AIRFLOW__CELERY__FLOWER_BASIC_AUTH

celery

Flower 基本认证

AIRFLOW__CELERY__RESULT_BACKEND

celery

Result Backend

AIRFLOW__KEYCLOAK_AUTH_MANAGER__CLIENT_SECRET

Keycloak

Client Secret

AIRFLOW__OPENSEARCH__PASSWORD

opensearch

密码

AIRFLOW__OPENSEARCH__USERNAME

opensearch

用户名

部署管理者应审查完整的配置参考,并识别任何包含与特定部署相关的凭据或秘密的其他参数。

使用非对称密钥进行 JWT 签名

使用非对称密钥(带 JWKS 端点的 [api_auth] jwt_private_key_path)比对称密钥提供更好的安全性,因为:

  • 私钥(用于签名)可以仅限于调度器/Executor 使用。

  • API 服务器仅需要公钥(通过 JWKS)进行验证。

  • 即使 Worker 能够访问 JWKS 端点,他们也无法伪造令牌,因为他们没有私钥。

网络级隔离

使用网络策略、VPC 或类似机制来限制哪些组件可以相互通信。例如,Worker 应该只能到达执行 API 端点,而不能直接到达元数据数据库或内部服务。如果实施了 Unix 用户级隔离,DAG 文件处理器和 Triggerer 子进程理想情况下也不应拥有对元数据数据库的网络访问权限。

其他措施与未来改进

根据安全需求,部署管理者可能需要实施额外的措施。这些可能包括监视和审计执行 API 的访问模式、对 DAG 代码进行运行时沙盒化,或为每个团队使用专用基础设施。

Airflow 的未来版本计划通过以下两种方法来解决这些限制:

  • 战略性(长期):使 DAG 文件处理器和 Triggerer 完全通过 API 服务器与元数据数据库通信(类似于 Worker 目前使用执行 API 的方式)。这将消除这些组件对数据库凭据的需要,从而在设计上实现安全,而不是依赖部署层面的措施。

  • 战术性(短期):在 DAG 文件处理器和 Triggerer 子进程中原生支持 Unix 用户模拟,以便 DAG 作者的代码以不同的低权限用户身份运行,该用户无法访问父进程的凭据或数据库。

Airflow 社区正在积极进行这些改进。

自定义 RBAC 的限制

虽然在 Airflow 中定义的 RBAC 可能限制了某些 UI 用户对特定 DAG 和功能的访问,但涉及到自定义角色和权限时,某些权限可能会覆盖用户对 DAG 的个体访问权限或缺乏该权限。例如,审计日志权限允许拥有该权限的用户查看所有 DAG 的日志,即使他们没有明确访问这些 DAG 的权限。这是部署管理者在创建自定义 RBAC 角色时应该了解的内容。

通过资产 (Assets) 触发 DAG

通过资产触发 DAG 是一项允许资产物化(asset materialization)来触发 DAG 的功能。此功能旨在允许在不给予用户手动触发 DAG 的特定权限的情况下触发 DAG。“触发 DAG”权限仅影响通过 UI 或 API 手动触发 DAG,但不影响通过资产触发 DAG。DAG 作者明确允许特定资产触发 DAG,并允许任何有能力创建这些资产的人通过资产触发 DAG。

部署管理者的职责

作为部署管理者,您应该了解 DAG 作者的能力,并确保您信任他们不会滥用这些能力。您还应确保已正确配置 Airflow 安装,以防止 DAG 作者在调度器和 API 服务器进程中执行任意代码。

部署与保护 Airflow 安装

部署管理者还负责部署 Airflow,并使其以遵循部署 Airflow 的组织所适用的安全部署最佳实践的方式可供用户访问。这包括但不限于:

  • 使用 TLS/VPC 和部署 Airflow 的组织所需的任何网络安全措施来保护通信;

  • 应用 Web 应用程序通常采用的速率限制(rate-limiting)和其他形式的保护;

  • 对 Web 应用程序应用认证和授权,以便只有已知且授权的用户才能访问 Airflow;

  • 检测任何异常活动并针对其采取保护措施;

  • 选择正确的会话后端并对其进行正确配置,包括会话超时。

限制 DAG 作者的能力

部署管理者也可以使用其他机制来防止 DAG 作者执行任意代码——例如,他们可以在 DAG 提交周围引入工具,允许在部署前审查代码、对其进行静态检查,并添加其他方式来防止恶意代码被提交。向 DAG 包提交代码的方式和保护方式完全由部署管理者决定——Airflow 不提供围绕此的任何工具或机制,并期望部署管理者提供保护对 DAG 包访问的工具,并确保只有受信任的代码被提交到那里。

Airflow 不会原生实现任何此类功能,而是委托给部署管理者去部署所有必要的基础设施以保护部署——将其作为外部基础设施组件。

限制已认证 UI 用户的访问权限

部署管理者也会确定访问级别,且必须了解用户可能造成的潜在损害。一些部署管理者可能会通过对已认证 UI 用户实施细粒度特权来进一步限制访问。然而,这些限制超出了 Airflow 的基本安全模型,由部署管理者自行决定。

细粒度访问控制的示例包括(但不限于):

  • 限制登录权限:限制用户可以使用哪些账户登录,仅允许特定账户或角色所属的账户访问 Airflow 系统。

  • 对视图或 DAG 的访问限制:控制用户对特定视图或特定 DAG 的访问,确保用户只能查看或与经授权的组件交互。

未来规划:多团队隔离

这些示例展示了部署管理者可以如何在 Airflow 内部细化和限制用户权限,提供更严格的控制,并确保用户只能根据其角色和职责访问必要的组件和功能。然而,细粒度访问控制尚不能提供不同用户组之间的完全隔离和访问分离。

实验性的多团队功能([core] multi_team)是迈向跨团队隔离的一步,但它目前仅在 UI 和 REST API 层面上强制执行基于团队的隔离。任务级隔离尚未得到保证——来自不同团队的工作负载共享同一个执行 API、JWT 签名密钥,以及对连接、变量和 XCom 的访问权限。在未实施额外加固措施(描述见 用于改进隔离的部署加固)的部署中,属于一个团队的任务可能访问到其他团队任务可用的共享资源。启用多团队功能的部署管理者不应仅仅依赖它来进行团队间任务执行层的关键安全隔离——部署管理者需要深入理解配置和部署安全性,以便以能够保证团队间分离的方式进行配置。

Airflow 的未来版本将改进任务级隔离,包括强制执行团队作用域的执行 API、更细粒度的 JWT 令牌作用域,以及对用户提交的代码进行更好的沙盒化处理。Airflow 社区正在积极进行这些改进。

什么情况不被视为安全漏洞

以下场景被视为 Airflow 中的安全漏洞。它们要么是蓄意的设计选择、上述信任模型的后果,要么是超出 Airflow 威胁模型的问题。安全研究人员(以及执行安全分析的 AI 代理)在向 Airflow 安全团队报告问题前应先审查本节。

关于报告策略的完整详情,请参阅 Airflow 安全策略

DAG 作者执行任意代码

DAG 作者可以在 Worker、DAG 文件处理器和 Triggerer 上执行任意代码。这包括访问凭据、环境变量,以及(在 DAG 文件处理器和 Triggerer 的情况下)直接访问元数据数据库。正如 DAG 作者的功能权限 中所述,这是预期行为——DAG 作者是受信任的用户。声称 DAG 作者可以通过编写 DAG 代码“实现 RCE”或“访问数据库”的报告,是在重申一个已记录的功能,而不是发现了漏洞。

DAG 作者的代码将未经清理的输入传递给 Operator 和 Hook

当 DAG 作者编写代码将未经清理的 UI 用户输入(如 DAG 运行参数、变量或连接配置值)传递给 Operator、Hook 或第三方库时,责任由 DAG 作者承担。Airflow 的 Hook 和 Operator 是低级接口——DAG 作者是必须在将输入传递给这些接口之前对其进行清理的 Python 程序员。

SQL 注入或命令注入仅在可被非 DAG 作者用户角色(例如,已认证 UI 用户)触发,且不涉及 DAG 作者蓄意编写未安全传递输入代码的情况下,才被视为漏洞。如果利用注入的唯一方法是编写或修改 DAG 文件,则它不是漏洞——DAG 作者已经具备执行任意代码的能力。另请参阅 SQL 注入

官方 Airflow 文档明确推荐了导致注入的模式的情况除外——在这种情况下,文档指南本身即是问题,可能需要发出咨询建议。

DAG 文件处理器和 Triggerer 可能拥有数据库访问权限

Dag 文件处理器可能直接访问数据库以存储序列化的 Dag。触发器可能直接访问数据库以管理触发器状态。这两个组件都会执行用户提交的代码(分别是 Dag 文件和触发器代码),并可能通过进程内执行 API 传输绕过 JWT 身份验证。这些是经过深思熟虑的架构选择,而非漏洞。它们记录在 JWT 身份验证与工作负载隔离 中。

Workers 访问共享的执行 API 资源

Worker 任务可以使用其 JWT 令牌通过执行 API 访问连接、变量和 XCom。虽然 ti:self 作用域可以防止跨任务状态篡改,但所有任务都可以访问共享资源。这是当前的设计,而非漏洞。关于“一个任务可以读取另一个团队的连接”的报告,描述的是当前隔离模型的已知限制,记录在 JWT 身份验证与工作负载隔离 中。

执行 API 令牌不可撤销

发放给 Worker 的执行 API 令牌是短期的(默认 10 分钟),具有自动刷新功能,且特意不进行撤销。这是一种设计选择,记录在 JWT 令牌身份验证 中,而非缺失的安全控制。

连接配置功能

具有连接配置角色的用户可以配置带有任意凭据和连接参数的连接。当启用 test connection(测试连接)功能时,这些用户可能通过连接参数触发远程代码执行(RCE)、任意文件读取或拒绝服务攻击。这是设计使然——连接配置用户属于高权限用户,必须确保他们不会滥用这些功能。自 Airflow 2.7.0 起,test connection 功能默认禁用,启用该功能是部署经理明确认可这些风险后的决定。详细信息请参阅 连接配置用户

已认证用户的拒绝服务攻击

Airflow 的设计并非为了暴露给公共互联网上的不受信任用户。所有可以访问 Airflow UI 和 API 的用户均经过身份验证且已知。由已认证用户触发的拒绝服务场景(例如创建非常大的 Dag 运行、提交昂贵的查询或洪水攻击 API)不被视为安全漏洞。这些是运营层面的问题,部署经理应通过限流、资源配额和监控等手段来解决——这是任何内部应用程序的标准措施。请参阅 部署与保护 Airflow 安装

已认证用户的自我 XSS

仅受害者本人注入有效负载的跨站脚本(XSS)场景(即自我 XSS)不被视为安全漏洞。Airflow 的用户均已认证且已知,且自我 XSS 不允许攻击者危害其他用户。如果您发现一种 XSS 场景,其中低权限用户可以注入有效负载,并在未经高权限用户操作的情况下在高权限用户的会话中执行,那才是一个有效的漏洞,应该进行报告。

简易身份验证管理器 (Simple Auth Manager)

简易身份验证管理器仅供开发和测试使用。这一点有明确文档记录,且登录页面上会显示明显的警告横幅。该管理器特有的安全问题(如弱密码处理、缺乏限流或缺少 CSRF 防护)不被视为生产环境的安全漏洞。生产环境部署必须使用生产级的身份验证管理器。

Docker 镜像中第三方依赖项的漏洞

Airflow 的参考 Docker 镜像在发布时会构建最新的可用依赖项。随着新 CVE 的发布,通过扫描这些镜像对比 CVE 数据库发现漏洞是预期之中的。这些漏洞不应报告给 Airflow 安全团队。用户应按照 Docker 镜像文档 中的说明,使用更新的依赖项构建自己的镜像。

如果您发现第三方依赖漏洞在 Airflow 中确实可被利用(并提供了证明其在 Airflow 上下文中可被利用的概念验证),则这是一个有效的报告,应按照安全策略进行提交。

未经人工验证的自动化扫描结果

列出未经人工对比 Airflow 安全模型验证的自动化安全扫描报告,不被视为有效的漏洞报告。Airflow 的信任模型与典型的 Web 应用程序有显著不同——许多扫描结果(例如“管理员用户可以执行代码”或“数据库凭据在配置中可见”)属于预期行为。报告必须包含概念验证,证明该发现如何违反本文档中描述的安全模型,包括识别所涉及的具体用户角色和攻击场景。

此条目是否有帮助?