How can I flush my ssh keys on power management activity?

Using ssh-agent and private keys per the usual. Everything's working as normal.

My question regards best practices on flushing keys from ssh-add on activity like sleep, suspend, hibernate, etc. I thought about writing a simple wrapper around those commands, but then wondered if are they even called? Or does the kernel initiate this activity directly? Are the PM utilities strictly userland?

I would like this additional layer of security beyond locking my screen, etc. and was wondering if anyone else had solved this elegantly or has best practices to recommend. Thanks.


Solution 1:

You might be able to have a user daemon listen for the status change over D-Bus. It looks like gnome-power-manager doesn't expose any signals for this, but you might be able to get something from hal or DeviceKit-power/upower.

Solution 2:

I have a little pm script that run's user-defined scripts for each logged in user on suspend/hibernate, resume/thaw. I've used this to kill or restart processes that don't behave well over suspend. User's can create scripts in ~/.user-pm which are run in lexicographic order on suspend and reverse order on resume. $1 has the pm operation name.

You could simply add a user-script that calls "ssh-add -D" on suspend/hibernate. (you'll have to look up the SSH_AUTH_SOCK somewhere, but I assume you'd need that for any solution).

Here's the global pm hook:

> cat /etc/pm/sleep.d/10_run_user_parts
#!/bin/sh

USER_PM_DIR=".user-pm"

# foreach logged in user
for user in `users | grep -o "\S*" | sort -u`; do
    user_home=`getent passwd "${user}" | awk -F: '{print $6}'`

    # check user has a valid home-directory
    [ -d $user_home ] || continue

    user_pm_dir="$user_home/$USER_PM_DIR"
    # check for user-pm directory
    [ -d "$user_pm_dir" ] || continue

    # call run-parts as $user
    case "$1" in
        hibernate|suspend)
        su -c "run-parts --arg=\"$1\" \"${user_pm_dir}\"" "${user}"
        ;;
        thaw|resume)
        su -c "run-parts --reverse --arg=\"$1\" \"${user_pm_dir}\"" "${user}"
        ;;
        *) exit $NA ;;
    esac
done

I'm on ubuntu - this should work for debian too - otherwise, YMMV

Solution 3:

If you add your key using the "-c" option to "ssh-add", it requires that you confirm every use. This isn't as good as removing the key from your agent on suspend, if you also lock your screen it can have a similar effect, since the key use can't be confirmed until you login.

In the past I accomplished this key removal by running a simple script that woke up every few seconds and looked for the program that locks the screen, and if it was found it would do the "ssh-add -D". Then once it went away, it would invoke the "ssh-add -c" again to ask me for the password. I ended up switching to just relying on confirmation and screen locking when I suspend or leave the keyboard.

Solution 4:

Thanks @Greg for your answer, I took the liberty of expanding on it to make it more "freedesktop" compliant, since pm-utils is a freedesktop.org project.

This script now will work in config.d, power.d, and sleep.d with a copy or a symlink. It'll then look for scripts to run in ~/.config/pm/ using the same folder names (config.d, power.d, and sleep.d) as /etc/pm.

#!/bin/sh

scriptdir=`cd $(dirname $0) && pwd`
USER_PM_DIR=".config/pm/$(basename $scriptdir)"

# foreach logged in user
for user in `users | grep -o "\S*" | sort -u`; do
    user_home=`getent passwd "${user}" | awk -F: '{print $6}'`

    # check user has a valid home-directory
    [ -d $user_home ] || continue

    user_pm_dir="$user_home/$USER_PM_DIR"
    # check for user-pm directory
    [ -d "$user_pm_dir" ] || continue

    # call run-parts as $user
    case "$1" in
        hibernate|suspend)
        su -c "run-parts --arg=\"$1\" \"${user_pm_dir}\"" "${user}"
        ;;
        thaw|resume)
        su -c "run-parts --reverse --arg=\"$1\" \"${user_pm_dir}\"" "${user}"
        ;;
        *) exit $NA ;;
    esac
done

Then this is my script to remove all keys from the ssh-agent on suspend/hibernate, and re-add a key used for SparkleShare. Just to be sure, it also checks for other ssh-agents and removes all the keys from them.

#!/bin/sh

case "$1" in
    hibernate|suspend)
        if [ ! -z $SSH_AUTH_SOCK ] && [ -r $SSH_AUTH_SOCK ]; then
            ssh-add -D
        fi

        for SSH_AUTH_SOCK in `find /tmp/ssh-*/agent.* -user $USER`; do
            SSH_AUTH_SOCK=$SSH_AUTH_SOCK /usr/bin/ssh-add -D
        done
        ;;
    thaw|resume)
        if [ ! -z $SSH_AUTH_SOCK ] && [ -r $SSH_AUTH_SOCK ]; then
            /usr/bin/ssh-add -t 0 ~/.config/sparkleshare/2011-03-21_14h15.key
        fi

        for SSH_AUTH_SOCK in `find /tmp/ssh-*/agent.* -user $USER`; do
            SSH_AUTH_SOCK=$SSH_AUTH_SOCK ssh-add -t 0 ~/.config/sparkleshare/2011-03-21_14h15.key
        done

        ;;
esac