Skip to content

Commit 457ad0d

Browse files
committed
feat: smart ufw reloading
1 parent 5a243d2 commit 457ad0d

File tree

2 files changed

+171
-54
lines changed

2 files changed

+171
-54
lines changed

ansible/playbooks/mongo.yml

Lines changed: 85 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -348,40 +348,98 @@
348348
#!/bin/bash
349349
set -e
350350
351-
# Fetch current IP list
352-
NEW_IPS=$(curl -s https://forwardemail.net/ips/v4.txt?comments=false | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$')
353-
354-
# Get current UFW rules for MongoDB port
351+
# Configuration
355352
MONGO_PORT="${MONGO_PORT:-27017}"
356-
CURRENT_IPS=$(ufw status | grep "${MONGO_PORT}/tcp" | grep "ALLOW" | awk '{print $3}' | sort -u)
353+
IP_LIST_URL="https://forwardemail.net/ips/v4.txt?comments=false"
354+
COMMENT="Auto-whitelist MongoDB"
355+
SERVICE_NAME="MongoDB"
356+
POSTFIX_RCPTS="${POSTFIX_RCPTS:[email protected]}"
357+
358+
echo "[$(date -Iseconds)] Fetching IP whitelist..."
359+
NEW_IPS=$(curl -s "$IP_LIST_URL" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' | sort -u)
360+
361+
if [ -z "$NEW_IPS" ]; then
362+
echo "[$(date -Iseconds)] ERROR: Failed to fetch IP list or list is empty"
363+
exit 1
364+
fi
365+
366+
# Get current IPs from UFW
367+
CURRENT_IPS=$(ufw status | grep "${MONGO_PORT}/tcp" | grep "$COMMENT" | awk '{print $3}' | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' | sort -u)
368+
369+
# Calculate diff
370+
TO_ADD=$(comm -13 <(echo "$CURRENT_IPS") <(echo "$NEW_IPS"))
371+
TO_REMOVE=$(comm -23 <(echo "$CURRENT_IPS") <(echo "$NEW_IPS"))
372+
373+
# Check if changes needed
374+
if [ -z "$TO_ADD" ] && [ -z "$TO_REMOVE" ]; then
375+
echo "[$(date -Iseconds)] No changes needed"
376+
exit 0
377+
fi
357378
358-
# Track if changes were made
359-
CHANGED=0
379+
echo "[$(date -Iseconds)] Changes detected - updating UFW rules..."
380+
381+
# Remove old IPs (delete from highest rule number to lowest)
382+
REMOVED_COUNT=0
383+
if [ -n "$TO_REMOVE" ]; then
384+
for ip in $TO_REMOVE; do
385+
RULE_NUMS=$(ufw status numbered | grep "${MONGO_PORT}/tcp" | grep "$ip" | grep "$COMMENT" | grep -oP '^\[\s*\K[0-9]+' | sort -rn)
386+
for rule_num in $RULE_NUMS; do
387+
echo "y" | ufw delete "$rule_num" > /dev/null 2>&1
388+
REMOVED_COUNT=$((REMOVED_COUNT + 1)) done
389+
done
390+
fi
360391
361392
# Add new IPs
362-
for ip in $NEW_IPS; do
363-
if ! echo "$CURRENT_IPS" | grep -q "^${ip}$"; then
364-
ufw allow from "$ip" to any port "$MONGO_PORT" proto tcp comment "Auto-whitelist MongoDB"
365-
CHANGED=1
366-
fi
367-
done
393+
ADDED_COUNT=0
394+
if [ -n "$TO_ADD" ]; then
395+
for ip in $TO_ADD; do
396+
ufw allow from "$ip" to any port "$MONGO_PORT" proto tcp comment "$COMMENT" > /dev/null 2>&1
397+
ADDED_COUNT=$((ADDED_COUNT + 1))
398+
done
399+
fi
368400
369-
# Remove old IPs (not in new list)
370-
for ip in $CURRENT_IPS; do
371-
if ! echo "$NEW_IPS" | grep -q "^${ip}$"; then
372-
# Find and delete the rule
373-
RULE_NUM=$(ufw status numbered | grep "${MONGO_PORT}/tcp" | grep "$ip" | grep -oP '^\[\s*\K[0-9]+' | head -1)
374-
if [ -n "$RULE_NUM" ]; then
375-
echo "y" | ufw delete "$RULE_NUM"
376-
CHANGED=1
377-
fi
378-
fi
379-
done
401+
# Reload UFW
402+
ufw reload > /dev/null 2>&1
380403
381-
# Reload UFW if changes were made
382-
if [ $CHANGED -eq 1 ]; then
383-
ufw reload
404+
# Build email report
405+
TOTAL_IPS=$(echo "$NEW_IPS" | wc -l)
406+
ADDED_LIST=$(echo "$TO_ADD" | sed 's/^/ - /' | head -20)
407+
REMOVED_LIST=$(echo "$TO_REMOVE" | sed 's/^/ - /' | head -20)
408+
409+
if [ $(echo "$TO_ADD" | wc -l) -gt 20 ]; then
410+
ADDED_LIST="$ADDED_LIST\n ... and $(($(echo "$TO_ADD" | wc -l) - 20)) more"
384411
fi
412+
413+
if [ $(echo "$TO_REMOVE" | wc -l) -gt 20 ]; then
414+
REMOVED_LIST="$REMOVED_LIST\n ... and $(($(echo "$TO_REMOVE" | wc -l) - 20)) more"
415+
fi
416+
417+
REPORT="UFW Whitelist Changes for $SERVICE_NAME
418+
Timestamp: $(date -Iseconds)
419+
420+
Added IPs ($ADDED_COUNT):
421+
$ADDED_LIST
422+
423+
Removed IPs ($REMOVED_COUNT):
424+
$REMOVED_LIST
425+
426+
Summary:
427+
- Total added: $ADDED_COUNT
428+
- Total removed: $REMOVED_COUNT
429+
- Current total: $TOTAL_IPS IPs whitelisted
430+
431+
Server: $(hostname)
432+
Port: $MONGO_PORT/tcp
433+
434+
View logs: sudo journalctl -u mongo-ufw-whitelist-update.service -n 50"
435+
436+
# Send email report
437+
/usr/local/bin/send-rate-limited-email.sh \
438+
"ufw-whitelist-mongo" \
439+
"[UFW] Whitelist Updated: $SERVICE_NAME (Port $MONGO_PORT)" \
440+
"$REPORT"
441+
442+
echo "[$(date -Iseconds)] UFW whitelist updated (added: $ADDED_COUNT, removed: $REMOVED_COUNT)"
385443
386444
# Create systemd timer for UFW whitelist updates
387445
- name: Create UFW whitelist update systemd service

ansible/playbooks/redis.yml

Lines changed: 86 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -630,40 +630,99 @@
630630
#!/bin/bash
631631
set -e
632632
633-
# Fetch current IP list
634-
NEW_IPS=$(curl -s https://forwardemail.net/ips/v4.txt?comments=false | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$')
635-
636-
# Get current UFW rules for Redis TLS port
633+
# Configuration
637634
REDIS_PORT="${REDIS_PORT:-6380}"
638-
CURRENT_IPS=$(ufw status | grep "${REDIS_PORT}/tcp" | grep "ALLOW" | awk '{print $3}' | sort -u)
635+
IP_LIST_URL="https://forwardemail.net/ips/v4.txt?comments=false"
636+
COMMENT="Auto-whitelist Redis TLS"
637+
SERVICE_NAME="Redis"
638+
POSTFIX_RCPTS="${POSTFIX_RCPTS:[email protected]}"
639+
640+
echo "[$(date -Iseconds)] Fetching IP whitelist..."
641+
NEW_IPS=$(curl -s "$IP_LIST_URL" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' | sort -u)
642+
643+
if [ -z "$NEW_IPS" ]; then
644+
echo "[$(date -Iseconds)] ERROR: Failed to fetch IP list or list is empty"
645+
exit 1
646+
fi
647+
648+
# Get current IPs from UFW
649+
CURRENT_IPS=$(ufw status | grep "${REDIS_PORT}/tcp" | grep "$COMMENT" | awk '{print $3}' | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' | sort -u)
650+
651+
# Calculate diff
652+
TO_ADD=$(comm -13 <(echo "$CURRENT_IPS") <(echo "$NEW_IPS"))
653+
TO_REMOVE=$(comm -23 <(echo "$CURRENT_IPS") <(echo "$NEW_IPS"))
654+
655+
# Check if changes needed
656+
if [ -z "$TO_ADD" ] && [ -z "$TO_REMOVE" ]; then
657+
echo "[$(date -Iseconds)] No changes needed"
658+
exit 0
659+
fi
639660
640-
# Track if changes were made
641-
CHANGED=0
661+
echo "[$(date -Iseconds)] Changes detected - updating UFW rules..."
662+
663+
# Remove old IPs (delete from highest rule number to lowest)
664+
REMOVED_COUNT=0
665+
if [ -n "$TO_REMOVE" ]; then
666+
for ip in $TO_REMOVE; do
667+
RULE_NUMS=$(ufw status numbered | grep "${REDIS_PORT}/tcp" | grep "$ip" | grep "$COMMENT" | grep -oP '^\[\s*\K[0-9]+' | sort -rn)
668+
for rule_num in $RULE_NUMS; do
669+
echo "y" | ufw delete "$rule_num" > /dev/null 2>&1
670+
REMOVED_COUNT=$((REMOVED_COUNT + 1))
671+
done
672+
done
673+
fi
642674
643675
# Add new IPs
644-
for ip in $NEW_IPS; do
645-
if ! echo "$CURRENT_IPS" | grep -q "^${ip}$"; then
646-
ufw allow from "$ip" to any port "$REDIS_PORT" proto tcp comment "Auto-whitelist Redis TLS"
647-
CHANGED=1
648-
fi
649-
done
676+
ADDED_COUNT=0
677+
if [ -n "$TO_ADD" ]; then
678+
for ip in $TO_ADD; do
679+
ufw allow from "$ip" to any port "$REDIS_PORT" proto tcp comment "$COMMENT" > /dev/null 2>&1
680+
ADDED_COUNT=$((ADDED_COUNT + 1))
681+
done
682+
fi
650683
651-
# Remove old IPs (not in new list)
652-
for ip in $CURRENT_IPS; do
653-
if ! echo "$NEW_IPS" | grep -q "^${ip}$"; then
654-
# Find and delete the rule
655-
RULE_NUM=$(ufw status numbered | grep "${REDIS_PORT}/tcp" | grep "$ip" | grep -oP '^\[\s*\K[0-9]+' | head -1)
656-
if [ -n "$RULE_NUM" ]; then
657-
echo "y" | ufw delete "$RULE_NUM"
658-
CHANGED=1
659-
fi
660-
fi
661-
done
684+
# Reload UFW
685+
ufw reload > /dev/null 2>&1
662686
663-
# Reload UFW if changes were made
664-
if [ $CHANGED -eq 1 ]; then
665-
ufw reload
687+
# Build email report
688+
TOTAL_IPS=$(echo "$NEW_IPS" | wc -l)
689+
ADDED_LIST=$(echo "$TO_ADD" | sed 's/^/ - /' | head -20)
690+
REMOVED_LIST=$(echo "$TO_REMOVE" | sed 's/^/ - /' | head -20)
691+
692+
if [ $(echo "$TO_ADD" | wc -l) -gt 20 ]; then
693+
ADDED_LIST="$ADDED_LIST\n ... and $(($(echo "$TO_ADD" | wc -l) - 20)) more"
666694
fi
695+
696+
if [ $(echo "$TO_REMOVE" | wc -l) -gt 20 ]; then
697+
REMOVED_LIST="$REMOVED_LIST\n ... and $(($(echo "$TO_REMOVE" | wc -l) - 20)) more"
698+
fi
699+
700+
REPORT="UFW Whitelist Changes for $SERVICE_NAME
701+
Timestamp: $(date -Iseconds)
702+
703+
Added IPs ($ADDED_COUNT):
704+
$ADDED_LIST
705+
706+
Removed IPs ($REMOVED_COUNT):
707+
$REMOVED_LIST
708+
709+
Summary:
710+
- Total added: $ADDED_COUNT
711+
- Total removed: $REMOVED_COUNT
712+
- Current total: $TOTAL_IPS IPs whitelisted
713+
714+
Server: $(hostname)
715+
Port: $REDIS_PORT/tcp
716+
717+
View logs: sudo journalctl -u redis-ufw-whitelist-update.service -n 50"
718+
719+
# Send email report
720+
/usr/local/bin/send-rate-limited-email.sh \
721+
"ufw-whitelist-redis" \
722+
"[UFW] Whitelist Updated: $SERVICE_NAME (Port $REDIS_PORT)" \
723+
"$REPORT"
724+
725+
echo "[$(date -Iseconds)] UFW whitelist updated (added: $ADDED_COUNT, removed: $REMOVED_COUNT)"
667726
668727
# Create systemd timer for UFW whitelist updates
669728
- name: Create UFW whitelist update systemd service

0 commit comments

Comments
 (0)