Skip to content

Monitoring & Logging

Configure SSH server logging, centralized log collection, and security alerts.


SSH Server Logging

Log Locations

OS Log File
Ubuntu/Debian /var/log/auth.log
CentOS/RHEL /var/log/secure
macOS log show --predicate 'process == "sshd"'

Configure Log Level

Edit /etc/ssh/sshd_config:

LogLevel VERBOSE    # Recommended for security
SyslogFacility AUTH

Restart: sudo systemctl restart sshd

Log Entry Examples

Successful login:

Dec 21 10:15:23 server sshd[12345]: Accepted publickey for tunneluser from 203.0.113.50 port 54321 ssh2

Failed login:

Dec 21 10:20:15 server sshd[12346]: Failed password for invalid user admin from 198.51.100.10 port 12345 ssh2

Port forwarding:

Dec 21 10:25:31 server sshd[12347]: Forwarding connection to localhost port 5432

Log Analysis

View Recent Activity

# Last 50 SSH entries
sudo tail -50 /var/log/auth.log | grep sshd

# Follow in real-time
sudo tail -f /var/log/auth.log | grep sshd

# Search by user or IP
sudo grep "tunneluser" /var/log/auth.log
sudo grep "203.0.113.50" /var/log/auth.log

Failed Login Attempts

# Today's failed attempts
sudo grep "Failed password" /var/log/auth.log | grep "$(date +%b\ %d)"

# Count by IP (find attackers)
sudo grep "Failed password" /var/log/auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn

Successful Logins

# Today's successful logins
sudo grep "Accepted publickey" /var/log/auth.log | grep "$(date +%b\ %d)"

# Count by user
sudo grep "Accepted publickey" /var/log/auth.log | awk '{print $9}' | sort | uniq -c

Port Forwarding

sudo grep "Forwarding connection" /var/log/auth.log

CloudWatch Logs (AWS)

Install Agent

Amazon Linux:

sudo yum install -y amazon-cloudwatch-agent

Ubuntu:

wget https://s3.amazonaws.com/amazoncloudwatch-agent/ubuntu/amd64/latest/amazon-cloudwatch-agent.deb
sudo dpkg -i amazon-cloudwatch-agent.deb

IAM Permissions

Attach to EC2 instance role:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "arn:aws:logs:*:*:log-group:/ssh/servers/*"
        }
    ]
}

Configure Agent

Create /opt/aws/amazon-cloudwatch-agent/etc/config.json:

{
    "logs": {
        "logs_collected": {
            "files": {
                "collect_list": [
                    {
                        "file_path": "/var/log/auth.log",
                        "log_group_name": "/ssh/servers/production",
                        "log_stream_name": "{instance_id}/auth",
                        "timestamp_format": "%b %d %H:%M:%S"
                    }
                ]
            }
        }
    }
}

Start:

sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl \
  -a fetch-config -m ec2 -s \
  -c file:/opt/aws/amazon-cloudwatch-agent/etc/config.json

Query Logs

# Tail logs
aws logs tail /ssh/servers/production --follow

# Search for failures
aws logs tail /ssh/servers/production --filter-pattern "Failed password" --since 1h

CloudWatch Insights

-- Failed attempts by IP
fields @message
| filter @message like /Failed password/
| parse @message "from * port" as ip
| stats count() by ip
| sort count desc

-- Successful logins
fields @timestamp, @message
| filter @message like /Accepted publickey/
| parse @message "for * from * port" as user, ip
| display @timestamp, user, ip

Centralized Syslog

Send to Remote Server

Edit /etc/rsyslog.conf:

# Send SSH logs to central server (TCP)
auth.* @@syslog.example.com:514

Restart: sudo systemctl restart rsyslog

Receive on Central Server

# Enable TCP reception
module(load="imtcp")
input(type="imtcp" port="514")

# Separate files per host
$template RemoteHost,"/var/log/remote/%HOSTNAME%/%PROGRAMNAME%.log"
*.* ?RemoteHost

Security Alerting

Monitoring Script

#!/bin/bash
# /usr/local/bin/ssh-monitor.sh

LOG_FILE="/var/log/auth.log"
FAILED_THRESHOLD=5
SLACK_WEBHOOK="https://hooks.slack.com/services/YOUR/WEBHOOK"

send_alert() {
    curl -X POST -H 'Content-type: application/json' \
        --data "{\"text\":\"SSH Alert: $1\"}" "$SLACK_WEBHOOK"
}

tail -f "$LOG_FILE" | while read line; do
    if echo "$line" | grep -q "Failed password"; then
        IP=$(echo "$line" | awk '{print $(NF-3)}')
        COUNT=$(grep "Failed password.*$IP" "$LOG_FILE" | tail -n $FAILED_THRESHOLD | wc -l)

        if [[ $COUNT -ge $FAILED_THRESHOLD ]]; then
            send_alert "Brute force from $IP ($COUNT attempts)"
        fi
    fi
done

Run as service (/etc/systemd/system/ssh-monitor.service):

[Unit]
Description=SSH Security Monitor
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/ssh-monitor.sh
Restart=always

[Install]
WantedBy=multi-user.target
sudo chmod +x /usr/local/bin/ssh-monitor.sh
sudo systemctl enable ssh-monitor
sudo systemctl start ssh-monitor

Log Rotation

Create /etc/logrotate.d/ssh-custom:

/var/log/auth.log /var/log/secure {
    daily
    rotate 90
    compress
    delaycompress
    missingok
    notifempty
    create 0640 root adm
    postrotate
        systemctl reload rsyslog > /dev/null 2>&1 || true
    endscript
}

Audit Report Script

#!/bin/bash
# /usr/local/bin/ssh-audit-report.sh

REPORT="/var/reports/ssh-audit-$(date +%Y%m%d).txt"
LOG="/var/log/auth.log"
mkdir -p /var/reports

cat > "$REPORT" <<EOF
SSH Security Audit Report - $(date)
====================================

SUCCESSFUL LOGINS:
$(grep "Accepted publickey" "$LOG" | wc -l) total

Top users:
$(grep "Accepted publickey" "$LOG" | awk '{print $9}' | sort | uniq -c | sort -rn | head -5)

FAILED ATTEMPTS:
$(grep "Failed password" "$LOG" | wc -l) total

Top attacking IPs:
$(grep "Failed password" "$LOG" | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head -5)

PORT FORWARDING:
$(grep "Forwarding connection" "$LOG" | wc -l) requests
EOF

cat "$REPORT"

Schedule monthly: 0 0 1 * * /usr/local/bin/ssh-audit-report.sh


Troubleshooting

Logs Not Appearing

# Check syslog running
sudo systemctl status rsyslog

# Check permissions
ls -la /var/log/auth.log

# Check SSH log level
sudo grep LogLevel /etc/ssh/sshd_config

CloudWatch Not Sending

# Check agent status
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -m ec2 -a query

# Check agent logs
sudo tail -f /opt/aws/amazon-cloudwatch-agent/logs/amazon-cloudwatch-agent.log

# Restart
sudo systemctl restart amazon-cloudwatch-agent

Next Steps