maleadt     posts     about

System-wide SSH login notifications with Pushbullet

I recently found about Pushbullet, a service and set of applications which allows you to share notifications and other text messages between your devices. They also provide a convenient API, making it easy to send notifications from scripts or other programs.

In a quest to secure my personal server, I wanted to get a notification for each SSH login. I found some solutions online, but they weren’t waterproof (relying on per-user .profile modifications) or were a bit too hackish for my taste (actively tailing auth.log).

Solution

It’s essential that any user logging in cannot externally prevent the notification from being sent. The best solution I found is to modify the SSH server configuration, and force execution of a wrapper script which will generate the notification. The ForceCommand option does exactly that:

Forces the execution of the command specified by ForceCommand, ignoring any command supplied by the client and ~/.ssh/rc if present.

Within the wrapper script, we can use the (relatively undocumented) SSH_CONNECTION environment variable to get a hold of some details about the current connection. We will use that to make our notification a bit more interesting. Finally, we hand control back to the user, spawning the command asked for (saved in SSH_ORIGINAL_COMMAND), or the user’s default shell:

#!/bin/sh

SHELL=$(getent passwd $USER | cut -d: -f7)
IP=$(echo $SSH_CONNECTION | cut -d " " -f 1)
HOSTNAME=$(dig -x $IP +short)
if [ -z "${HOSTNAME}" ]; then
        HOSTNAME=$IP
fi
LOCALHOST=$(hostname)

/usr/local/bin/pushmessage \
        "SSH login on $LOCALHOST" \
        "User ${USER} has logged in from ${HOSTNAME}"

${SSH_ORIGINAL_COMMAND-$SHELL}

I saved this script in /usr/local/sbin/ssh-wrapper, made it executable, and activated it by adding ForceCommand /usr/local/sbin/ssh-wrapper to /etc/ssh/sshd_config.

Note that my wrapper script makes use of pushmessage, a small script which delivers the actual notification:

#!/bin/sh

if [ "$#" != 2 ]; then
    echo "Usage: $0 TITLE MESSAGE" >&2
    exit 1
fi

APIKEY="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
IDEN="XXXXXXXXXXXXXXXXXXXXXX"

curl https://api.pushbullet.com/api/pushes -u ${APIKEY}: \
    --output /dev/null --silent --max-time 5 \
    -X POST -d device_iden=${IDEN} \
    -d type=note -d title="$1" \
    -d body="$2"

The APIKEY and IDEN variables are personalised, and contain respectively your Pushbullet access token and the device identification. The former you can find on your Pushbullet account page, and in order to get a suitable device identifier you’ll need to inquire the API:

$ curl --silent -u ${APIKEY}: \
  https://api.pushbullet.com/api/devices | python -m json.tool
{
    "devices": [
        {
            ...,
            "iden": "XXXXXXXXXXXXXXXXXXXXXX"
        }
    ],
    "shared_devices": []
}

Limitations

References

  1. SSH Login Notifications using Pushbullet
  2. SSH Login Meldung aufs Handy per Pushbullet
  3. Raspberry Pi: Push Benachrichtigung bei SSH Anmeldung
  4. Wie wird eine Pushover Benachrichtigung auf dem Raspberry Pi bei Zugriff per SSH versendet um Einbrüche zu erkennen?