Authenticators:
hub:
config:
authenticator_class #this defined which of the authenticators the hub will use
Basic LDAP
hub:
revisionHistoryLimit:
config:
JupyterHub:
admin_access: true
authenticator_class: ldapauthenticator.LDAPAuthenticator
## Ref: https://github.com/jupyterhub/ldapauthenticator
LDAPAuthenticator:
# LDAPS conn info
server_address: SET_IN_CLI # IP or FQDN only, no ldap(s)://
server_port: 636
use_ssl: true
## Account look up settings
valid_username_regex: ^[A-Za-z]*.[A-Za-z]*$ #good base for username characters
bind_dn_template:
- uid={username},cn=users,dc=acme,dc=com #this is what jhub will use to make the query to ldap for the user info
lookup_dn: true #keeping this true for AD, sounds iffy for openldap or ipa
lookup_dn_search_filter: ({login_attr}={login})
user_search_base: cn=users,dc=acme,dc=com #base search dn to find users
allowed_groups: #full DN group info to allow access a lsit of strings
- "cn=grp-jhub-user,cn=groups,dc=acme,dc=com"
- "cn=grp-jhub-admin,cn=groups,dc=acme,dc=com"
admin_groups:
- "cn=grp-jhub-admin,cn=groups,dc=acme,dc=com" #similar to allowed_groups, but not exact - obviously
user_attribute: uid #the user's uid (for openldap and ipa), of sAM-thing in AD
# Bind account info
lookup_dn_search_user: SET_IN_CLI #LDAP_BIND_UID #when using the lookup_dn, some ldaps don't like anonymous binds
lookup_dn_search_password: SET_IN_CLI #LDAP_BIND_PASSWD #when using the lookup_dn, some ldaps don't like anonymous binds
lookup_dn_user_dn_attribute: uid
Working LDAP:
hub:
revisionHistoryLimit:
config:
JupyterHub:
admin_access: true
authenticator_class: ldapauthenticator.LDAPAuthenticator
## Ref: https://github.com/jupyterhub/ldapauthenticator
LDAPAuthenticator:
# LDAPS conn info
server_address: SET_IN_CLI
server_port: 636
use_ssl: true
lookup_dn: false
bind_dn_template:
- "uid={username},cn=users,dc=acme,dc=com"
allowed_groups:
- "cn=grp-jhub-user,cn=groups,dc=acme,dc=com"
- "cn=grp-jhub-admin,cn=groups,dc=acme,dc=com"
admin_groups:
- "cn=grp-jhub-admin,cn=groups,dc=acme,dc=com"
auth_state_attributes:
- uid
- memberOf
- loginShell
- uidNumber
lookup_dn_search_user: SET_IN_CLI #just the username, not the dn - because it's specified above
lookup_dn_search_password: SET_IN_CLI
OAuth - in this case Keycloak
hub:
revisionHistoryLimit:
config:
JupyterHub:
admin_access: true
authenticator_class: generic-oauth
GenericOAuthenticator:
client_id: JHub #generated by the admins as client creation
client_secret: SET_IN_CLI #OAUTH_SECRET this is generated within keycloak and the admins have to retrieve it
oauth_callback_url: https://jhub.LAB_DOMAIN/hub/oauth_callback
authorize_url: https://OAUTH_SERVER_FQDN/auth/realms/{REALM}/protocol/openid-connect/auth
token_url: https://OAUTH_SERVER_FQDN/auth/realms/{REALM}/protocol/openid-connect/token
userdata_url: https://OAUTH_SERVER_FQDN/auth/realms/{REALM}/protocol/openid-connect/userinfo
login_service: keycloak #whatever string you want the login button to have "Sign in with ...."
manage_groups: true #this allows for the groups in the token to be used by jhub
username_key: preferred_username #this value is dependent on the OAuth provider, for keycloak the username is preferred_username
userdata_params:
state: state
allowed_groups:
- grp-jhub-user
- grp-jhub-admin
admin_groups:
- grp-jhub-admin
Notes about OAuth
- this is using the generic OAuth for jhub, if can be extended, but I have modified my keycloak to provide things:
- My client for jhub provides groups as a default scope
- My groups are based on an LDAP-based backend (pulls them into the realm and serves them out to the client auth)
I found that when using some backend for authentication, I would receive from the single user image terminal about not being able to resolve UID and GID of the user. It made sense to enable this for users, mainly to lessen confusion, but to also enable better user management for shared storage and such.
My working solution is to utilize a custom image which is based on a Rocky 8 image with sssd that will connect to the LDAP backend, and store the user/group info in a way that can be shared across the other pods. The implementation in this case is to use a daemonset to have this image running on all nodes, and also use a hostPath for the /var/lib/sss dorectory; which can then be mounted on the single user images for use. I also had to modify my single user images so they contained the sssd packages necessary to look at the sssd data.
The changes to this repo for this is as follows:
# For demonstration purposes I have included sssd_container.yml to show the mounts on the sssd image.
# In rocky_profiles.py added the following:
medium_instance = {
...
"volumes": [
...
{
"name": "var-lib-sss",
"hostPath": {
"path": "/tmp/sss",
"type": "DirectoryOrCreate"
}
}
],
"volume_mounts": [
...
{
"name": "var-lib-sss",
"mountPath": "/var/lib/sss"
}
]
}
...
}
For information on what i did in the single user image, being based on ubuntu, i added the line below to the Dockerfile:
RUN apt-get update && apt-get install -y sssd libpam-sss libnss-sss sssd-tools