Status

StateAccepted
Discussion Threadhttps://lists.apache.org/thread/57zpjqvxstm45ro1zdj7c2gltjlttfrp
Vote Threadhttps://lists.apache.org/thread/drshhyd1sy3kgzpdk9nwf4djt0s0xxmd
Vote Result Threadhttps://lists.apache.org/thread/2b131o1yxshq1v2c8480hq7h3nkjf21x
Progress Tracking (PR/GitHub Project/Issue Label)
Date Created

2024-07-24

Version Released
AuthorsBuğra Öztürk 

Motivation

The Command-Line Interface (CLI) for Airflow includes various types, such as those with direct database access, those operating locally, those running core Airflow components, and those that combine these features. Integrating API functionality into the CLI can provide isolated and secure database access while enabling features like built-in authentication. This integration facilitates the seamless deployment of CLI and API features together, reducing redundancy and simplifying maintenance. Transitioning from direct database access to an API-driven model will enhance the CLI’s capabilities and improve security. A gateway to bridge CLI commands with API interactions will support this shift, requiring new definitions and security protocols to ensure effective and secure communication.

Considerations

What change do you propose to make?

Definitions:

  • Core Commands: CLI commands for managing Airflow.
  • API Commands: CLI commands designed to interface with the API.

It is proposed to categorize Core Commands into the following groups. Categorizing commands will help identify which ones can be replaced with API Commands. This means an easier transition period if needed.

  1. Airflow Management Commands: Commands for tasks such as running the webserver, scheduler, internal API server, or operating Airflow in standalone mode.
  2. Database Access Commands: Commands involving direct database access, such as listing DAGs, and managing tasks, connections, and variables.
  3. Hybrid Commands: Commands that manage Airflow while also requiring direct database access.

API Commands will support all necessary API interactions, following a consistent naming convention (to be defined), such as:

Example Airflow API Commands
airflow dags list  
airflow taskinstances clear dag_id task_id 

API commands should be auto-generated as much as possible from configuration files (such as OpenAPI or the chosen API technology). This approach will minimize the number of changes required for new or updated API endpoints, ensuring consistency and reducing manual effort. It would be good to have a tool to auto-generate these commands. 

Security Considerations:

  • API Commands
    • Existing Security Policies: Utilize current security policies for API endpoints, such as permissions required for listing DAGs.
  • Core Commands
    • Airflow Management Commands: Commands like the webserver and scheduler, which prepare or create environments and do not require prior authorization, should remain unchanged.
    • Database Access Commands: Commands that involve direct database access should transition to API Commands, ensuring all database interactions are handled through the API with appropriate authentication and permissions.
    • Hybrid Commands: Commands that manage Airflow and also involve direct database access should route database communication through API methods. Examples include loading DagBag and accessing DagRun from commands used by Celery and Kubernetes executors. These commands often operate with daemon options, minimizing instances where both direct database access and management functionalities are needed simultaneously.

The CLI should be secure-by-design. This means any sensitive data used by the CLI should be handled properly, such as being passed through stdin or retrieved from environment variables. Ensuring secure data handling practices will protect against potential security vulnerabilities and maintain user trust.

Command Inventory with Command Type Categorisation 

CommandCommand TypeNotes
cheat_sheat_commandCore Command
dag-processorCore Command
infoCore Command
internal-apiCore Command
kerberosCore Command
pluginCore Command
schedulerCore Command
standaloneCore Command
triggererCore Command
versionCore CommandPlan to be a Hybrid Command where it will show the CLI and the Airflow version. CLI version will be able to run locally. The Airflow version should be returned from API, please check Check Command/Subcommand and API Endpoint Mapping.
webserverCore Command
configDirect DB AccessFully REST Integration Needed. Check Command/Subcommand and API Endpoint Mapping.
connectionsDirect DB AccessFully REST Integration Needed. Check Command/Subcommand and API Endpoint Mapping.
dagsDirect DB AccessFully REST Integration Needed. Check Command/Subcommand and API Endpoint Mapping.
dbDirect DB AccessFully REST Integration Needed. Check Command/Subcommand and API Endpoint Mapping.
jobsDirect DB AccessFully REST Integration Needed. Check Command/Subcommand and API Endpoint Mapping.
poolsDirect DB AccessFully REST Integration Needed. Check Command/Subcommand and API Endpoint Mapping.
tasksDirect DB AccessFully REST Integration Needed. Check Command/Subcommand and API Endpoint Mapping.
variablesDirect DB AccessFully REST Integration Needed. Check Command/Subcommand and API Endpoint Mapping.
rotate-fernet-keyHybrid CommandFully REST Integration Needed. Check Mapping for endpoints.
providerHybrid CommandDB connections will be replaced by API flavour.
awsHybrid CommandDB connections will be replaced by API flavour.
celeryHybrid CommandActual CLI command implementation in the core is deprecated. From provider apache-airflow-providers-celery. DB connections will be replaced by API flavour.
kubernetesHybrid CommandActual CLI command implementation in the core is deprecated. From provider apache-airflow-providers-cncf-kubernetes. DB connections will be replaced by API flavour.
fabHybrid CommandDB connections will be replaced by API flavour.

