Update:
This method of locking a user workstation with Yubikeys is now available for Gnome3, KDE, LXDE, Cinnamon and XFCE.
I, like many others use Linux as my main Operating System, both at home and in the enterprise. Token based authentication is also a very strong topic for many organisations for two factor authentication (password + one time password = successful login).
My preferred token of choice is the Yubikey from Yubico.
Questions have been floating around recently of “How do I lock my linux desktop when I unplug my Yubikey?”. I have been trying to achieve this for a few weeks now and despite coming across a fantastic article (http://wiki.d3xt3r01.tk/index.php/YubiKey_lock_screen), I never managed to get it to work in Fedora 18.
I’d like to just say here, that this is not my original work. Thank you very much to the author of the above link for their contribution to the community as it has helped many people to achieve this goal.
A special thanks to Lennart Poettering for pointing me in the right direction to get this working as well. Thanks very much.
Unfortunately for Gnome3 / Fedora 18 users, some changes needed to be made to the original method.
Below I will be walking you through setting up your Fedora 18 system running the Gnome3 desktop, to lock and unlock with your Yubikey.
(This will be based on the above article, however I have made a few changes to get things working for Fedora 18.)
Here is a short Youtube video of the final result.
http://ww
Step 1: Create a new udev rule.
Udev is used to map hardware to your system. We can tap into udev and ask it to do funky things for us, which is exactly what we need to do here.
Create a file called /etc/udev/rules.d/85-yubikey-screen-lock.rules with the below contents:
[root@localhost ~]# vi /etc/udev/rules.d/85-yubikey-screen-lock.rules SUBSYSTEM=="usb", ACTION=="remove", ENV{ID_VENDOR_ID}=="1050", ENV{ID_MODEL_ID}="0010", RUN+="/usr/local/bin/yubikey-screen-lock enable" SUBSYSTEM=="usb", ACTION=="add", ENV{ID_VENDOR_ID}=="1050", ENV{ID_MODEL_ID}=="0010", RUN+="/usr/local/bin/yubikey-screen-lock disable"
Step 2. Create the yubikey-screen-lock
Create a file called /usr/local/bin/yubikey-screen-lock with the below contents:
[root@localhost ~]# vi /usr/local/bin/yubikey-screen-lock #!/bin/bash log="/var/log/yubilock.log" yubimap="/etc/sysconfig/yubikeys" user=`ps aux | grep -v root | grep session | head -n 1 | awk '{print $1}'` check_gnome=$(ps -aux | awk '{print $11}' | grep ^gnome-session) if [[ -n $check_gnome ]] then DESKTOP=gnome sessionid=`/bin/loginctl list-sessions | grep ${user} | awk '{print $1}'` fi check_cinnamon=$(ps -aux | awk '{print $11}' | grep ^cinnamon-session) if [[ -n $check_cinnamon ]] then DESKTOP=cinnamon fi check_lxde=$(ps -aux | awk '{print $11}' | grep lxsession) if [[ -n $check_lxde ]] then DESKTOP=lxde fi check_xfce=$(ps -aux | awk '{print $11}' | grep ^xfce4-session) if [[ -n $check_xfce ]] then DESKTOP=xfce fi check_kde=$(ps -aux | awk '{print $11}' | grep kded4) if [[ -n $check_kde ]] then DESKTOP=kde fi echo "$(date) $(whoami) '$0' '$1' | Desktop Environment = '$DESKTOP'" >> ${log} case "$1" in enable) if [ -n ${user} -a "$(grep -c ${user}:000$(ykinfo -q -s) ${yubimap})" == "1" ] then case $DESKTOP in gnome) /bin/loginctl lock-session $sessionid ;; cinnamon) /bin/su ${user} -c "DISPLAY=:0 /usr/bin/cinnamon-screensaver-command -a" ;; lxde) /bin/su ${user} -c "DISPLAY=:0 /usr/bin/xscreensaver-command -activate" ;; xfce) /bin/su ${user} -c "DISPLAY=:0 /usr/bin/xflock4" ;; kde) /bin/su ${user} -c "DISPLAY=:0 /usr/bin/xscreensaver-command -activate" ;; esac fi ;; disable) if [ -n ${user} -a "$(grep -c ${user}:000$(ykinfo -q -s) ${yubimap})" == "1" ] then case $DESKTOP in gnome) /bin/loginctl unlock-session $sessionid ;; cinnamon) /bin/su ${user} -c "DISPLAY=:0 /usr/bin/cinnamon-screensaver-command -d" ;; lxde) /bin/su ${user} -c "DISPLAY=:0 /usr/bin/xscreensaver-command -deactivate" ;; xfce) /bin/su ${user} -c "DISPLAY=:0 /usr/bin/xscreensaver-command -deactivate" ;; kde) /bin/su ${user} -c "DISPLAY=:0 /usr/bin/xscreensaver-command -deactivate" ;; esac fi ;; esac
Step 3. Ensure yubikey-screen-lock can be executed
Here we need to change the permissions of the /usr/local/bin/yubikey-screen-lock script to allow it to execute like any other normal command.
Please do the following:
[root@localhost ~]# chmod 755 /usr/local/bin/yubikey-screen-lock
Step 4. Add username and yubikey token to authorised file
We need to create a user maps file which has a list of which Yubikeys can unlock which user’s sessions. We need to do this to stop user Jim, from unlocking user Bob’s session.
Firstly, insert a single Yubikey into your system and on your terminal, run “ykinfo -q -s”. This will give you the output of your key serial number.
For example:
This is one of my test keys.
[root@localhost ~]# ykinfo -q -s 283749
Now we need to take this number, and add it to our user maps file. Here the syntax is <username>:000<serial number>
For example:
Here my username is mac and my serial number is 283749, so my user maps file looks as follows.
[root@localhost ~]# cat /etc/sysconfig/yubikeys mac:000283749 [root@localhost ~]#
Step 5. Reload udev
As we have just added a new rule, we need to apply it so udev knows to action it.
To reload udev in Feodra 18, run the following.
[root@localhost ~]# udevadm control --reload-rules
Step 6. Test
It is important to test your configuration. If you are making these chances and are already logged into Gnome3 as the user you have set up, simply by removing your Yubikey will activate the lock screen.
If you reinsert your key, it will take you back to your existing session.
Please note:
One of the big reasons Two factor authentication is seen as so critical is because it forces a user to require both a password AND a key or token to log back into your session.
If you are planning to do this in the enterprise, I highly recommend that you do not unlock your sessions with your Yubikey tokens.
If you use systems in a kerberised environment (for example Microsoft Active Directory or FreeIPA), unlocking your user session will not acquire a valid authentication ticket (TGT). If you don’t acquire a ticket, you won’t be able to access several resources that would normally be required.
My recommendation here is, only use this in the enterprise to lock your sessions.
To achieve this, change your udev rule from:
[root@localhost ~]# vi /etc/udev/rules.d/85-yubikey-screen-lock.rules SUBSYSTEM=="usb", ACTION=="remove", ENV{ID_VENDOR_ID}=="1050", ENV{ID_MODEL_ID}="0010", RUN+="/usr/local/bin/yubikey-screen-lock enable" SUBSYSTEM=="usb", ACTION=="add", ENV{ID_VENDOR_ID}=="1050", ENV{ID_MODEL_ID}=="0010", RUN+="/usr/local/bin/yubikey-screen-lock disable"
to
[root@localhost ~]# vi /etc/udev/rules.d/85-yubikey-screen-lock.rules SUBSYSTEM=="usb", ACTION=="remove", ENV{ID_VENDOR_ID}=="1050", ENV{ID_MODEL_ID}="0010", RUN+="/usr/local/bin/yubikey-screen-lock enable" #SUBSYSTEM=="usb", ACTION=="add", ENV{ID_VENDOR_ID}=="1050", ENV{ID_MODEL_ID}=="0010", RUN+="/usr/local/bin/yubikey-screen-lock disable"
Don’t forget to reload your rules after you make this change.
[root@localhost ~]# udevadm control --reload-rules
Troubleshooting
If you are having problems with your new udev rule, perhaps you have hit a problem with SELinux if you use it in enforcing mode.
Firstly, verify if SELinux is causing a problem.
You can do this by setting SELinux to permissive mode whilst you troubleshoot. To do this, run the following
[root@localhost ~]# setenforce 0
Now insert and remove your yubikey. If your GNOME3 session now locks and unlocks with no problems then chances are you are affected by the same problem I had.
When I tailed my /var/log/audit/audit.log file, I found the following kept appearing when I inserted my key.
type=USER_AVC msg=audit(1358202964.902:412): pid=563 uid=81 auid=4294967295 ses=4294967295 subj=system_u:system_r:system_dbusd_t:s0-s0:c0.c1023 msg='avc: denied { send_msg } for msgtype=method_return dest=:1.106 spid=548 tpid=2305 scontext=system_u:system_r:systemd_logind_t:s0 tcontext=system_u:system_r:udev_t:s0-s0:c0.c1023 tclass=dbus exe="/usr/bin/dbus-daemon" sauid=81 hostname=? addr=? terminal=?'
What I did to resolve the issue was,
Save the above output to a text file. I called mine selinux.txt
I then cat’d the file and passed it to ‘audit2allow’ which is a tool you can use to create your own SELinux policies.
[root@localhost ~]# cat selinux.txt | audit2allow -M yubikey_session_lock ******************** IMPORTANT *********************** To make this policy package active, execute: semodule -i yubikey_session_lock.pp [root@localhost ~]#
Next you should install your new policy with the following.
[root@localhost ~]# semodule -i yubikey_session_lock.pp
Next, just reenable SELinux and try testing your keys again.
Turn SELinux back to Enforcing mode with the following.
[root@localhost ~]# setenforce 1
I came across this script since I was looking to lock / unlock a gnome 3 session under fedora 18 using a yubikey. Seems ideal 🙂 However, it appears that the script has commented out the checks to see which yubikey has been inserted, so basically it will lock / unlock a session if any yubikey is removed / inserted (which isnt quite what I want, although no-one else should be using my laptop it would be safer to make sure). Is there any reason for the checks to be commented out?
Hi James
Thanks for pointing that out. I have just removed the #’s in the script. If you remove the #’s as well it will validate the key to user match in the mappings file.
Looks like I had them left over from when I was testing the raw functionality with udev.
Thanks again for noticing.
Dale
Hi, is this possible to do with KDE?
Hi Wayne
I have just added support for new Desktop Environments, which includes support for KDE.
I have tested this on Fedora 19/20 so please feel free to give it a go.
Dale
Just implemented this on ubuntu 14.04 with gnome (unity), had to implement 2 small changes:
1. /etc/sysconfig does not exist on ubunty (step 4 in your manual). I just placed the yubimap directly in /etc. Also I changed privileges to 600 on the yubimap file (for security)
2. /bin/loginctl list-sessions can return multiple rows. This causes the script to stop working. Therefore I setup lock and unlock in a loop:
for sessionid in `/bin/loginctl list-sessions | grep ${user} | awk ‘{print $1}’`
do
/bin/loginctl lock-session $sessionid
done
Hope this helps.
Thanks for the writeup, i simplified the lock script:
#!/bin/bash
log="/var/log/yubilock.log"
yubimap="/etc/yubikeys"
user=`ps aux | grep -v root | grep session | head -n 1 | awk '{print $1}'`
sessionid=`/bin/loginctl list-sessions | grep ${user} | awk '{print $1}'`
echo "$(date) $(whoami) '$0' '$1' | Desktop Environment = '$DESKTOP'" >> ${log}
/bin/loginctl lock-session $sessionid
and the udev rule (since fedora 20 works well with yubikey):
SUBSYSTEM=="usb", ACTION=="remove", ENV{ID_VENDOR_ID}=="1050", ENV{ID_MODEL_ID}="0010", RUN+="/usr/local/bin/yubilock"
This is mostly working for me on Fedora 20 w/ Gnome. However, if I insert a second yubikey (with different serial # and unmapped in user maps) and remove it, it also locks the screen. For whatever reason, it doesn’t seem to be respecting the user map file and is just seeing a yubikey and locking on removal. This happens with and without SELinux. Any ideas?
Fixed. I realized that my yubikey Serial Number is 1234567 whereas your example was 123456 so in my case (and anyone else with a larger yubikey SN) the syntax would be
:00
Working flawlessly now.
Oops, delete my ‘fix’. it worked until a reboot and now it doesn’t work at all. Sorry 🙂
A couple of extra tweaks I have added to the script are:
pkill -u ${user} -SIGHUP gpg-agent
if which sudo >/dev/null ; then sudo -H -u ${user} sudo -K ; fi
The first line tells gpg-agent (which I use with my yubikey to mange ssh keys) to drop it’s password cache
The second line tells sudo to drop my credentials cache.
The net effect is to drop all my password caches as I leave my workstation.
I’m playing around with this and its pretty kewl. I would suggest adding ‘loginctl activate $sessionid’ for those that are playing around with actually allowing this to unlock them
Great post !
I’m using XFCE and I had to replace /bin/su ${user} -c “DISPLAY=:0 /usr/bin/xflock4” with export XDG_SEAT_PATH=”/org/freedesktop/DisplayManager/Seat0″; /usr/bin/dm-tool lock in order to get this working.
Thanks for this post. It helped me a lot. I just had to replace the model id for the Yubikey Neo by ENV{ID_MODEL_ID}=”0116″ and to apply the following patch for Arch Linux with Gnome.