Setting Up Linux SSH Login Alerts with Slack Notifications: A Step-by-Step Guide


In this article, I will walk you through creating a simple but effective alerting system for SSH logins on your Linux server that sends notifications directly to Slack. These notifications provide crucial information such as which user logged in, the server’s hostname, and optional geographic data using an IP API.

With the rising importance of server security, monitoring SSH access is essential for keeping your systems secure. By setting up these alerts, you can keep an eye on server access in real-time, ensuring quick action when something unusual happens.

You can download the project from my GitHub repository at: Linux Slack Alert. Let’s break down what it does, how it works, and how to use it in detail.

What Does the Linux Slack Alert Do?

As of now the project contains two primary scripts:

  • notify.sh: A basic notification script that sends a Slack message whenever an SSH login occurs.
  • advanced.sh: A more advanced version that includes IP information from the Free IP API, such as country, city, proxy status, and geographic coordinates.

Both scripts are triggered upon user login to your server, using the PAM (Pluggable Authentication Modules) system, which can execute a command or script when a session is opened. Once triggered, the scripts send a customized message to a Slack channel via a Slack webhook.

Why Use Slack for SSH Alerts?

Slack is a popular team collaboration tool, and by integrating it with your server’s SSH login notifications, you ensure that your team is instantly informed whenever someone logs into your server. You can monitor server access from anywhere, and since Slack supports webhooks, setting it up is straightforward. Furthermore, if you prefer to use other endpoints like Microsoft Teams, Discord, or email, with slight modifications to the script, these notifications can be adapted to your preferred platform.

How It Works

The core of the system is the notify.sh script. When a user logs in via SSH, PAM triggers the script, which sends a notification to your Slack channel. This notification includes the username, the IP address of the user, and a special name for the server for easy identification.

For more detailed information about the incoming IP address, the advanced.sh script integrates with the Free IP API. The API allows you to extract geographical data like city, country, and proxy information, which is helpful in detecting suspicious logins.

Step-by-Step Guide to Setting It Up

Follow these steps to set up SSH login notifications on your Linux server:

Step 1: Clone the Repository

First, clone the project from GitHub:

git clone https://github.com/rolandfarkasCOM/linux-slack-alert.git

Step 2: Create a Scripts Folder

SSH login notifications will be managed by PAM, and you’ll need to place the notification script in a dedicated folder:

mkdir /etc/ssh/scripts/

Step 3: Add the notify.sh or advanced.sh Script

Navigate to the cloned repository and copy the notify.sh or advanced.sh file to the scripts folder:

cp linux-slack-alert/notify.sh /etc/ssh/scripts/

If you want more detailed geographic information, use advanced.sh instead:

cp linux-slack-alert/advanced.sh /etc/ssh/scripts/

Step 4: Update the Script

Open the script to edit the webhook URL and other parameters:

nano /etc/ssh/scripts/notify.sh

or

nano /etc/ssh/scripts/advanced.sh

Replace the placeholder <YOUR SLACK WEBHOOK> with your actual Slack webhook URL. You can customize other parameters like the channel name and the special server name to make notifications more informative.

Step 5: Set Permissions

The script needs to be executable by the system, so ensure you set the appropriate permissions:

sudo chmod +x /etc/ssh/scripts/notify.sh

Step 6: Link the Script to SSHD Service

To make sure the script runs every time someone logs in via SSH, add the following line to the /etc/pam.d/sshd file:

sudo echo "session optional pam_exec.so seteuid /etc/ssh/scripts/notify.sh" >> /etc/pam.d/sshd

For advanced.sh, install the jq tool to parse JSON responses from the IP API:

sudo apt-get install jq

Step 7: Test the Script

You can test the script by initiating an SSH session to your server. As soon as you log in, you should receive a notification in Slack.

How to Customize and Extend

The script is fully customizable and can be adapted to suit your needs. Here are some ideas for extending its functionality:

  • Change Notification Endpoint: If you want to send the notification to another platform like Microsoft Teams, Discord, or even an email, simply replace the Slack webhook URL with the appropriate webhook URL for the platform.
  • Add More Data to the Notification: The advanced version of the script uses IP data from the Free IP API to provide information about the user’s location. You can expand this further by adding more fields from the API response, such as ISP, postal code, or time zone.
  • Track Failed Login Attempts: You could modify the script to notify you about failed login attempts, which could help in detecting brute force attacks.
  • Use Environment-Specific Webhooks: If you’re managing multiple environments (e.g., development, staging, production), you could set up different webhooks for each and configure the script accordingly, allowing you to see where the login is happening.

Code Breakdown for advanced.sh

The advanced.sh script is an extended version of the notify.sh script, with added functionality to fetch IP details via an external API. Here’s a breakdown of each section of the code:


1. Initial Checks for PAM Session Type
if [ "$PAM_TYPE" != "close_session" ]; then

This line ensures the script only runs when a new SSH session is opened (not when a session is closed). PAM triggers this script for both session types, but we only care about the login event.


2. Webhook and Notification Settings
url="<YOUR SLACK WEBHOOK>"
channel="#channel"
host="$(hostname)"
special_name="YourSpecialName"  # Define your special name
group="OptionalGroupName"       # Define your optional group (can be left empty)

Here, we define the Slack webhook URL where the notifications will be sent. You also specify the Slack channel, the hostname (which is dynamically fetched using hostname), and optional fields such as a special name for the server and a group name to categorize the server.


