diff --git a/hieradata/roles/apps/jupyter/hub.eyaml b/hieradata/roles/apps/jupyter/hub.eyaml new file mode 100644 index 0000000..6b5a91a --- /dev/null +++ b/hieradata/roles/apps/jupyter/hub.eyaml @@ -0,0 +1 @@ +profiles::jupyter::jupyterhub::ldap_bind_pass: ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAJspN3e2WzA0uZaLgFZ0Ewqii9dY0tTgbirsW70M2VZtLY+s+C6HE8ZZUtpfnRsFwUUhOj7s25X9xVOZNTpZIGPyfx9MWlSyFw2RFuXSEwaydf1DcBbg8261YrTTysA4Jsa1L4DLsX55q+XJUyeUbimVQkIacVIvzTdnZCBKnVNUh3U2PNAmV7SOL2KH8Jpbfs/EQfBt8XuGMCg3I/4RDyoNERqthW6W2KiMX2Gmd8iQ5+W9udH0lEAMx415oyImmN+dEuThcx9FGMi8BWYtnxH96yWafpT5qltwW6EVzIGWuLhiD1LcWYc5RB8jc3DhbeouChpKsN6c4EHoKt3aWsTBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBC8jcnqilJgY1/AnHWHfX4bgDCi2a3Rj43Z0dgfB5HaHdpfked3Cx+u94r2S5+Cg3QogU1AIF04rjzOL+bD2HdaMfo=] diff --git a/hieradata/roles/apps/jupyter/hub.yaml b/hieradata/roles/apps/jupyter/hub.yaml index 24c171e..630fafe 100644 --- a/hieradata/roles/apps/jupyter/hub.yaml +++ b/hieradata/roles/apps/jupyter/hub.yaml @@ -4,8 +4,13 @@ profiles::packages::include: python3.12-pip: {} hiera_include: + - docker - profiles::nginx::simpleproxy +# manage docker +docker::version: latest +docker::curl_ensure: false + # manage a simple nginx reverse proxy profiles::nginx::simpleproxy::nginx_vhost: 'jupyterhub.query.consul' profiles::nginx::simpleproxy::nginx_aliases: @@ -13,10 +18,33 @@ profiles::nginx::simpleproxy::nginx_aliases: - jupyterhub.query.consul - "jupyterhub.service.%{facts.country}-%{facts.region}.consul" +profiles::nginx::simpleproxy::proxy_host: 127.0.0.1 profiles::nginx::simpleproxy::proxy_port: 8000 profiles::nginx::simpleproxy::proxy_path: '/' +profiles::nginx::simpleproxy::use_default_location: false nginx::client_max_body_size: 20M +profiles::nginx::simpleproxy::locations: + # authorised access from external + default: + ensure: 'present' + server: "%{lookup('profiles::nginx::simpleproxy::nginx_vhost')}" + ssl_only: true + location: '/' + proxy: "http://%{lookup('profiles::nginx::simpleproxy::proxy_host')}:%{lookup('profiles::nginx::simpleproxy::proxy_port')}" + proxy_set_header: + - 'Host $host' + - 'X-Real-IP $remote_addr' + - 'X-Forwarded-For $proxy_add_x_forwarded_for' + - 'X-Forwarded-Host $host' + - 'X-Forwarded-Proto $scheme' + - 'Upgrade $http_upgrade' + - 'Connection $http_connection' + - 'X-Scheme $scheme' + proxy_redirect: 'off' + proxy_http_version: '1.1' + proxy_buffering: 'off' + # additional altnames profiles::pki::vault::alt_names: - jupyterhub.service.consul diff --git a/hieradata/roles/infra/auth/glauth.yaml b/hieradata/roles/infra/auth/glauth.yaml index 3348ffb..9e77ecf 100644 --- a/hieradata/roles/infra/auth/glauth.yaml +++ b/hieradata/roles/infra/auth/glauth.yaml @@ -63,7 +63,8 @@ glauth::users: - 20018 - 20023 - 20024 - - 20025 + - 20025 # jupyterhub_admin + - 20026 # jupyterhub_user loginshell: '/bin/bash' homedir: '/home/benvin' passsha256: 'd2434f6b4764ef75d5b7b96a876a32deedbd6aa726a109c3f32e823ca66f604a' @@ -242,6 +243,12 @@ glauth::services: uidnumber: 30009 primarygroup: 20001 passsha256: 'd63b04884d5c7d630b0c06896046065a0926ac5c3d6177ef85320e5fa1be00b9' + svc_jupyterhub: + service_name: 'svc_jupyterhub' + mail: 'jupyterhub@service.main.unkin.net' + uidnumber: 30010 + primarygroup: 20001 + passsha256: '09db1e0c2498214da35f3f2ed46a90a7b90635c207f8725e7abf76b48345a39b' glauth::groups: users: diff --git a/site/profiles/manifests/jupyter/jupyterhub.pp b/site/profiles/manifests/jupyter/jupyterhub.pp index af3bb7f..405c1bd 100644 --- a/site/profiles/manifests/jupyter/jupyterhub.pp +++ b/site/profiles/manifests/jupyter/jupyterhub.pp @@ -3,6 +3,7 @@ class profiles::jupyter::jupyterhub ( Stdlib::AbsolutePath $base_path = '/opt/jupyterhub', Stdlib::AbsolutePath $venv_path = "${base_path}/venv", Stdlib::AbsolutePath $config_path = "${base_path}/config.py", + Stdlib::AbsolutePath $notebook_path = '/home/jupyter/work', Hash $vault_config = {}, String $owner = 'jupyterhub', String $group = 'jupyterhub', @@ -13,11 +14,19 @@ class profiles::jupyter::jupyterhub ( 'dockerspawner', 'jupyterhub-ldapauthenticator', ], - String $ldap_server_address = 'ldap://ldap.service.consul', - String $ldap_bind_dn_template = 'cn={username},ou=people,ou=users,dc=main,dc=unkin,dc=net', - Boolean $ldap_use_ssl = false, - Array $ldap_allowed_groups = ['ou=jupyterhub_user,ou=groups,dc=main,dc=unkin,dc=net'], - Array $ldap_admin_groups = ['ou=jupyterhub_admin,ou=groups,dc=main,dc=unkin,dc=net'], + String $ldap_server_address = 'ldap://ldap.service.consul', + String $ldap_tls_strategy = 'insecure', + Array $ldap_allowed_groups = ['ou=jupyterhub_user,ou=groups,dc=main,dc=unkin,dc=net'], + Array $ldap_admin_users = [], + String $ldap_bind_user = 'cn=svc_jupyterhub,ou=services,ou=users,dc=main,dc=unkin,dc=net', + String $ldap_bind_pass = 'change-me', + String $ldap_user_search_base = 'ou=people,ou=users,dc=main,dc=unkin,dc=net', + String $ldap_user_search_filter = '({login_attr}={login})', + String $ldap_group_search_filter = '(uniqueMember={userdn})', + String $ldap_user_attribute = 'uid', + String $ldap_user_dn_attribute = 'cn', + String $docker_image = 'git.query.consul/unkin/almalinux8-jupyterinstance:latest', + String $docker_network = 'bridge', ){ # ensure nodejs:20 is installed @@ -91,7 +100,7 @@ class profiles::jupyter::jupyterhub ( username => $owner, uid => 1101, gid => 1101, - groups => ['systemd-journal'], + groups => ['systemd-journal', 'docker'], system => true, } @@ -105,11 +114,5 @@ class profiles::jupyter::jupyterhub ( ], } - ## create symbolic link in $PATH - #file { "/usr/local/bin/${script_name}": - # ensure => 'link', - # target => "${base_path}/${script_name}", - # require => File["${base_path}/${script_name}"], - #} } } diff --git a/site/profiles/templates/jupyterhub/config.py.erb b/site/profiles/templates/jupyterhub/config.py.erb index d4f964b..071c87f 100644 --- a/site/profiles/templates/jupyterhub/config.py.erb +++ b/site/profiles/templates/jupyterhub/config.py.erb @@ -9,6 +9,7 @@ c = get_config() c.JupyterHub.bind_url = 'http://:8000' c.JupyterHub.hub_ip = '0.0.0.0' c.JupyterHub.hub_port = 8081 +c.NotebookApp.enable_terminals = True # Configure the DockerSpawner c.JupyterHub.spawner_class = DockerSpawner @@ -16,28 +17,37 @@ c.DockerSpawner.image = '<%= @docker_image %>' c.DockerSpawner.network_name = '<%= @docker_network %>' # Notebook directory and mount location -notebook_dir = '/home/jupyter/work' -c.DockerSpawner.notebook_dir = notebook_dir +c.DockerSpawner.notebook_dir = '<%= @notebook_path %>' # Optional: Volume mapping for user data persistence c.DockerSpawner.volumes = { - 'jupyterhub-user-{username}': notebook_dir + 'jupyterhub-user-{username}': '<%= @notebook_path %>' } # DockerSpawner options c.DockerSpawner.remove = True c.DockerSpawner.debug = True +c.DockerSpawner.pull_policy = "always" # LDAP Authentication c.JupyterHub.authenticator_class = 'ldapauthenticator.LDAPAuthenticator' # LDAP Server settings c.LDAPAuthenticator.server_address = '<%= @ldap_server_address %>' -c.LDAPAuthenticator.bind_dn_template = '<%= @ldap_bind_dn_template %>' -c.LDAPAuthenticator.use_ssl = <%= @ldap_use_ssl ? 'True' : 'False' %> +c.LDAPAuthenticator.tls_strategy = '<%= @ldap_tls_strategy %>' # Restrict access to a specific LDAP group c.LDAPAuthenticator.allowed_groups = <%= @ldap_allowed_groups.to_s %> -# Set an LDAP group as admins -c.LDAPAuthenticator.admin_groups = <%= @ldap_admin_groups.to_s %> +# List LDAP users as admins +c.LDAPAuthenticator.admin_users = <%= @ldap_admin_users.to_s %> + +# Lookup settings +c.LDAPAuthenticator.lookup_dn = True +c.LDAPAuthenticator.lookup_dn_search_filter = '<%= @ldap_user_search_filter %>' +c.LDAPAuthenticator.lookup_dn_search_user = '<%= @ldap_bind_user %>' +c.LDAPAuthenticator.lookup_dn_search_password = '<%= @ldap_bind_pass %>' +c.LDAPAuthenticator.user_search_base = '<%= @ldap_user_search_base %>' +c.LDAPAuthenticator.user_attribute = '<%= @ldap_user_attribute %>' +c.LDAPAuthenticator.lookup_dn_user_dn_attribute = '<%= @ldap_user_dn_attribute %>' +c.LDAPAuthenticator.group_search_filter = '<%= @ldap_group_search_filter %>'