83

Does anyone have a bash script that will email or notify someone in the case of a successful login to a ssh server? I want to be notified if anyone logs into my personal box.

I'm using Ubuntu 12.04 running xfce

12 Answers 12

99

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.

20
  • 5
    Thanks, it works great. Just make sure you have UsePAM set to yes in your sshd_config. Mar 11, 2015 at 8:11
  • 2
    You should probably remove the fork (&) if you have required in the sshd file because mailx can fail but the user may still have logged on. Also, the script is run as root, so make sure mailx is also configured for root
    – texasflood
    Oct 4, 2015 at 13:55
  • 2
    Just a note to myself or other people who are new to Selinux. I got a permission error when pam_exec ran the script. Later I found out that it was incorrectly labelled for Selinux. I cloned the script to /bin/ which will automatically be labelled as unconfined_u:object_r:bin_t:s0. Then I chmod +x /bin/login-notify.sh and it works.
    – RedGiant
    Jan 18, 2017 at 17:12
  • 4
    /etc/pam.d/login <- for tty logins Sep 29, 2018 at 3:10
  • 2
    @4wk_ Thanks for the hint. I replaced it with a link to the Internet Archive, so it should work again now.
    – Fritz
    Jan 16, 2019 at 9:59
60

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.

5
  • 1
    Does this also work if the client doesn't request a TTY? E.g. ssh -N with only port forwarding.
    – gertvdijk
    Jan 5, 2013 at 15:58
  • does this also work when we are using gmail as the smtp server ?
    – user155073
    May 3, 2013 at 6:38
  • This needs a Warning: This does not work if the user creates a file called ~/.ssh/rc so it's quite useless as a security measure. @adosaiguas' answer concerning pam_exec is the correct one.
    – Fritz
    Apr 16, 2014 at 11:38
  • 2
    @mchid: If you consider the question "I want to be notified if anyone logs into my personal box.", then this might be acceptable. If you have only one user account. Otherwise you have to do it for all accounts, including every newly added account. And ideally you have make sure that users can not modify or delete their ~/.ssh/rc file. Using a system-wide method based on pam is just more reliable and safer, because only root can mess with it. So the answer is: The sshrd methods works okay for single-user systems, but the pam method works reliably for all systems.
    – Fritz
    Jan 26, 2017 at 11:32
  • It works perfectly. Just correction, that does not need sendmail: ip=echo $SSH_CONNECTION | cut -d " " -f 1 logger -t ssh-wrapper $USER login from $ip echo "User $USER just logged in from $ip" | mail -s "SSH Login from $ip" [email protected] & Mar 15, 2023 at 23:04
14

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.

4
  • Replaced hostname -f with hostnamectl --static Nov 23, 2019 at 9:12
  • 1
    Better put it to /etc/profile.d/ssh_login.sh for example
    – tagplus5
    Jan 11, 2020 at 11:13
  • easy and concise, I prefer this to @Fritz answer which does not seem to work on Ubuntu 19
    – Tian
    Apr 27, 2020 at 4:22
  • Note that if you use a synchronized email command, user can just ctrl+c and interrupt it before it finishes.
    – EvanBlack
    Apr 4, 2021 at 7:36
12

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

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.

2

In this other question you probably have what you are looking for. Basically you can add a call to the mail command in the script that is run when a user logs in via ssh: /etc/pam.d/sshd

2

I've taken some of the excellent answers from this thread and made something that is more-or-less copy-and-pasteable. It uses Mailgun to send the emails so you are spared any issues with setting up STMP. You just need a Mailgun API key and a sending domain.

Upon SSH login, the script will send details of the login (user, hostname, IP address, and all current environment variables) to an email address. It's easy to add other parameters you'd want to send by customising the message variable.

#!/bin/sh

# this script is triggered on SSH login and sends an email with details of the login
# such as user, IP, hostname, and environment variables

# script should be placed somewhere on the server, eg /etc/ssh
# to trigger on SSH login, put this line in /etc/pam.d/sshd:
#   session optional pam_exec.so seteuid /etc/ssh/snippet-for-sending-emails-on-SSH-login-using-PAM.sh

# Script settings
MAILGUN_API_KEY=
MAILGUN_DOMAIN=
SENDER_NAME=
SENDER_EMAIL_ADDRESS=
RECIPIENT_EMAIL_ADDRESS=

if [ "$PAM_TYPE" != "close_session" ]; then
    host=$(hostname)
    ip=$(dig +short myip.opendns.com @resolver1.opendns.com) # gets public IP
    # Message to send, e.g. the current environment variables.
    subject="SSH login - user:$USER pam-host:$PAM_RHOST host:$host ip:$ip" \
    message=$(env)
    curl -s --user '$MAILGUN_API_KEY' \
        https://api.mailgun.net/v3/$MAILGUN_DOMAIN/messages \
        -F from='$SENDER_NAME <$SENDER_EMAIL_ADDRESS>' \
        -F to=$RECIPIENT_EMAIL_ADDRESS \
        -F subject="$subject" \
        -F text="${subject} ${message}"