3. Defining the IP API URL
ip_api_url="https://freeipapi.com/api/json/$PAM_RHOST"

This URL is used to fetch location data based on the SSH client’s IP address. The variable $PAM_RHOST contains the IP address of the remote host attempting to log in. The script sends a request to the IP API using this IP address to get more information about the user’s location.


4. Fields to Extract from the API Response
ip_fields=("countryName" "cityName" "latitude" "longitude")

The ip_fields array defines the specific fields you want to extract from the IP API’s response. You can modify this array to include other fields such as isProxy, regionName, postalCode, etc.


5. Fetching and Parsing IP Data
if [ -n "$PAM_RHOST" ]; then
    ip_info=$(curl -s "$ip_api_url")

    ip_details=""

    for field in "${ip_fields[@]}"; do
        value=$(echo "$ip_info" | jq -r ".${field}")
        if [ "$value" != "null" ]; then
            ip_details+="$field: $value, "
        fi
    done

    ip_details=$(echo "$ip_details" | sed 's/, $//')
fi

This block checks if the $PAM_RHOST variable (remote IP address) exists, then uses curl to fetch data from the API. The response is stored in ip_info.

  • Looping through Fields: The script loops through the fields in the ip_fields array and extracts the corresponding values using jq. If a field contains valid data (i.e., it’s not null), it is appended to the ip_details string.
  • Cleaning the Output: After building the ip_details string, it removes any trailing commas and spaces for cleaner formatting.

6. Creating the Notification Content
if [ -z "$group" ]; then
    content="\"attachments\": [ { \"mrkdwn_in\": [\"text\", \"fallback\"], \"fallback\": \"SSH login: $PAM_USER connected to \`$host\` - $special_name\", \"text\": \"SSH login to \`$host\` - $special_name\", \"fields\": [ { \"title\": \"User\", \"value\": \"$PAM_USER\", \"short\": true }, { \"title\": \"IP Address\", \"value\": \"$PAM_RHOST\", \"short\": true } ], \"color\": \"#F35A00\" } ]"
else
    content="\"attachments\": [ { \"mrkdwn_in\": [\"text\", \"fallback\"], \"fallback\": \"SSH login: $PAM_USER connected to \`$host\` - $special_name ($group)\", \"text\": \"SSH login to \`$host\` - $special_name ($group)\", \"fields\": [ { \"title\": \"User\", \"value\": \"$PAM_USER\", \"short\": true }, { \"title\": \"IP Address\", \"value\": \"$PAM_RHOST\", \"short\": true } ], \"color\": \"#F35A00\" } ]"
fi

The notification content is built here. It uses Slack’s attachment format to send structured messages with fields for the user ($PAM_USER) and the IP address ($PAM_RHOST). If a group is defined, it is appended to the special name.


7. Adding IP Details to the Notification
if [ -n "$ip_details" ]; then
    content="\"attachments\": [ { \"mrkdwn_in\": [\"text\", \"fallback\"], \"fallback\": \"SSH login: $PAM_USER connected to \`$host\` - $special_name\", \"text\": \"SSH login to \`$host\` - $special_name ($group) \n *IP Details:* $ip_details\", \"fields\": [ { \"title\": \"User\", \"value\": \"$PAM_USER\", \"short\": true }, { \"title\": \"IP Address\", \"value\": \"$PAM_RHOST\", \"short\": true } ], \"color\": \"#F35A00\" } ]"
fi

If IP details were fetched successfully, they are appended to the Slack message. The ip_details variable is inserted under the “IP Details” section of the message.


8. Sending the Slack Notification
curl -X POST --data-urlencode "payload={\"channel\": \"$channel\", \"mrkdwn\": true, \"username\": \"SSH Alert\", $content, \"icon_emoji\": \":closed_lock_with_key:\"}" "$url" &

This command uses curl to send the message to Slack via the webhook URL. The message payload contains:

  • channel: The Slack channel where the message will be posted.
  • username: The name that will appear as the sender of the message (e.g., “SSH Alert”).
  • icon_emoji: An emoji icon that represents the alert.
  • content: The message content, which includes the user, IP address, and optional IP details.

The & at the end runs the curl command in the background.


9. Exit
exit

Finally, the script exits. This ensures that no further code is executed after sending the notification.


Summary

The advanced.sh script extends the basic functionality of notify.sh by incorporating geographic data from an IP API. It sends detailed Slack notifications about SSH logins, including the user’s IP address, location details, and proxy status.

Practical Use Cases

This system is highly versatile and can be adapted for various scenarios:

  • Monitoring Access in Production Environments: Keep track of who accesses your production servers and from where. If a login occurs from an unexpected location, it can signal a potential breach.
  • Development Environments: Even though security is often less strict in dev environments, keeping an eye on SSH access can help prevent unauthorized changes to critical resources.
  • Alerting on Suspicious Logins: The integration with the Free IP API allows you to detect logins from suspicious locations or via proxies, which could be an indicator of malicious activity.

Conclusion

Setting up SSH login notifications in Slack with this script is a simple yet effective way to improve server security. Whether you use the basic notify.sh script or the advanced version that provides geographic information, this system gives you real-time insight into who’s accessing your servers and from where.

The project is available on GitHub, and with a few simple steps, you can have this monitoring solution in place, ensuring you’re always aware of SSH logins to your system.

Get the Linux Slack Alert scripts here and start enhancing your server security today!