|
2 | 2 | :description: Secure Apache Airflow by configuring user authentication and authorization. |
3 | 3 | :airflow-access-control-docs: https://airflow.apache.org/docs/apache-airflow-providers-fab/stable/auth-manager/access-control.html |
4 | 4 | :keycloak: https://www.keycloak.org/ |
| 5 | +:airflow-fab-token-docs: https://airflow.apache.org/docs/apache-airflow-providers-fab/stable/auth-manager/token.html |
5 | 6 |
|
6 | 7 | Secure Apache Airflow by configuring user authentication and authorization. |
7 | 8 | Airflow provides built-in user and role management, but can also connect to an LDAP server or an OIDC provider to manage users centrally instead. |
@@ -140,6 +141,60 @@ A minimum client configuration in Keycloak for this example looks like this: |
140 | 141 |
|
141 | 142 | Further information for specifying an AuthenticationClass for an OIDC provider can be found at the xref:concepts:authentication.adoc#_oidc[concepts page]. |
142 | 143 |
|
| 144 | +=== [[api-access]]REST API access |
| 145 | + |
| 146 | +This section applies to Airflow 3.x. |
| 147 | + |
| 148 | +The authentication methods described above (built-in users, LDAP and OpenID Connect) govern how users log in to the web interface. |
| 149 | +The REST API (`/api/v2`) authenticates requests differently: it accepts only JSON Web Tokens (JWTs) issued by Airflow itself. |
| 150 | +A client obtains such a token by sending a username and password to the `/auth/token` endpoint of the webserver: |
| 151 | + |
| 152 | +[source,bash] |
| 153 | +---- |
| 154 | +ACCESS_TOKEN=$( |
| 155 | + curl -s -X POST http://<cluster>-webserver:8080/auth/token \ |
| 156 | + -H 'Content-Type: application/json' \ |
| 157 | + -d '{"username": "<user>", "password": "<password>"}' | jq -r '.access_token' |
| 158 | +) |
| 159 | +curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \ |
| 160 | + http://<cluster>-webserver:8080/api/v2/dags/<dag_id>/dagRuns |
| 161 | +---- |
| 162 | + |
| 163 | +The `/auth/token` endpoint checks the credentials against Airflow's internal user database (and against the LDAP server if LDAP authentication is configured). |
| 164 | +See the {airflow-fab-token-docs}[Airflow documentation on generating tokens{external-link-icon}^] for details. |
| 165 | + |
| 166 | +IMPORTANT: With OpenID Connect, Keycloak is used for the interactive login to the web interface only. |
| 167 | +Tokens issued by Keycloak (for example via the client credentials grant of a service account) are rejected by the REST API with `Invalid JWT token`. |
| 168 | +Users created through a Keycloak login have no usable password in Airflow, so their credentials are rejected by `/auth/token` with `Invalid credentials`. |
| 169 | + |
| 170 | +NOTE: Airflow allows tokens to be obtained for OAuth users by overriding the `create_token` method of the FAB auth manager, as described in the {airflow-fab-token-docs}[Airflow documentation on generating tokens{external-link-icon}^]. |
| 171 | +The Stackable Data Platform does not provide or test such an override. |
| 172 | +It requires a custom auth manager in a custom image, and that code is then responsible for validating the token from the identity provider. |
| 173 | + |
| 174 | +IMPORTANT: The example in the Airflow documentation disables signature verification and (as also stated there) should not be used in production. |
| 175 | + |
| 176 | +==== Service-to-service access |
| 177 | + |
| 178 | +For API clients such as scripts, external services or DAGs, create a dedicated user in Airflow's internal user database. |
| 179 | +This works regardless of the authentication method configured for the web interface. |
| 180 | +Assign the least privileged role that covers the required API calls; for example, the `Viewer` role allows reading DAGs and DAG runs, but not modifying them: |
| 181 | + |
| 182 | +[source,bash] |
| 183 | +---- |
| 184 | +kubectl exec <cluster>-webserver-<rolegroup>-0 -c airflow -- \ |
| 185 | + airflow users create \ |
| 186 | + --username <technical-user> \ |
| 187 | + --password <password> \ |
| 188 | + --role Viewer \ |
| 189 | + --firstname <first-name> \ |
| 190 | + --lastname <last-name> \ |
| 191 | + --email <email> |
| 192 | +---- |
| 193 | + |
| 194 | +Store the credentials in a Kubernetes Secret and make them available to the client. |
| 195 | +Request a new token for each run rather than storing one, as tokens expire. |
| 196 | +See xref:usage-guide/dag-run-information.adoc[] for an example of a DAG that reads DAG run information via the REST API. |
| 197 | + |
143 | 198 | == Authorization |
144 | 199 |
|
145 | 200 | The Airflow Webserver delegates the {airflow-access-control-docs}[handling of user access control{external-link-icon}^] to the https://flask-appbuilder.readthedocs.io/en/latest/security.html[Flask AppBuilder{external-link-icon}^]. |
|
0 commit comments