Command/Subcommand and API Endpoint Mapping

CommandSubcommandREST Endpoint Name (with Additional Notes)
configget_valueGet a option from configuration
configlistGet current configuration
connectionsaddCreate a connection
connectionsdeleteDelete a connection
connectionsexportMissing: Export connection(s) from a file
Additional Note: This could be done via parsing the JSON locally and calling the API endpoints accordingly. I think this would cause too many API requests. I think we can handle this one in a single request via accepting multipart file
connectionsgetGet a connection
connectionsimportMissing: Import connection(s) from a file
Additional Note: This could be done via parsing the JSON locally and calling the API endpoints accordingly. I think this would cause too many API requests. I think we can handle this one in a single request via accepting multipart file
connectionslistList connection
connectionstestTest a connection
dagsbackfillMissing: Backfill a dag
Additional note:
Rely on AIP-78
dagsdeleteDelete a DAG
dagsdetailsGet basic information about a DAG
dagslistList DAGs
dagslist-import-errorsList dag warnings
dagslist-jobsMissing: List Jobs
dagslist-runsList DAG runs
dagsnext-executionGet basic information about a DAG
dagspauseUpdate a DAG
dagsreportCombination of List DAGs and List task instances
dagsreserializeMissing: Reserialize a DAG
dagsshowMissing: Show a DAG (Graph)
dagsshow-dependenciesMissing: Show Dependencies of a DAG
dagsstateGet a Dag run
dagstestMissing: Test a DAG
dagstriggerTrigger a new DAG run.
dagsunpauseUpdate a DAG
dbinit: deprecated over migrate
check
check-migrations
clean
downgrade
export-archived
migrate
reset
shell
Missing: We should call all the db methods of `db.py` from endpoints to cover each cases
Additional Note: I think we should disable `shell` command since this shouldn't be allowed in airflow CLI context. This should part of user's process which is basically connecting to a database with it's CLI tools/UI tools.
jobscheckMissing: List Jobs with Filter (like State, job_type hostname)
Additional Note: We should make a decision if we want to support the local part. I think it should use the same approach where API calls for the local deployment.
poolslistList pools
poolsgetGet a pool
poolsexportMissing: Import pool(s) from a file
Additional Note: This could be done via parsing the JSON locally and calling the API endpoints accordingly. I think this would cause too many API requests. I think we can handle this one in a single request via accepting multipart file
poolsimportMissing: Import pool(s) from a file
Additional Note: This could be done via parsing the JSON locally and calling the API endpoints accordingly. I think this would cause too many API requests. I think we can handle this one in a single request via accepting multipart file
poolsdeleteDelete a pool
poolssetUpdate a pool
tasksclearMissing: Clear task instance
Additional Note: Rely on AIP-72 Task SDK
Updates the state of a task instance endpoint isn't enough to provide wider scope for clearing multiple task instance at the same time such as providing start-date, only-failed etc...
tasksfailed-depsMissing: List failed dependencies of a task instance
Additional Note: Rely on AIP-72 Task SDK
taskslistList task instances
Additional Note: Rely on AIP-72 Task SDK
tasksrenderMissing: Render a task instance
Additional Note: Rely on AIP-72 Task SDK
tasksrunMissing: Run a task instance
Additional Note: Rely on AIP-72 Task SDK
tasksstateGet a task instance
Additional Note: Rely on AIP-72 Task SDK
tasksstates-for-dag-runList task instances
Additional Note: Rely on AIP-72 Task SDK
taskstestMissing: Run a task instance without DB Update
Additional Note: Rely on AIP-72 Task SDK
variablesdeleteDelete a variable
variablesgetGet a variable
variablesexportMissing: Import variables(s) from a file
Additional Note: This could be done via parsing the JSON locally and calling the API endpoints accordingly. I think this would cause too many API requests. I think we can handle this one in a single request via accepting multipart file
variablesimportMissing: Import variables(s) from a file
Additional Note: This could be done via parsing the JSON locally and calling the API endpoints accordingly. I think this would cause too many API requests. I think we can handle this one in a single request via accepting multipart file
variableslistList variables
variablessetUpdate a variable
rotate-fernet-keyrotate-fernet-keyMissing: Rotate fernet key
providers*Missing: List providers with all the informations
Additional Note:
Current List providers endpoint isn't enough due to it's not returning enough information about providers.
aws-auth-manager*Additional Note: No additional DB call(s) other than loading provider configuration.
celery*Additional Note: No additional DB call(s) other than loading provider configuration.
kubernetescleanup-podsAdditional Note: No additional DB call(s) other than loading provider configuration.
kubernetesgenerate-dag-yamlList task instances
Additional Note: Rely on AIP-72 Task SDK
No additional DB call(s) other than loading provider configuration.
fab*

