Skip to content

DAG-level access control broken without global RESOURCE_DAG permissions #58985

@bmoon4

Description

@bmoon4

Apache Airflow Provider(s)

fab

Versions of Apache Airflow Providers

Description

When implementing team-based DAG isolation by removing global RESOURCE_DAG permission, users cannot access DAG runs, or task instances—even with explicit scoped permissions via access_control.

This forces users to grant global permissions as a workaround, defeating the purpose of DAG-level access control.

Current Behavior

Without global permissions: (RESOURCE_DAG)

With global permissions (workaround):

  • ✅ All views accessible (DAG Run, Task Instances)
  • ⚠️ But users see ALL DAGs (no isolation)

Expected Behavior

Users should be able to access their scoped DAGs, runs, and tasks using only the permissions defined in access_control, without needing global permissions.

Environment

  • Airflow Version: 3.0.6
  • FAB Provider Version: apache-airflow-providers-fab == 2.4.1
  • Backend: Any (issue is in auth logic)

Steps to Reproduce

  1. Create a DAG with scoped access:
dag = DAG(
    "team_a_dag",
    access_control={"TEAM_A": {'can_read', 'can_edit'}}
)
  1. Create a user with only TEAM_A role (no global RESOURCE_DAG permission)

  2. Try to view DAG runs (/dag_runs), Task Instances(/task_instances)
    Result: 403 Forbidden ❌

Root Cause Analysis

Four authorization issues in fab_auth_manager.py:

  1. get_authorized_dag_ids() ignores DAG Run: scoped permissions
  2. is_authorized_dag() requires DAG-level permission before checking sub-entities
  3. _is_authorized_dag() returns false for list endpoints without checking any scoped permissions
  4. _is_authorized_dag_run() doesn't check DAG-level permission as fallback

Related Issues

Similar issue mentioned by @romanpanov993 in #51325

Apache Airflow version

3.0.6

Operating System

debian

Deployment

Other Docker-based deployment

Deployment details

No response

What happened

No response

What you think should happen instead

No response

How to reproduce

  1. Create a DAG with scoped access:
dag = DAG(
    "team_a_dag",
    access_control={"TEAM_A": {'can_read', 'can_edit'}}
)
  1. Create a user with only TEAM_A role (no global RESOURCE_DAG permission)

  2. Try to view DAG runs (/dag_runs), Task Instances(/task_instances)
    Result: 403 Forbidden ❌

Anything else

No response

Are you willing to submit PR?

  • Yes I am willing to submit a PR!

Code of Conduct

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions