mik-laj opened a new issue #11305:
URL: https://github.com/apache/airflow/issues/11305
# Why?
Users expect integration with various Identity Aware Proxies (IAP) that
provide authorization. The use of such proxies brings many benefits.
- facilitates the enforcement of the company's policy by:
- central access management, depending on the proxy selected, we can
support various authentication protocols, including LDAP, Google IAM, SAML,
OpenID
- audibility - can write additional metadata about the operations
performed by users
- No need to keep secrets in a container that can execute user code. All the
necessary user info is provided in a push model.
- One proxy can be used to protect multiple applications, so it is code that
meets higher security standards. They are often regularly audited. The in-app
part is very simple and easier to audit.
Besides, it can make using LDAP with Airflow much easier. Deficiencies in
the implementation of LDAP for Airflow will no longer be a problem for our
users e.g. https://github.com/dpgaspar/Flask-AppBuilder/issues/956)
I think we should prepare implementations for some of the most popular
products:
- [Louketo Proxy](https://github.com/louketo/louketo-proxy) (formerly
Keycloak Gateway)
- [Google Identity Aware Proxy (IAP)](https://cloud.google.com/iap)
- [Promerium](https://www.pomerium.com/)
This will be an example for other uses for other products as well.
# How?
In order to accomplish this task for each supported proxy, we need to
prepare two authorization checks - one for Web UI, one for API.
Creating your own API auth backend is described in our documentation:
https://airflow.readthedocs.io/en/latest/security/api.html#roll-your-own-api-authentication
Creating an integration with Flask App Builder is a bit worse described, but
in our case, we can extend
[`REMOTE_USER`](https://flask-appbuilder.readthedocs.io/en/latest/security.html)
to support product-specific headers.
To do this, create a new view based on the
`flask_appbuilder.security.views.AuthView` class, and then set it as an
`authremoteuserview` attribute in the
`airflow.www.security.AirflowSecurityManager` class. You can use the
[`flask_appbuilder.security.views.AuthRemoteUserView`
class](https://github.com/dpgaspar/Flask-AppBuilder/blob/5806f9ff66a26eb287759f890051060060e55e53/flask_appbuilder/security/views.py#L732)
as a template.
Below is a minimal example of the `webserver_config.py` file (you should
save it to `~/airflow/config/`) that provide authorizations using the
`X-Auth-Username` header. The goal is to support more vendor-specific headers
```python
from flask import get_flashed_messages, request, redirect, flash
from flask_appbuilder import expose
from flask_appbuilder._compat import as_unicode
from flask_appbuilder.security.views import AuthView
from flask_login import login_user, logout_user
from airflow.www.security import AirflowSecurityManager
class CustomAuthRemoteUserView(AuthView):
login_template = ""
@expose("/login/")
def login(self):
if g.user is not None and g.user.is_authenticated:
return redirect(self.appbuilder.get_url_for_index)
username = request.environ.get("X-Auth-Username")
if username:
user = self.appbuilder.sm.auth_user_remote_user(username)
if user is None:
flash(as_unicode(self.invalid_login_message), "warning")
else:
login_user(user)
else:
flash(as_unicode(self.invalid_login_message), "warning")
# Flush "Access is Denied" flash messaage
get_flashed_messages()
return redirect(self.appbuilder.get_url_for_index)
@expose("/logout/")
def logout(self):
logout_user()
return redirect("/oauth/logout")
class CustomAirflowSecurityManager(AirflowSecurityManager):
authremoteuserview = CustomAuthRemoteUserView
SECURITY_MANAGER_CLASS = CustomAirflowSecurityManager # pylint:
```
Invoking function `get_flashed_messages` clears the "Access denied" flash
message that appears when the user is redirected from `/` to `/login`. This is
not included with the FAB, but is needed in Airflow.
In the case of Louketo/Keycloak, we should support the following headers:
- X-Auth-Email
- X-Auth-Family-Name
- X-Auth-Given-Name
- X-Auth-Groups
- X-Auth-Roles
- X-Auth-Username
In the case of Google IAP, we should use the JWT signed header:
https://cloud.google.com/iap/docs/signed-headers-howto
In the case of Promerium, we should use the JWT signed header -
`X-Pomerium-Jwt-Assertion: `:
https://www.pomerium.io/docs/topics/getting-users-identity.html#prerequisites
# Status
- [ ] API support Louketo Proxy
- [ ] API support Google IAP
- [ ] API support Promerium
- [ ] Web UI support Louketo Proxy
- [ ] Web UI support Google IAP
- [ ] Web UI support Promerium
- [ ] Docs for Louketo Proxy
- [ ] Docs for Google IAP
- [ ] Docs for Promerium
# Disclaimer
If someone is interested in this task, I will be happy to provide all the
necessary information and support.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]