Missing: Import Users, Export Users, Import Roles, Export Roles

Additional Note: This could be done via parsing the JSON locally and calling the API endpoints accordingly. I think this would cause too many API requests. I think we can handle this one in a single request via accepting multipart file
All the other endpoints avaiable under fab API for this command

version*

Missing: Get Airflow version

Additional Note: This API will only return the Airflow version in the running environment. The CLI version will be locally displayed.

This mapping doesn't contain any Core Commands due to they will stay the same without any additional changes.

General Note for Hybrid Commands added by providers: `providers_configuration_loaded` calls `ProvidersManager().initialize_providers_configuration()`. This command is only depends on dataset endpoints. When changing the method with API calls, this should apply to all the commands coming from the providers.

Unified Authentication Mechanism for CLI and API Integration

The authentication mechanism should be consistent across all setups, adopting a unified approach for all authentication scenarios. Despite variations in the backend authentication systems, the same authentication mechanism will be used. The only difference is that, instead of redirecting users to the default page, it will redirect them to the CLI.

User Workflow

All users will authenticate through the CLI using a standard command. This command will redirect users to the Webserver Sign-In page, where they will approve the authentication request. Upon approval, the API will return a token to the CLI, completing the authentication process. All subsequent API calls will be made using this token.

Automation Workflow (CI/CD or Automated Processes)

For CLI use in CI/CD pipelines or other automated processes, users will need to acquire the token independently. This can be done through the User Profile, where there will be a button to generate an API token specifically for automated users. Users can set the expiration date for this token to avoid rotating credentials with each run. Additionally, an API should be available to renew the expiration date of the token before it expires. If the token expires, users will need to follow the same procedure to acquire a new token. To support this process, Airflow should include a flag indicating whether a user is an automated (computer) user or an individual (human) user. Automated users should not have access to any webpages in the UI.

Important Notes

  • A crucial aspect of this approach is the implementation of an expiration date for tokens obtained through the user workflow. For automated workflows, users should be allowed to set their own expiration dates, and there should be unique permissions for managing tokens for automated users.
  • Users will need to enter the API URL once, and it will be saved for future use. After that, they can enter the authentication command without providing the URL. Automated users, however, will need to use a different command from the same command family, which will require additional token information during authentication.
  • Individual users cannot generate a token with a long lifespan due to security concerns, as user tokens are typically stored on personal computers. In contrast, tokens for automated processes are generally stored in a secure (secret) backend.
  • There should be a separation between the actual sign-in endpoint and the CLI sign-in endpoint. This separation will be enforced at the sign-in level. Even if a user is already logged in and can access web pages without signing in again, the CLI sign-in will still require mandatory user validation.

Diagrams


Use Case Diagram: User Flow

Activity Diagram: User Flow

Use Case Diagram: Automation Flow

Activity Diagram: Automation Flow

Release Strategy

Release it as a separate package. This will reduce the number of dependencies and reduce the release maintenance effort. This strategy will be discussed as more broad

Name Suggestion: apache-airflow-cli

Dependencies on other AIPs

