How do I set up an email alert when a ssh login is successful?

Solution 1:

Warning: As always when you change the login configuration, leave a backup ssh session open in the background and test the login from a new terminal.

Since the sshrc method doesn't work if the user has their own ~/.ssh/rc file, I'll explain how to do this with pam_exec as @adosaiguas suggested. The good thing is that this can also be easily adapted to login types other than ssh (such as local logins or even all logins) by hooking into a different file in /etc/pam.d/.

First you need to be able to send mail from the command line. There are other questions about this. On a mail server it's probably easiest to install mailx (which is probably already installed anyway). You need to configure mailx so that the user root can send mails.

Then you need an executable script file login-notify.sh with the following content. You can change the variables to change the subject and content of the e-mail notification. You can put the file in /usr/local/bin or in /etc/ssh/ for example. Don't forget to run chmod +x login-notify.sh to make it executable. And give ownership to root with sudo chown root:root login-notify.sh, so that nobody can mess with the script.

#!/bin/sh

# Change these two lines:
sender="[email protected]"
recepient="[email protected]"

if [ "$PAM_TYPE" != "close_session" ]; then
    host="`hostname`"
    subject="SSH Login: $PAM_USER from $PAM_RHOST on $host"
    # Message to send, e.g. the current environment variables.
    message="`env`"
    echo "$message" | mailx -r "$sender" -s "$subject" "$recepient"
fi

Once you have that, you can add the following line to /etc/pam.d/sshd (with the correct /path/to/login-notify.sh of course):

session optional pam_exec.so seteuid /path/to/login-notify.sh

For testing purposes, the module is included as optional, so that you can still log in if the execution fails. You could change optional to required. However, this will prevent any SSH login unless the script is run successfully. Not sure if this is a good idea...

For those of you in need of an explanation of what PAM is and how it works, here is a very good one.

Solution 2:

Warning: according to the comments, this does not work if the user creates a file called ~/.ssh/rc.*

Modify or create /etc/ssh/sshrc with the following contents:

ip=`echo $SSH_CONNECTION | cut -d " " -f 1`

logger -t ssh-wrapper $USER login from $ip
echo "User $USER just logged in from $ip" | sendemail -q -u "SSH Login" -f "Originator <[email protected]>" -t "Your Name <[email protected]>" -s smtp.server.com &

This will effectively notify you by email anytime someone logs in through SSH, and the login will be logged in the syslog.

Note: You'll need the sendemailpackage (sudo apt-get install sendemail) for the email notification to work.

Note: works with port forwarding, but with -N option not.

Solution 3:

Put the following in /etc/profile:

if [ -n "$SSH_CLIENT" ]; then 
    TEXT="$(date): ssh login to ${USER}@$(hostname -f)" 
    TEXT="$TEXT from $(echo $SSH_CLIENT|awk '{print $1}')" 
    echo $TEXT|mail -s "ssh login" [email protected] 
fi

How the script works

/etc/profile is executed at every login (for bash shell users). The if statement will only return true if the user has logged in via ssh, which in turn will cause the indented code block to be run.

Next, we then build the text of the message:

  • $(date) will be replaced by the output of the date command
  • ${USER} will be replaced by the user’s login name
  • $(hostname -f) will be replaced by the full hostname of the system being logged into

The second TEXT line adds to the first, giving the IP address of the system this user is logging in from. Finally, the generated text is sent in an email to your address.

Summary Linux will, by default, record every system login, whether by ssh or not, in the system log files, but sometimes – particularly for a system that is seldom accessed via ssh – a quick and dirty notification can be useful.

Solution 4:

We have been using monit to monitor processes on our linux boxes. monit can also alert by emails on successful logins over ssh. Our monit config looks like this

 check file ssh_logins with path /var/log/auth.log  
     # Ignore login's from whitelist ip addresses
     ignore match "100.100.100.1"    
     # Else, alert
     if match "Accepted publickey" then alert

Note: The mailserver configuration, email format etc. should be set in monitrc file

Update: Wrote a more detailed blog post on this

Solution 5:

Mailgun adaptation of @Fritz answer

After posting I noticed @pacharanero also writes about mailgun, but I don't understand what they are doing with dig, so I'll post my solution as well.

If you are on a VM that doesn't have SMTP, you might need to use something like mailgun, sendgrid, or the like. This worked for me on Google Cloud.

One risk of this approach is that an attacker may get your outgoing email sending credentials if they can sudo su and find the script or you leave the script for sending email readable. mailgun has an ip whitelist you should set up, but that's imperfect for this particular use case, obviously.

This script should work with mailgun after you change mydomain.com to your actual domain. You could save the script in /root/login-alert.sh or some more obscure location.

#!/bin/bash
if [ "$PAM_TYPE" != "close_session" ]; then
    APK='api:your-mailgun-api-key-goes-here' 
    FROM='Login Alert <[email protected]>'
    TO='[email protected]'  
    SUBJECT="Login: $PAM_USER @ mydomain.com from $PAM_RHOST"
    DATE=$(date)
    TEXT="At $DATE a login occurred for $PAM_USER on mydomain.com from $PAM_RHOST"
    curl -s --user $APK \
     https://api.mailgun.net/v3/mg.mydomain.com/messages \
     -F from="$FROM" \
     -F to="$TO" \
     -F subject="$SUBJECT" \
     -F text="$TEXT"
fi

After that you can follow @Fritz answer to change /etc/pam.d/sshd to include:

session optional pam_exec.so seteuid /root/login-alert.sh

I note this works with no read permissions for arriving users (chmod 700 /root/login-alert.sh) so arriving users do not need to have read access to the script.