fi
1
  • This is the best answer in my opinion. It is simple and doesn't require sending an e-mail from the machine, which will surely end up in the spam folder unless properly configured.
    – JayD3e
    May 27, 2019 at 10:23
2

I'm using swatchdog from the swatch package to monitor for any lines containing the phrase "fail" (case insensitive) in /var/log/auth.log. I set it up to run it as a simple systemd service.

apt install swatch

Create a configure file /etc/swatch/swatch-auth-log.conf with owner root, permission 644 --

watchfor /fail/i
  pipe /usr/local/sbin/sendmail -t [email protected]

The "/fail/i" is a regexp, with the "i" indicating it is case insensitive. (My sendmail is a script sending everything to a fixed address via mailgun, so the address doesn't really matter).

Create a systemd service file /etc/systemd/system/swatch-auth-log.service with owner root, permission 644 --

[Unit]
Description=monitor /var/log/auth.log, send fail notices by mail

[Service]
ExecStart=/usr/bin/swatchdog -c /etc/swatch/swatch-auth-log.conf -t /var/log/auth.log

[Install]
#WantedBy=multi-user.target
WantedBy=pre-network.target

Then enable, start, and view the status of the service --

sudo systemctl enable swatch-auth-log.service
sudo systemctl start swatch-auth-log.service
sudo systemctl status swatch-auth-log.service

An example of a successful status report --

● swatch-auth-log.service - monitor /var/log/auth.log, send fail notices by mail
   Loaded: loaded (/etc/systemd/system/swatch-auth-log.service; enabled; vendor preset: enabled)
   Active: active (running) since Thu 2019-01-31 21:41:52 PST; 17min ago
 Main PID: 27945 (swatchdog)
    Tasks: 3 (limit: 4915)
   CGroup: /system.slice/swatch-auth-log.service
           ├─27945 /usr/bin/perl /usr/bin/swatchdog -c /etc/swatch/swatch-auth-log.conf -t /var/log/auth.log
           ├─27947 /usr/bin/perl /.swatchdog_script.27945
           └─27949 /usr/bin/tail -n 0 -F /var/log/auth.log

Jan 31 21:41:52 ub18 systemd[1]: Started monitor /var/log/auth.log, send fail notices by mail.
Jan 31 21:41:52 ub18 swatchdog[27945]: *** swatchdog version 3.2.4 (pid:27945) started at Thu Jan 31 21:41:52 PST 2019

The service will be automatically started at boot and monitored by systemd.


Discussion

Originally I used a pam solution similar to the above, but in /etc/pam.d/common-auth not sshd. That was to catch ssh, sudo, and logins. But then after an update all my passwords stopped working, even after changing the passwords in rescue mode. Eventually I changed the /etc/pam.d/common-auth back to the original and passwords worked again. Here is a description on the Stack Exchange UNIX & Linux board

I decided it would be safer not to touch difficult to understand security settings. And everything is in the log files anyway.

1

I've actually just modified @SirCharlo answer

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

logger -t ssh-wrapper $USER login from $ip
echo "User $USER just logged in from $ip" | mail -s "SSH Login" "who to <[email protected]>" &

This works on 14.04, 16.04 and Centos 6.5.x servers I've setup, I'm pretty sure you need to ensure mta is configured, but once that is done, this works a charm. Next step twilio alerts

1

This script in /etc/ssh/sshrc sends an email and adds a log to system logger. A difference is made (so you can disable it if you want) between your personal subnet and the world wide web (requires sudo apt-get install mailutils).

SUBNET="192.168.0"

IP=`echo $SSH_CONNECTION | cut -d " " -f 1`
CURRENT_SUBNET="$(echo $IP|cut -d'.' -f1-3)"
if [ "$CURRENT_SUBNET" = "$SUBNET" ]; then
        msg="This message comes from same subnet! User $USER just logged in from $IP"
        echo $msg|mail -s "$msg" root
else
        msg="This message comes from different subnet! User $USER just logged in from $IP"
        echo $msg|mail -s "$msg" root
fi

logger -t ssh-wrapper $USER login from $IP
0

That works for me :

1- Find user folder (root for me) :

echo  ~root

2- create or edit file ".bashrc" in root folder :

nano root/.bashrc

(replace "root" with your user folder)

3- add theses lines :

# ssh mail notification
echo 'NOTIFICATION - Acces SSH en ROOT sur `hostname` le:' `date` `who` | mail -s "NOTIFICATION - Connexion en ROOT via SSH depuis: `who | cut -d"(" -f2 | cut -d")" -f1`" [email protected]

Just replace [email protected] by your email.

Repeat with other users if you have more than one.

Source : http://blogmotion.fr/systeme/notification-connexion-ssh-4246

0

I tried this, but, I had trouble getting mailx to cooperate with my gmail account. I found an alternative to email. If you have an android phone you can install "MQTT push Client". Setup an MQTT broker using mosquitto, and publish to it in the login-notify.sh script. Subscribe to the broker+topic with "MQTT push Client" and you're done. You will get push notifications on your phone, no email needed.

0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .