← Back to list

5 Practical Bash Scripts for SSH Monitoring (No SIEM, No Agents)

Simple tools used correctly

Obafemi · 2026-01-13 16:02 · 57 claps · 2.7 min read paywalled
#ssh-security #ssh-login #ssh #bash #devops
Open on Medium ↗
Wiki topics: AGT · AI Agents ☁️ · DevOps & Cloud

5 Practical Bash Scripts for SSH Monitoring (No SIEM, No Agents)

Simple tools used correctly

SSH monitoring means tracking login attempts, authentication failures, and configuration changes to detect attacks and unauthorized access early.

You can monitor SSH activity using simple Bash scripts by parsing auth.log without deploying heavy security tools.

Important Scope (Read This First)

These scripts are not a replacement for:

  • Fail2Ban
  • central logging
  • SIEMs
  • configuration management

They are best used when:

  • you run small fleets or VPSs
  • you want visibility before adding heavy tools
  • you need something auditable and transparent
  • you want to understand what your SSH logs actually say

Log Location

Set this once and reuse it:

LOG_FILE="/var/log/auth.log"   # /var/log/secure on RHEL/CentOS

Now let’s get into the meat of the article.

1. Detect SSH Brute Force Attempts (Time-Bounded & Stateful)

This solves the problem of random bots constantly hitting SSH. You only care when attempts are frequent and recent.

#!/bin/bash

LOG_FILE="/var/log/auth.log"
STATE_FILE="/var/tmp/ssh_failed.offset"
THRESHOLD=10

LAST_LINE=$(cat "$STATE_FILE" 2>/dev/null || echo 0)
TOTAL_LINES=$(wc -l < "$LOG_FILE")

tail -n +"$((LAST_LINE + 1))" "$LOG_FILE" \
| grep "Failed password" \
| awk '{print $(NF-3)}' \
| sort | uniq -c \
| awk -v t="$THRESHOLD" '$1 >= t {print $2 " (" $1 " attempts)"}'

echo "$TOTAL_LINES" > "$STATE_FILE"
  • Only scans new log lines since the last run
  • Groups failed logins by IP
  • Flags IPs that fail too many times in a short window
  • Avoids re-alerting on old noise

This gives you signal, not background internet noise.

2. Alert on Root SSH Logins (Correctly)

Root SSH access should already be disabled. If it ever happens, you want to know once, not forever.

#!/bin/bash

LOG_FILE="/var/log/auth.log"
STATE_FILE="/var/tmp/ssh_root.offset"

LAST_LINE=$(cat "$STATE_FILE" 2>/dev/null || echo 0)
TOTAL_LINES=$(wc -l < "$LOG_FILE")

tail -n +"$((LAST_LINE + 1))" "$LOG_FILE" \
| grep "Accepted" \
| grep "root" \
| while read -r line; do
    echo " Root SSH login detected on $(hostname)"
    echo "$line"
  done

echo "$TOTAL_LINES" > "$STATE_FILE"
  • Alerts only on new root logins
  • Avoids alert spam
  • Catches misconfiguration or policy violations fast

It’s best practice to disable root SSH entirely and keep this as a safety net.

3. Detect Successful SSH Logins From New IPs (Safely)

Instead of “any new IP ever”, this script tracks recent history.

#!/bin/bash

LOG_FILE="/var/log/auth.log"
KNOWN_IPS="/var/log/ssh_known_ips.txt"

grep "Accepted" "$LOG_FILE" \
| awk '{print $(NF-3)}' \
| sort -u > /tmp/current_ips

touch "$KNOWN_IPS"

NEW_IPS=$(comm -13 <(sort "$KNOWN_IPS") /tmp/current_ips)

if [[ -n "$NEW_IPS" ]]; then
  echo "New SSH login IPs detected:"
  echo "$NEW_IPS"
  echo "$NEW_IPS" >> "$KNOWN_IPS"
fi
  • Alerts only when a new source appears
  • Simple and transparent

Helps catch stolen keys, leaked credentials and forgotten access paths.

It is noisy for:

  • Mobile admins
  • Dynamic IPs
  • No bastion host

In those cases, use this for awareness, not blocking.

4. Detect SSH Configuration Changes

SSH config changes can silently weaken your security.

This script alerts you the moment it happens.

#!/bin/bash

CONFIG="/etc/ssh/sshd_config"
STATE="/var/log/sshd_config.sha256"

CURRENT=$(sha256sum "$CONFIG" | awk '{print $1}')

if [[ ! -f "$STATE" ]]; then
  echo "$CURRENT" > "$STATE"
  exit 0
fi

KNOWN=$(cat "$STATE")

if [[ "$CURRENT" != "$KNOWN" ]]; then
  echo " SSH configuration changed on $(hostname)"
  echo "$CURRENT" > "$STATE"
fi
  • Detects unauthorized changes
  • Catches config drift
  • Works even without Git or Ansible

This is cheap integrity monitoring, and it’s effective.

5. Daily SSH Activity Summary (Readable & Actionable)

Instead of raw counts, this report gives context.

#!/bin/bash

LOG_FILE="/var/log/auth.log"

echo "===== SSH Daily Summary ====="
echo "Host: $(hostname)"
echo

echo "Successful logins by user:"
grep "Accepted" "$LOG_FILE" \
| awk '{print $(NF-5)}' \
| sort | uniq -c | sort -nr
echo

echo "Top source IPs:"
grep "Accepted" "$LOG_FILE" \
| awk '{print $(NF-3)}' \
| sort | uniq -c | sort -nr | head
echo

echo "Failed login attempts:"
grep "Failed password" "$LOG_FILE" \
| wc -l
  • Shows who actually logged in
  • Shows where access comes from
  • Helps spot unusual patterns over time

Send this once per day, not every hour.

[embed]11 systemctl Commands for Power Users in Production level up your systemd management skillsmedium.com

[embed]12 Essential Bash Scripts for Streamlining Database Administration simplify your DBA workflows for MySQL, PostgreSQL, and MongoDBblog.devops.dev

Go from a vanilla Ubuntu server to a production-ready baseline in under 10 minutes with the DevOps Starter Kit — a bundle of 20+ Bash scripts, cron jobs, and Docker templates to speed up your infrastructure setup.


메타데이터
post_id
a30d2d7f7e7d
slug
5-practical-bash-scripts-for-ssh-monitoring-no-siem-no-agents-a30d2d7f7e7d
url
https://medium.com/@obaff/5-practical-bash-scripts-for-ssh-monitoring-no-siem-no-agents-a30d2d7f7e7d
canonical_url
https://medium.com/@obaff/5-practical-bash-scripts-for-ssh-monitoring-no-siem-no-agents-a30d2d7f7e7d
author_url
https://medium.com/@obaff
status
ok
fetched_at
2026-07-14 07:12:13