やるきなし

2021/12/11 19:39 / Jupyterhub LDAP Authentication

Python の code (正確には Jupyter Notebook)を Web 上でインタラクティブに動作させる環境である Jupyterhub で LDAP 認証が使えるのであるが(つまりマルチユーザで利用可能),LDAP w/o SSL 環境(port #: 389)ではそのままではうまく認証できない,という話.

以下のようなエラーを吐いて,認証しようとするとコケる.

[I 2021-12-11 12:48:55.527 JupyterHub app:2717] Running JupyterHub version 2.0.0
[I 2021-12-11 12:48:55.527 JupyterHub app:2747] Using Authenticator: ldapauthenticator.ldapauthenticator.LDAPAuthenticator-1.3.2
[I 2021-12-11 12:48:55.527 JupyterHub app:2747] Using Spawner: jupyterhub.spawner.LocalProcessSpawner-2.0.0
[I 2021-12-11 12:48:55.527 JupyterHub app:2747] Using Proxy: jupyterhub.proxy.ConfigurableHTTPProxy-2.0.0
[I 2021-12-11 12:48:55.528 JupyterHub app:1641] Writing cookie_secret to /tf/jupyterhub_cookie_secret
[I 2021-12-11 12:48:55.541 alembic.runtime.migration migration:201] Context impl SQLiteImpl.
[I 2021-12-11 12:48:55.541 alembic.runtime.migration migration:204] Will assume non-transactional DDL.
[I 2021-12-11 12:48:55.548 alembic.runtime.migration migration:615] Running stamp_revision  -> 833da8570507
[I 2021-12-11 12:48:55.683 JupyterHub proxy:496] Generating new CONFIGPROXY_AUTH_TOKEN
[I 2021-12-11 12:48:55.709 JupyterHub app:1913] Not using allowed_users. Any authenticated user will be allowed.
[I 2021-12-11 12:48:55.727 JupyterHub roles:358] Adding role admin for User: myn
[W 2021-12-11 12:48:55.729 JupyterHub app:2152] No admin role found; assuming hub upgrade. Initializing default roles for all entities
[I 2021-12-11 12:48:55.768 JupyterHub app:2786] Initialized 0 spawners in 0.002 seconds
[W 2021-12-11 12:48:55.769 JupyterHub proxy:687] Running JupyterHub without SSL.  I hope there is SSL termination happening somewhere else...
[I 2021-12-11 12:48:55.769 JupyterHub proxy:691] Starting proxy @ http://:8000
12:48:55.921 [ConfigProxy] info: Proxying http://*:8000 to (no default)
12:48:55.934 [ConfigProxy] info: Proxy API at http://127.0.0.1:8001/api/routes
[I 2021-12-11 12:48:56.023 JupyterHub app:3035] Hub API listening on http://0.0.0.0:8081/hub/
[I 2021-12-11 12:48:56.023 JupyterHub app:3037] Private Hub API connect url http://hoge-mydockerimage:8081/hub/
12:48:56.023 [ConfigProxy] info: 200 GET /api/routes 
12:48:56.024 [ConfigProxy] info: 200 GET /api/routes 
[I 2021-12-11 12:48:56.024 JupyterHub proxy:431] Adding route for Hub: / => http://hoge-mydockerimage:8081
12:48:56.025 [ConfigProxy] info: Adding route / -> http://hoge-mydockerimage:8081
12:48:56.026 [ConfigProxy] info: Route added / -> http://hoge-mydockerimage:8081
12:48:56.026 [ConfigProxy] info: 201 POST /api/routes/ 
[I 2021-12-11 12:48:56.026 JupyterHub app:3101] JupyterHub is now running at http://:8000
[I 2021-12-11 12:53:41.998 JupyterHub log:189] 302 GET / -> /hub/ (@::ffff:10.8.1.6) 0.61ms
[I 2021-12-11 12:53:42.069 JupyterHub log:189] 302 GET /hub/ -> /hub/login?next=%2Fhub%2F (@::ffff:10.8.1.6) 0.51ms
[I 2021-12-11 12:53:42.240 JupyterHub log:189] 200 GET /hub/login?next=%2Fhub%2F (@::ffff:10.8.1.6) 27.24ms
[E 2021-12-11 12:53:47.996 JupyterHub web:1789] Uncaught exception POST /hub/login?next=%2Fhub%2F (::ffff:10.8.1.6)
    HTTPServerRequest(protocol='http', host='hoge:8000', method='POST', uri='/hub/login?next=%2Fhub%2F', version='HTTP/1.1', remote_ip='::ffff:10.8.1.6')
    Traceback (most recent call last):
      File "/usr/local/lib/python3.8/dist-packages/tornado/web.py", line 1704, in _execute
        result = await result
      File "/usr/local/lib/python3.8/dist-packages/jupyterhub/handlers/login.py", line 151, in post
        user = await self.login_user(data)
      File "/usr/local/lib/python3.8/dist-packages/jupyterhub/handlers/base.py", line 788, in login_user
        authenticated = await self.authenticate(data)
      File "/usr/local/lib/python3.8/dist-packages/jupyterhub/auth.py", line 473, in get_authenticated_user
        authenticated = await maybe_future(self.authenticate(handler, data))
      File "/usr/local/lib/python3.8/dist-packages/ldapauthenticator/ldapauthenticator.py", line 382, in authenticate
        conn = self.get_connection(userdn, password)
      File "/usr/local/lib/python3.8/dist-packages/ldapauthenticator/ldapauthenticator.py", line 314, in get_connection
        conn = ldap3.Connection(
      File "/usr/local/lib/python3.8/dist-packages/ldap3/core/connection.py", line 363, in __init__
        self._do_auto_bind()
      File "/usr/local/lib/python3.8/dist-packages/ldap3/core/connection.py", line 391, in _do_auto_bind
        if self.start_tls(read_server_info=False):
      File "/usr/local/lib/python3.8/dist-packages/ldap3/core/connection.py", line 1314, in start_tls
        if self.server.tls.start_tls(self) and self.strategy.sync:  # for asynchronous connections _start_tls is run by the strategy
      File "/usr/local/lib/python3.8/dist-packages/ldap3/core/tls.py", line 277, in start_tls
        raise LDAPStartTLSError(connection.last_error)
    ldap3.core.exceptions.LDAPStartTLSError: startTLS failed - protocolError
    
[E 2021-12-11 12:53:48.018 JupyterHub log:181] {
      "X-Forwarded-Host": "hoge:8000",
      "X-Forwarded-Proto": "http",
      "X-Forwarded-Port": "8000",
      "X-Forwarded-For": "::ffff:10.8.1.6",
      "Accept-Language": "en-US,en;q=0.9,ja;q=0.8",
      "Accept-Encoding": "gzip, deflate",
      "Referer": "http://hoge:8000/hub/login?next=%2Fhub%2F",
      "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
      "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36",
      "Content-Type": "application/x-www-form-urlencoded",
      "Origin": "http://hoge:8000",
      "Upgrade-Insecure-Requests": "1",
      "Cache-Control": "max-age=0",
      "Content-Length": "34",
      "Connection": "close",
      "Host": "hoge:8000"
    }
[E 2021-12-11 12:53:48.018 JupyterHub log:189] 500 POST /hub/login?next=%2Fhub%2F (@::ffff:10.8.1.6) 23.50ms
12:53:56.029 [ConfigProxy] info: 200 GET /api/routes 

Jupyterhub は Docker image として構築していて,Jupyterhub (+ LDAP auth) 関連の Docierfile 該当部は以下.

RUN pip install jupyterhub
RUN pip install jupyterhub-ldapauthenticator
RUN npm install -g configurable-http-proxy

あとは,起動時に

jupyterhub --config=/etc/jupyterhub_config.py

が呼ばれるようになっていて,jupyterhub_config.py は以下のようなもの.

c.JupyterHub.authenticator_class = "ldapauthenticator.LDAPAuthenticator"
c.LDAPAuthenticator.server_address = "10.0.0.1"
c.LDAPAuthenticator.server_port = 389
c.LDAPAuthenticator.bind_dn_template = "uid={username},ou=People,dc=example,dc=com"
c.LDAPAuthenticator.use_ssl = False
c.JupyterHub.hub_ip = '0.0.0.0'
c.Authenticator.admin_users = {'myn'}

LDAP には SSL 使っていない(ローカル環境なので)のに startTLS しようとしているように見える.たぶん /usr/local/lib/python3.8/dist-packages/ldapauthenticator/ldapauthenticator.pyの以下の箇所がおかしいような気がしていて,

    def get_connection(self, userdn, password):
        server = ldap3.Server(
            self.server_address, port=self.server_port, use_ssl=self.use_ssl
        )
        auto_bind = (
            ldap3.AUTO_BIND_NO_TLS if self.use_ssl else ldap3.AUTO_BIND_TLS_BEFORE_BIND
        )
        conn = ldap3.Connection(
            server, user=userdn, password=password, auto_bind=auto_bind
        )
        return conn

ここの箇所で以下の修正をするとうまく動いてくれる.

-    ldap3.AUTO_BIND_NO_TLS if self.use_ssl else ldap3.AUTO_BIND_TLS_BEFORE_BIND
+    ldap3.AUTO_BIND_NO_TLS if not self.use_ssl else ldap3.AUTO_BIND_TLS_BEFORE_BIND

Dockerfile 的には以下を書いている.

RUN sed -i 's/ldap3\.AUTO_BIND_NO_TLS if self\.use_ssl/ldap3.AUTO_BIND_NO_TLS if not self.use_ssl/g' /usr/local/lib/python3.*/dist-packages/ldapauthenticator/ldapauthenticator.py

Related articles