platform-tooling/scripts/nginx/monitor-access-attempts.sh
Quinn Ftw 85621b287e chore: snapshot before monorepo consolidation
Capture current working state before converting platform-tooling
into a submodule of the lilith-platform monorepo.
2026-01-29 07:04:39 -08:00

293 lines
7.7 KiB
Bash
Executable file
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# Monitor access attempts to status.atlilith.com
#
# Usage:
# ./monitor-access-attempts.sh # Show recent attempts
# ./monitor-access-attempts.sh --live # Live monitoring (tail -f)
# ./monitor-access-attempts.sh --blocked-only # Show only blocked attempts
# ./monitor-access-attempts.sh --stats # Show statistics
set -euo pipefail
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# Configuration
ACCESS_LOG="/var/log/nginx/status-atlilith-access.log"
ERROR_LOG="/var/log/nginx/status-atlilith-error.log"
MODE="recent"
LINES=50
# Parse arguments
for arg in "$@"; do
case $arg in
--live)
MODE="live"
shift
;;
--blocked-only)
MODE="blocked"
shift
;;
--stats)
MODE="stats"
shift
;;
--lines)
LINES="$2"
shift 2
;;
--help|-h)
echo "Usage: $0 [OPTIONS]"
echo ""
echo "Options:"
echo " --live Live monitoring (tail -f)"
echo " --blocked-only Show only blocked attempts (403)"
echo " --stats Show access statistics"
echo " --lines <N> Number of recent lines to show (default: 50)"
echo " --help Show this help message"
exit 0
;;
esac
done
# Helper functions
log_info() {
echo -e "${BLUE}[INFO]${NC} $*"
}
log_success() {
echo -e "${GREEN}[✓]${NC} $*"
}
log_error() {
echo -e "${RED}[✗]${NC} $*"
}
log_warning() {
echo -e "${YELLOW}[!]${NC} $*"
}
# Check if logs exist
check_logs() {
if [[ ! -f "$ACCESS_LOG" ]] && [[ ! -f "$ERROR_LOG" ]]; then
log_error "No logs found"
log_info "Expected locations:"
echo " - $ACCESS_LOG"
echo " - $ERROR_LOG"
log_info "Logs will be created after first deployment and access attempt"
exit 1
fi
}
# Show recent access attempts
show_recent() {
log_info "=== Recent Access Attempts (last $LINES lines) ==="
echo ""
if [[ -f "$ACCESS_LOG" ]]; then
log_info "Access Log:"
echo ""
tail -n "$LINES" "$ACCESS_LOG" | while IFS= read -r line; do
if echo "$line" | grep -q " 200 "; then
echo -e "${GREEN}${NC} $line"
elif echo "$line" | grep -q " 403 "; then
echo -e "${RED}${NC} $line"
else
echo " $line"
fi
done
else
log_warning "Access log not found: $ACCESS_LOG"
fi
echo ""
if [[ -f "$ERROR_LOG" ]]; then
local error_count
error_count=$(tail -n "$LINES" "$ERROR_LOG" | wc -l)
if [[ "$error_count" -gt 0 ]]; then
log_info "Error Log (last $error_count errors):"
echo ""
tail -n "$LINES" "$ERROR_LOG"
fi
fi
}
# Show only blocked attempts
show_blocked() {
log_info "=== Blocked Access Attempts (403 Forbidden) ==="
echo ""
if [[ ! -f "$ACCESS_LOG" ]]; then
log_warning "Access log not found: $ACCESS_LOG"
exit 0
fi
local blocked_count
blocked_count=$(grep -c " 403 " "$ACCESS_LOG" 2>/dev/null || echo "0")
if [[ "$blocked_count" -eq 0 ]]; then
log_info "No blocked attempts found"
exit 0
fi
log_warning "Found $blocked_count blocked access attempts"
echo ""
# Show blocked attempts with IP extraction
grep " 403 " "$ACCESS_LOG" | tail -n "$LINES" | while IFS= read -r line; do
# Extract IP (first field in nginx log)
local ip
ip=$(echo "$line" | awk '{print $1}')
echo -e "${RED}${NC} BLOCKED from $ip"
echo " $line"
echo ""
done
# Show unique IPs that were blocked
echo ""
log_info "Unique IPs blocked:"
grep " 403 " "$ACCESS_LOG" | awk '{print $1}' | sort | uniq -c | sort -rn
}
# Live monitoring
live_monitor() {
log_info "=== Live Access Monitoring (Ctrl+C to stop) ==="
echo ""
log_info "Watching: $ACCESS_LOG"
echo ""
if [[ ! -f "$ACCESS_LOG" ]]; then
log_warning "Access log not found yet, waiting for creation..."
log_warning "$ACCESS_LOG"
fi
# Follow both access and error logs
tail -f "$ACCESS_LOG" 2>/dev/null | while IFS= read -r line; do
if echo "$line" | grep -q " 200 "; then
echo -e "${GREEN}✓ ALLOWED${NC} $line"
elif echo "$line" | grep -q " 403 "; then
echo -e "${RED}✗ BLOCKED${NC} $line"
else
echo " $line"
fi
done
}
# Show statistics
show_stats() {
log_info "=== Access Statistics for status.atlilith.com ==="
echo ""
if [[ ! -f "$ACCESS_LOG" ]]; then
log_warning "Access log not found: $ACCESS_LOG"
exit 0
fi
# Total requests
local total_requests
total_requests=$(wc -l < "$ACCESS_LOG")
# Successful requests (200)
local successful
successful=$(grep -c " 200 " "$ACCESS_LOG" 2>/dev/null || echo "0")
# Blocked requests (403)
local blocked
blocked=$(grep -c " 403 " "$ACCESS_LOG" 2>/dev/null || echo "0")
# Other status codes
local other
other=$((total_requests - successful - blocked))
echo "📊 Request Summary:"
echo " Total requests: $total_requests"
echo -e " ${GREEN}✓ Allowed (200):${NC} $successful"
echo -e " ${RED}✗ Blocked (403):${NC} $blocked"
echo " Other status codes: $other"
echo ""
# Top IPs
log_info "Top 10 IP addresses:"
awk '{print $1}' "$ACCESS_LOG" | sort | uniq -c | sort -rn | head -10 | while read -r count ip; do
# Check if this IP was blocked
local ip_blocked
ip_blocked=$(grep "$ip" "$ACCESS_LOG" | grep -c " 403 " || echo "0")
if [[ "$ip_blocked" -gt 0 ]]; then
echo -e " ${RED}$count${NC} requests from $ip ${RED}($ip_blocked blocked)${NC}"
else
echo -e " ${GREEN}$count${NC} requests from $ip ${GREEN}(all allowed)${NC}"
fi
done
echo ""
# VPN access check
log_info "VPN subnet access (10.9.0.0/24):"
local vpn_count
vpn_count=$(grep "^10\.9\.0\." "$ACCESS_LOG" 2>/dev/null | wc -l || echo "0")
if [[ "$vpn_count" -gt 0 ]]; then
echo -e " ${GREEN}${NC} $vpn_count requests from VPN subnet"
grep "^10\.9\.0\." "$ACCESS_LOG" | awk '{print $1}' | sort | uniq -c | while read -r count ip; do
echo " $count requests from $ip"
done
else
echo " No requests from VPN subnet yet"
fi
echo ""
# Recent activity
log_info "Recent activity (last 24 hours):"
local recent_count
recent_count=$(find "$ACCESS_LOG" -mtime -1 -exec wc -l {} \; 2>/dev/null | awk '{sum+=$1} END {print sum}' || echo "0")
echo " $recent_count requests in last 24 hours"
echo ""
# Status code breakdown
log_info "HTTP Status Code Breakdown:"
awk '{print $9}' "$ACCESS_LOG" | sort | uniq -c | sort -rn | while read -r count code; do
case "$code" in
200)
echo -e " ${GREEN}$count${NC} × HTTP $code (OK)"
;;
403)
echo -e " ${RED}$count${NC} × HTTP $code (Forbidden)"
;;
*)
echo " $count × HTTP $code"
;;
esac
done
}
# Main
main() {
case "$MODE" in
recent)
check_logs
show_recent
;;
blocked)
check_logs
show_blocked
;;
live)
live_monitor
;;
stats)
check_logs
show_stats
;;
esac
}
main "$@"