Some parts of this AIP rely on other AIP works such as removing the backfill mechanism from CLI or using Task SDK to use some APIs. The scaffolding of the API Commands and authentication mechanisms can start earlier.

Which users are affected by the change?

All the Airflow users that are using the CLI

How are users affected by the change? (e.g. DB upgrade required?)

Users should have to use authentication mechanism for all the API Commands.

For Core Commands,

Command NameAuthentication Needed
Direct Database Access CommandsYes
Local CommandsNo
Hybrid CommandsYes

Local Commands needs an Airflow Config (CFG)  with Database Connection string filled to be able to execute. The other commands (Direct Database Access Commands and Hybrid Commands) won't need an Airflow Config (CFG) to execute.

What is the level of migration effort (manual and automated) needed for the users to adapt to the breaking changes? (especially in context of Airflow 3)

No changes are needed in this context. Users will continue to use Core Commands in the CLI as they do now, while new API Commands will also be available.


10 Comments

  1. Looks like there is a GitHub issue (although 4 year old) for it too: https://github.com/apache/airflow/issues/10552

    1. Good to see that there was the same vision and it will be accomplished after 4 years :) Great one, I missed that. I deleted the api part from the naming convention. Thanks Kaxil!

  2. Looks interesting. 

    I assume that you would be relying on other work such as the AIP-78 Scheduler-managed backfill and AIP-72 Task Execution Interface for some of the APIs to call. 
    Do you have a sense of what APIs are missing? 


    1. Great point! Indeed, to fully complete this AIP, some parts of the work rely on AIP-78 Scheduler-managed backfill and some parts rely on AIP-72 Task Execution Interface. I think most parts can be transitioned after AIP-72 since AIP-78 only covers one flavour of the CLI. We can start scaffolding the API Commands and authentication mechanisms while these AIPs are in progress. I am updating the proposal to include these dependencies.

      I don’t know how many of them are missing. The next step is the categorization of the current CLIs and mapping them to each API we have. Jarek has a great suggestion in the thread to make an inventory. I will make the inventory for the current commands. I will map the inventory with the current APIs. That mapping will help us to identify which part is missing from where. I will do that work soon and will include it in the AIP. Thanks, Vikram!

  3. As discussed in the Dev-Call I support this cleanup, especially because redundancy is removed and a clear entrypoint is defined.

    Otherwise I see it challening as the API authentication might be different depending on the setup. It is limited to an interactive session per default (Today with FAB: https://airflow.apache.org/docs/apache-airflow-providers-fab/stable/auth-manager/api-authentication.htmlauth_backends = airflow.api.auth.backend.session).

    So follow-up questions:

    • Would we then ensure stable API is enabled per default - or will airflow CLI only usable if explicitly enabled?
    • Username / password authentication might be OK, but how about if the API is protected by Kerberos/oAuth? How will this be supported in CLI?
      • I think everything should be disabled by default. Even though this could cause additional migration changes by adding a new statement in the configuration, it would be safer to disable it at the start. For example, if a user is neither using the API nor CLI, this can help to reduce entry points to the system by default.
      • We can use an open-source project similar to apache-airflow-providers-fab (requests-kerberos). We may need to include a couple of new implementations to support different setups or implement them ourselves if they are missing. I don’t think we should do any authentication at the CLI level. We should always call our APIs for it. This would be safer. I will make the API authentication a separate title. It will include this topic there in detail soon.

      Thanks, Jens!

  4. I like the state of it now! 

    1. Thanks for the feedback, Jarek! Great to hear that!

  5. Great work on this one Buğra Öztürk  on this short time. The Authentication flow is the only one (but critical) thing to be figured out before we can start the VOTE IMO. The good thing though is that is a common feature, so we have good examples to look:

    where we can store the Base URL of the "host" somewhere so we don't need to explicitly pass it for each command.


    One more advantage of this AIP is if things are routed through an API, you can now connect to remote Airflow deployments and get results for most of them – which is why I feel we should utilize the API for things like "version" too. And then it would be similar to kubectl 

    1. Thanks, Kaxil Naik ! I’m enjoying the ride (smile) I’ve also included the authentication flow in the document. I have updated the document step by step to collect incremental feedback to finalize this AIP more swiftly. 

      These examples align perfectly with what I had in mind. For authentication, I envisioned a method similar to google-cloud-sdk, and throughout the design and planning of this AIP, I’ve been drawing inspiration from kubectl