Skip to content

Instantly share code, notes, and snippets.

@delannoy
Last active August 18, 2025 09:59
Show Gist options
  • Select an option

  • Save delannoy/9512a180dea2a3436b13d860bcaf4296 to your computer and use it in GitHub Desktop.

Select an option

Save delannoy/9512a180dea2a3436b13d860bcaf4296 to your computer and use it in GitHub Desktop.
Setup for CERN lxplus keytab file (creates kerberos tokens for password-less SSH access)
#!/usr/bin/env bash
# References:
# [https://linux.web.cern.ch/docs/kerberos-access/]
# [https://twiki.cern.ch/twiki/bin/view/Main/Kerberos]
# [https://uz.sns.it/~enrico/site/posts/kerberos/password-less-ssh-login-with-kerberos.html]
# Requirements:
# [MIT Kerberos V5. Kerberos is a network authentication protocol.](https://github.com/krb5/krb5)
# Kerberos is usually installed in most systems (run `command -v kinit` to verify)
# [k5start and krenew are modified versions of kinit which add support for running as a daemon](https://github.com/rra/kstart)
# kstart will most probably need to be installed (e.g. `command -v k5start || sudo apt install kstart`)
# [If you have MacOS Sierra or later, it comes with an updated version of OpenSSH that drops some options that support Kerberos authentication [...] The best way to obtain an SSH binary with GSSAPITrustDNS support is using Homebrew](https://frankenthal.dev/post/ssh_kerberos_keytabs_macos/)
export XDG_DATA_HOME="${XDG_DATA_HOME:-${HOME}/.local/share}" # [XDG Base Directory Specification](https://specifications.freedesktop.org/basedir-spec/latest/#variables)
export KRB5_CONFIG="${XDG_DATA_HOME}/krb5/conf" # [Main Kerberos configuration file.](https://web.mit.edu/kerberos/krb5-1.12/doc/admin/env_variables.html#environment-variables)
export KRB5_KTNAME="${XDG_DATA_HOME}/krb5/keytab" # [Default keytab file name.](https://web.mit.edu/kerberos/krb5-1.12/doc/admin/env_variables.html#environment-variables)
krb5_principal(){
# based on user input, define $KRB5_PRINCIPAL as an environment variable
local principal="$1"
local user="${principal%@*}"
local realm="${principal#*@}"
export KRB5_PRINCIPAL="${user,,}@${realm^^}"
}
krb5_config(){
# unless it already exists, download a Kerberos configuration file for lxplus
[[ -f "${KRB5_CONFIG}" ]] && return 0
local url='https://linux.web.cern.ch/docs/krb5.conf'
mkdir --parents "${KRB5_CONFIG%/*}"
curl --progress-bar --create-dirs --location --url "${url}" --output "${KRB5_CONFIG}" --write-out '%{filename_effective}\n'
}
krb5_keytab(){
# unless a keytab file exists containing a key corresponding to $KRB5_PRINCIPAL, ssh into lxplus and execute `cern-get-keytab` to create a keytab file and transfer it to local machine via `scp`
(( "$(klist -k "${KRB5_KTNAME}" 2>/dev/null | grep --ignore-case --count "${KRB5_PRINCIPAL}")" > 0 )) && return 0
local user="${KRB5_PRINCIPAL%@*}"
ssh "${user}@lxplus.cern.ch" '/usr/sbin/cern-get-keytab --user --keytab ~/private/keytab || echo "error creating keytab file!"' # [https://gitlab.cern.ch/linuxsupport/rpms/cern-get-keytab]
scp "${user}@lxplus.cern.ch:~/private/keytab" "${KRB5_KTNAME}"
krb5_kinit(){
# unless $KRB5_KTNAME doesn't exist, list the keys in the keytab file (`klist -k`), obtain and cache Kerberos ticket (`kinit`), and list cached Kerberos tickets (`klist -c`)
[[ -f "${KRB5_KTNAME}" ]] || return 1
klist -k -t -e -K "${KRB5_KTNAME}"
kinit -f -p -k -t "${KRB5_KTNAME}" "${KRB5_PRINCIPAL}"
klist -c -e -f
}
krb5_daemon(){
# unless already running, run `k5start` in the background to check (every 60 minutes) for an active kerberod tivcket and renew it if needed
command -v k5start || return 1
(( "$(pgrep --list-full k5start | grep --ignore-case --count "${KRB5_PRINCIPAL}")" > 0 )) && return 0
k5start -v -b -K 60 -u "${KRB5_PRINCIPAL}" -f "${KRB5_KTNAME}"
}
krb5(){
krb5_principal "$1"
krb5_config
krb5_keytab
krb5_kinit
krb5_daemon
}
# Modify or update your "${HOME}/.ssh/config" as below, change <CERNUSERNAME> and <CMSUSERNAME> to your username, and execute the `krb5` function, and enjoy password-less ssh access to lxplus!
krb5 <CERNUSERNAME>@cern.ch
ssh lxplus
# This example ssh config simplifies ssh tunneling through lxplus (when needed) to reach machines within the CMS network. For example:
# ssh cmsusr ssh -tCXY brildev1 'xsudo --user=brilpro --login'
Host lxplus
User <CERNUSERNAME>
Hostname lxplus.cern.ch
GSSAPIAuthentication yes
GSSAPIDelegateCredentials yes
ForwardX11 yes
RequestTTY yes
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
# [Tunneling an SSH connection only when necessary using Match](https://mike.place/2017/ssh-match)
# The `Match` statement below will tunnel through lxplus only when needed (if cmsusr.cern.ch is not directly accessible). Requires OpenSSH version > 7.2.
Match host cmsusr !exec "ping -c1 -W1 cmsusr.cern.ch &>/dev/null"
ProxyJump lxplus
Host cmsusr
User <CMSUSERNAME>
Hostname cmsusr.cern.ch
ForwardX11 yes
RequestTTY force
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
Host cmstunnel
User <CMSUSERNAME>
Hostname cmsusr.cern.ch
DynamicForward 10880
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment