🚀 Executive Summary
TL;DR: This guide provides a Python-based solution to detect SSH root logins in real-time, addressing the critical need for immediate notification of high-privilege access attempts. By continuously monitoring SSH authentication logs, the script triggers instant email alerts upon detecting a successful root login, significantly enhancing server security posture.
🎯 Key Takeaways
- The Python script dynamically identifies SSH log file paths (e.g., /var/log/auth.log or /var/log/secure) to ensure cross-distribution compatibility.
- Secure handling of email credentials is achieved by loading sensitive information from environment variables via a
config.shfile, preventing hardcoding in the script. - Log monitoring efficiency is maintained by tracking the last read position in a
last\_position.txtfile, ensuring only new log entries are processed in subsequent runs.
Detecting SSH Root Logins: Real-time Email Alerts using Python
Introduction
In the realm of system administration and DevOps, security is paramount. One of the most critical events to monitor on any Linux server is an SSH login using the root account. While direct root logins are often discouraged and sometimes disabled, they can occur in legacy systems or specific operational scenarios. More importantly, an unauthorized root login signifies a severe security breach that demands immediate attention. Waiting for daily log reviews is simply not an option when the integrity of your entire system is at stake.
This tutorial addresses that critical need. We will walk through building a robust, yet straightforward, Python script that continuously monitors your server’s SSH authentication logs. Upon detecting a successful root login, the script will instantly trigger an email alert, providing you with real-time notification to react swiftly to potential threats. By automating this crucial monitoring, you enhance your system’s security posture, ensuring that you are always in the loop regarding high-privilege access attempts.
Prerequisites
- A Linux server (e.g., Ubuntu, Debian, CentOS, RHEL).
- Python 3 installed on your server.
- An SMTP server or service for sending emails (e.g., Gmail, SendGrid, a local Postfix setup).
- Basic familiarity with Bash shell commands and Python scripting.
- Network access from your server to the internet if using an external SMTP service.
Step-by-Step Guide
Step 1: Identify SSH Log Patterns
The first step is to understand where your server logs SSH authentication attempts and what a successful root login looks like in those logs. The location of these logs can vary depending on your Linux distribution:
-
Debian/Ubuntu: Typically
/var/log/auth.log -
CentOS/RHEL: Typically
/var/log/secure
A successful root login usually contains phrases like “Accepted password for root” or “Accepted publickey for root”. We’ll use regular expressions to match these patterns. To inspect your logs, you might use a command like: tail -f /var/log/auth.log (or /var/log/secure) and then attempt a root login (if safe to do so) to observe the entries.
Example log entry for a successful root login (IP address obfuscated):
Dec 01 10:30:45 your-hostname sshd[12345]: Accepted password for root from 203.0.113.10 port 54321 ssh2
Dec 01 10:31:00 your-hostname sshd[12346]: Accepted publickey for root from 203.0.113.11 port 54322 ssh2: RSA SHA256:[KEYHASH]
Step 2: Develop the Python Alert Script (ssh_monitor.py)
Create a new Python file named ssh\_monitor.py. This script will be responsible for reading the log file, identifying root logins, and sending email alerts. The script will also track its position in the log file to avoid re-processing old entries and only focus on new ones.
import smtplib
import re
import os
import time
from email.mime.text import MIMEText
# --- Configuration (loaded from environment variables) ---
SMTP_SERVER = os.environ.get('SMTP_SERVER', 'smtp.gmail.com')
SMTP_PORT = int(os.environ.get('SMTP_PORT', 587))
SENDER_EMAIL = os.environ.get('SENDER_EMAIL')
SENDER_PASSWORD = os.environ.get('SENDER_PASSWORD') # Use app-specific passwords for Gmail
RECIPIENT_EMAIL = os.environ.get('RECIPIENT_EMAIL')
LOG_POSITION_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'last_position.txt')
def get_log_file_path():
"""Determines the correct SSH authentication log file path."""
if os.path.exists('/var/log/auth.log'):
return '/var/log/auth.log'
elif os.path.exists('/var/log/secure'):
return '/var/log/secure'
else:
print("Error: SSH log file not found. Checked /var/log/auth.log and /var/log/secure.")
return None
def send_alert(subject, body):
"""Sends an email alert using SMTP."""
if not all([SENDER_EMAIL, SENDER_PASSWORD, RECIPIENT_EMAIL]):
print("Email credentials or recipient not fully configured. Skipping email alert.")
return
msg = MIMEText(body)
msg['Subject'] = subject
msg['From'] = SENDER_EMAIL
msg['To'] = RECIPIENT_EMAIL
try:
with smtplib.SMTP(SMTP_SERVER, SMTP_PORT) as server:
server.starttls() # Enable TLS encryption
server.login(SENDER_EMAIL, SENDER_PASSWORD)
server.send_message(msg)
print(f"Alert email sent successfully to {RECIPIENT_EMAIL}.")
except Exception as e:
print(f"Failed to send email alert: {e}")
def monitor_ssh_logs():
"""Monitors SSH log file for root logins and sends alerts."""
log_file = get_log_file_path()
if not log_file:
return
# Read last known position
last_position = 0
if os.path.exists(LOG_POSITION_FILE):
try:
with open(LOG_POSITION_FILE, 'r') as f:
last_position = int(f.read().strip())
except ValueError:
print("Warning: Could not read last position. Starting from beginning.")
last_position = 0
print(f"Monitoring '{log_file}' from position {last_position}...")
try:
with open(log_file, 'r') as f:
f.seek(last_position) # Go to the last read position
for line in f:
# Regex to detect successful root logins
if re.search(r'Accepted (password|publickey) for root from (\S+) port (\d+)', line):
hostname = os.uname().nodename
alert_subject = f"CRITICAL ALERT: Root SSH Login on {hostname}"
alert_body = f"A successful root SSH login has been detected on server '{hostname}'.\n\nLog Entry:\n{line.strip()}\n\nPlease investigate immediately."
send_alert(alert_subject, alert_body)
print(f"Root login detected: {line.strip()}")
# Save the new last position
current_position = f.tell()
if current_position != last_position:
with open(LOG_POSITION_FILE, 'w') as f_pos:
f_pos.write(str(current_position))
print(f"Updated log position to {current_position}.")
except FileNotFoundError:
print(f"Error: Log file not found at {log_file}.")
except Exception as e:
print(f"An unexpected error occurred: {e}")
if __name__ == "__main__":
monitor_ssh_logs()
Code Logic Explained:
-
Configuration: It retrieves SMTP server details, sender/recipient emails, and sender password from environment variables for security. The
LOG\_POSITION\_FILEensures the script remembers where it left off. -
get_log_file_path(): This function dynamically checks for/var/log/auth.logor/var/log/secureto support different Linux distributions. -
send_alert(subject, body): This function constructs and sends an email using Python’ssmtplibmodule. It uses TLS for secure communication and handles login with your SMTP credentials. -
monitor_ssh_logs():- Reads the
last\_position.txtfile to get the byte offset of the last read line in the SSH log. If the file doesn’t exist or is invalid, it starts from the beginning. - Opens the SSH log file in read mode and uses
f.seek(last\_position)to jump to the previously recorded position. - It then iterates through new lines, applying a regular expression (
re.search) to identify patterns indicative of a successful root login. - Upon detection, it constructs an alert email with relevant details (server hostname, log entry) and calls
send\_alert(). - After processing new lines, it updates
last\_position.txtwith the current file pointer (f.tell()) to ensure that only new entries are processed in subsequent runs.
- Reads the
Step 3: Securely Configure Email Credentials
Hardcoding sensitive information like email passwords directly into your script is a major security risk. Instead, we use environment variables. For a cron job, these variables need to be set in the cron environment or within a wrapper script that sources them.
Create a file named config.sh in the same directory as your Python script (e.g., /home/user/) and populate it with your email credentials. Remember to use an app-specific password if you are using Gmail with 2-Factor Authentication enabled.
# config.sh
export SMTP_SERVER="smtp.gmail.com" # Or your SMTP server (e.g., smtp.sendgrid.net)
export SMTP_PORT="587" # Or your SMTP port (e.g., 25, 465, 587)
export SENDER_EMAIL="your_alert_email@example.com"
export SENDER_PASSWORD="your_secure_app_password" # Use an app password!
export RECIPIENT_EMAIL="your_sysadmin_email@example.com"
Make sure this file is only readable by the owner to protect your credentials:
chmod 600 /home/user/config.sh
Step 4: Create a Wrapper Script and Set up Execution (run_monitor)
To run your Python script periodically via cron, it’s best to use a small wrapper script. This ensures that the environment variables are correctly loaded before the Python script executes.
Create a file named run\_monitor (no extension) in the same directory (/home/user/):
# Bash Script: run_monitor
#!/bin/bash
# Source the configuration file to load environment variables
source /home/user/config.sh
# Navigate to the script's directory
cd /home/user/ || exit 1
# Execute the Python script
python3 ssh_monitor.py
Make both your Python script and the wrapper script executable:
chmod +x /home/user/ssh_monitor.py
chmod +x /home/user/run_monitor
Step 5: Schedule with Cron
Now, we’ll schedule the run\_monitor script to execute periodically using cron. This will ensure that your SSH logs are constantly monitored for root login activity.
Open your cron editor:
Open your cron editor
Add the following line to the end of the file. This entry will execute your run\_monitor script every minute:
*/1 * * * * /home/user/run_monitor
Save and exit the cron editor. Your cron job is now set up and will run the monitor every minute, checking for new root SSH logins.
Common Pitfalls
-
Incorrect Log File Path: The script dynamically checks, but ensure your system’s SSH log file is either
/var/log/auth.logor/var/log/secure. If not, update theget\_log\_file\_path()function accordingly. -
SMTP Server/Credential Issues: Double-check your
SMTP\_SERVER,SMTP\_PORT,SENDER\_EMAIL,SENDER\_PASSWORD, andRECIPIENT\_EMAILvalues. For Gmail, you MUST use an app-specific password if 2-Factor Authentication is enabled. Firewall rules might also block outgoing SMTP traffic from your server. -
Permissions: The user running the cron job (usually root) must have read access to the SSH log file and write access to the
last\_position.txtfile and the directory it resides in (e.g.,/home/user/). Thessh\_monitor.pyandrun\_monitorscripts also need execute permissions. -
Environment Variables Not Loaded for Cron: Ensure
config.shis correctly sourced inrun\_monitorand thatrun\_monitoritself is executable and called with its full path in the cron entry. -
Python Dependencies: While
smtplib,re,os,time,email.mime.text.MIMETextare standard, ensure your Python 3 installation is complete.
Conclusion
By following this tutorial, you’ve successfully implemented a critical security measure: real-time email alerts for SSH root logins. This Python-based solution provides an immediate notification system, empowering you to detect and respond to potential compromises swiftly. Proactive monitoring of high-privilege access is a cornerstone of robust server security, and this script provides a reliable, easy-to-deploy method to maintain vigilance. Consider expanding this solution with features like alert rate-limiting, integration with other monitoring systems, or different notification channels (e.g., Slack, PagerDuty) as your needs evolve.
👉 Read the original article on TechResolve.blog
☕ Support my work
If this article helped you, you can buy me a coffee:

Top comments (0)