[This is obsolete. My improved code is now in Github.]
[The technique in this article supersedes my earlier “How I remember my YubiKey, take two” how-to; I explain at the bottom of this article what was wrong with my earlier technique and why this new technique is better.]
I’ve recently started using a YubiKey NEO for two-factor authentication for sites that support it.1
Because I am using my YubiKey for more and more sites, I tend to leave it plugged in whenever I am in front of a computer for an extended period of time. The first day I was using the key it became clear that this was going to be a problem, when I left it plugged into my computer at work and didn’t realize it until I’d gotten home. Yes, new technology leads to new problems, but problems that are created by technology can be solved by technology too. Here’s how I solved the “Don’t forget your YubiKey at work” problem.2
In a nutshell, I am generating push notifications from my computer to my phone every time I plug in or unplug my YubiKey, reading those notifications in the Android Tasker app to to track whether it’s plugged in, and using Tasker to alert me if I walk away from my computer when it is. I explain in detail below how each of these pieces works.
Set up push notifications from my computer to my phone
I registered for an IFTTT account and installed the IFTTT Android app so that I can generate push notifications from IFTTT to my phone.
On the IFTTT web site, I set up a new applet as follows:
- For “this”, select “Webhooks” and then “Receive a web request”.
- Enter “yubikey_plugged_in” as the event name.
- For “that”, select “Notifications” and then “Send a notification from the IFTTT app”.
- For the message, enter “YubiKey is plugged in”.
Then I repeated the above steps but this time I used “yubikey_unplugged” as the event name and “YubiKey is not plugged in” as the message.
Next, I went to https://ifttt.com/services/maker_webhooks/settings and copied down my Maker key, which is the last component of the URL shown on that page, and saved it in the file /root/.ifttt_maker_key.
Finally, I tested:
curl https://maker.ifttt.com/trigger/yubikey_plugged_in/with/key/$(sudo cat /root/.ifttt_maker_key) curl https://maker.ifttt.com/trigger/yubikey_unplugged/with/key/$(sudo cat /root/.ifttt_maker_key)
Once I followed the steps above properly, the two curl
commands above generated two notifications on my phone, one of which said “YubiKey is plugged in” and the other “YubiKey is not plugged in”.
Set up my computer to notify my phone whenever my YubiKey is plugged in or unplugged
This has four pieces:
- a shell script that does the notifying;
- a
systemd
service that invokes the shell script; - a
udev
rule that triggers the service; and - a
systemd
timer that also triggers the service once per minute, just in case theudev
rule doesn’t work.
The shell script
This is installed as /usr/local/bin/yubikey-monitor.sh
:
#!/bin/bash -e export HOME=$(eval echo "~$(whoami)") FLAG=/var/run/yubikey-watcher MIN_NOTIF_GAP=30 # seconds KEY_FILE=/root/.ifttt_maker_key trap "rm -f \"$FLAG.lock\"" EXIT lockfile -1 -l 15 "$FLAG.lock" check_yubikey() { usb-devices 2>/dev/null | grep -q -s -i -w yubikey } next_state() { if [ "$ACTION" = "add" ]; then if [ "$STATE" = "just-plugged" -o "$STATE" = "plugged" ]; then echo "plugged" else echo "just-plugged" fi elif [ "$STATE" = "just-unplugged" -o "$STATE" = "unplugged" ]; then echo "unplugged" else echo "just-unplugged" fi } notify_message() { if [ "$ACTION" = "add" ]; then echo "yubikey_plugged_in" else echo "yubikey_unplugged" fi } doit() { if check_yubikey; then ACTION="add" else ACTION="remove" fi set $(cat $FLAG 2>/dev/null || : ) if [ "$1" ]; then STATE=$1; shift if [ "$1" ]; then LAST_TIME=$1; shift fi fi NEXT_STATE=$(next_state) if [ "$NEXT_STATE" = "$STATE" ]; then exit fi if [ "$LAST_TIME" ]; then DELTA=$(($(date +%s) - LAST_TIME)) REMAINING=$((MIN_NOTIF_GAP - DELTA)) if [ $REMAINING -gt 0 ]; then echo Delaying notification for $REMAINING seconds sleep $REMAINING doit return fi fi if ! ifttt_key=$(cat $KEY_FILE); then echo IFTTT Maker key not installed in $KEY_FILE 1>&2 else url=https://maker.ifttt.com/trigger/$(notify_message)/with/key echo $(curl --silent "$url/$ifttt_key") echo Triggered "$url/[key-elided]" fi echo "$NEXT_STATE $(date +%s)" >| $FLAG } doit
The script is written to generate two notifications every time the YubiKey is plugged in or unplugged, just in case one of the notifications gets lost. That’s probably overkill, but shrug.
The systemd
service
This is installed as /etc/systemd/system/yubikey-monitor.service
, after which systemctl daemon-reload
is run to tell systemd
to load it:
[Unit]
Description=Check for inserted Yubikey
StartLimitIntervalSec=0
[Service]
Type=exec
ExecStart=/usr/local/bin/yubikey-monitor.sh
The udev
rule
This is installed as /etc/udev/rules.d/50-yubikey.rules
, after which udevadm control --reload-rules
is run to tell udev
to reread all of its rules.
ATTRS{idVendor}=="1050", ACTION=="add|remove", RUN+="/bin/systemctl start yubikey-monitor.service"
The systemd
timer
This is installed as /etc/systemd/system/yubikey-monitor.timer
, after which systemctl daemon-reload
is run to tell systemd
to load it:
[Unit]
Description=Check for inserted Yubikey every minute
[Timer]
OnStartupSec=60
OnUnitActiveSec=60
[Install]
WantedBy=timers.target
Process the notifications in Tasker
Once you’ve got the computer generating notifications to your phone, you need to configure the phone to process the notifications. I’m using the AutoNotification app, which integrates with Tasker, to do that. Here are the relevant Tasker configs:
Profile: YubiKey Plugged In (37)
Event: AutoNotification Intercept [ Configuration:Event Behaviour: true
Notification Type: Only Created Notifications
Notification App: IFTTT
Notification Text: YubiKey is plugged in ]
Enter: Set YubiKey Variable (34)
Profile: YubiKey Unplugged (38)
Event: AutoNotification Intercept [ Configuration:Event Behaviour: true
Notification Type: Only Created Notifications
Notification App: IFTTT
Notification Text: YubiKey is not plugged in ]
Enter: Clear YubiKey Variable (36)
Exit: Remove YubiKey Reminder (33)
Task: Set YubiKey Variable (34)
A1: Variable Set [ Name:%YUBIKEY To:1 Recurse Variables:Off Do Maths:Off Append:Off ]
A2: AutoNotification Cancel [ Configuration:Other Id: %anid
Package: %anpackage
Tag: %antag Timeout (Seconds):20 ]
Task: Clear YubiKey Variable (36)
A1: Variable Clear [ Name:%YUBIKEY Pattern Matching:Off Local Variables Only:Off ]
A2: AutoNotification Cancel [ Configuration:Other Id: %anid
Package: %anpackage
Tag: %antag Timeout (Seconds):20 ]
Task: Remove YubiKey Reminder (33)
A1: Notify Cancel [ Title:Don't Forget Your YubiKey Warn Not Exist:Off ]
Notify me when I walk away from my computer
Finally, these additional Tasker configs generate a notification (which goes to my Fitbit) and a silent vibration when I walk ten steps away from my computer, or a really loud alert when I walk fifty steps away:
Profile: YubiKey Soft Reminder (39)
Event: Steps Taken [ Number:10 ]
State: Variable Value [ %YUBIKEY ~ 1 ]
Enter: Quiet YubiKey Reminder (30)
Profile: YubiKey Loud Reminder (41)
Event: Steps Taken [ Number:50 ]
State: Variable Value [ %YUBIKEY ~ 2 ]
Enter: Loud YubiKey Reminder (40)
Task: Quiet YubiKey Reminder (30)
Run Both Together
A1: Notify [ Title:Don't Forget Your YubiKey Text:Don't Forget Your YubiKey Icon:null Number:0 Permanent:Off Priority:5 ]
A2: Vibrate Pattern [ Pattern:0,1000,250,1000,250,1000 ]
A3: Variable Set [ Name:%YUBIKEY To:2 Recurse Variables:Off Do Maths:Off Append:Off ]
Task: Loud YubiKey Reminder (40)
Run Both Together
A1: Morse [ Text:oo Frequency:4000 Speed:80 Amplitude:50 Stream:4 ]
A2: Variable Set [ Name:%YUBIKEY To:3 Recurse Variables:Off Do Maths:Off Append:Off ]
Conclusion
So, there you have it. My phone is now alerting me whenever I walk away from my computer and leave my YubiKey behind, first quietly and then loudly if I don’t pay attention, You can do it too, assuming that you’re as ridiculously obsessive about stuff like this as I am and willing to take the time to set it up.
Please email me or comment if you found this useful!
P.S. Don’t forget to back up your Tasker configuration (“Data” -> “Backup” from the home screen menu) and save the backup file somewhere off your phone, so you don’t have to rebuild everything if you lose or break it!
P.P.S. My first attempt at solving this problem involved having Tasker alert me if I strayed so far from my computer that it was no longer visible to my phone via Bluetooth. This proved to be quite unreliable; I was unable to get Tasker to reliably detect a nearby Bluetooth device, causing both false positives (i.e., my phone alerting me when I was still standing at my desk) and false negatives (i.e., my phone failing to alert me when I walked away from my desk without my YubiKey). The notification-based solution described here appears, at least so, far to be much more reliable.
P.P.P.S. My second attempt at solving this problem, which more closely resembled this one, worked fine until the Notify app and disappeared from the app store and the NodeJS notify
command-line interface stopped working, or more accurately, it said it was sending notifications but my phone never received them. Other people were having the same problem, so I decided to switch to using IFTTT. Also, in addition to modifying yubikey-monitor.sh
to use IFTTT instead of Notify, I’ve refactored it in some other ways to make it more robust.
1A quick primer, for those of you who are unfamiliar… The YubiKey sends two-factor authentication information to web sites when I either tap the button on the key, when it is plugged into my computer, or tap it on my phone’s NFC sensor, if I’m logging into somewhere on my phone. Furthermore, for sites that support Universal 2nd Factor (U2F) authentication, the YubiKey adds an additional layer of security, confirming the identity of the web site I’m logging into to ensure that I’m not being phished.
2If someone else has already solved this problem and I’m a fool to have wasted my time on it ;-), please feel free to let me know in a comment below. I’m always happy to throw away my own hacks and use somebody else’s instead, if it means one less hack for me to have to maintain.
Pingback: How I remember my YubiKey, take four – Something better to do
Note: I’ve just made two minor improvements to the shell script above; the new, improved version is the one currently embedded in the article.
1) I’ve adjusted the logic so that if you plug in or unplug your YubiKey while the script is running but delaying its notification, then it’ll re-check the status of the YubiKey after the delay but before sending the notification, so that it won’t accidentally send the wrong notification.
2) I’ve increased the minimum gap between the first and second (backup, redundant) notification from 15 seconds to 30 seconds, because it appears that sometimes 15 seconds isn’t enough for the notification to work its way through channels and make it to the phone.
X
Pingback: How I remember my YubiKey, take two – Something better to do