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:
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:
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¶
CloudWatch Logs (AWS)¶
Install Agent¶
Amazon Linux:
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:
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¶
- Server Security - Hardening, 2FA, fail2ban
- SSH Server Setup - Basic configuration
- AWS Configuration - Session Manager setup