Sync all scripts from website downloads — 352 scripts total
Includes updated JS challenge scripts with Claude-User whitelist, same-site referer bypass, Blackbox-Exporter allowed bot, and all new exporters, cheat sheets, and automation scripts.
This commit is contained in:
Executable
+607
@@ -0,0 +1,607 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#########################################################################################
|
||||
#### nsg-auditor.sh — Audit Azure NSGs for risky inbound rules and misconfigurations ####
|
||||
#### Finds open ports, missing NSGs, overly permissive rules, and unused NSGs ####
|
||||
#### Requires: bash 4+, az, jq ####
|
||||
#### ####
|
||||
#### Author: Phil Connor ####
|
||||
#### Contact: contact@mylinux.work ####
|
||||
#### License: MIT ####
|
||||
#### Version 1.01 ####
|
||||
#### ####
|
||||
#### Usage: ####
|
||||
#### ./nsg-auditor.sh --full ####
|
||||
#### ####
|
||||
#### See --help for all options. ####
|
||||
#########################################################################################
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# ── Colors (pre-initialized) ─────────────────────────────────────────
|
||||
RED="" GREEN="" YELLOW="" BLUE="" CYAN="" BOLD="" DIM="" RESET=""
|
||||
|
||||
setup_colors() {
|
||||
if [[ "${COLOR:-auto}" == "never" ]]; then
|
||||
return
|
||||
fi
|
||||
if [[ "${COLOR:-auto}" == "always" ]] || [[ -t 1 ]]; then
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[0;33m'
|
||||
BLUE='\033[0;34m'
|
||||
CYAN='\033[0;36m'
|
||||
BOLD='\033[1m'
|
||||
DIM='\033[2m'
|
||||
RESET='\033[0m'
|
||||
fi
|
||||
}
|
||||
|
||||
# ── Logging ───────────────────────────────────────────────────────────
|
||||
log() { echo -e "${BLUE}[INFO]${RESET} $*"; }
|
||||
warn() { echo -e "${YELLOW}[WARN]${RESET} $*" >&2; }
|
||||
err() { echo -e "${RED}[ERROR]${RESET} $*" >&2; }
|
||||
verbose() { if [[ "$VERBOSE" == "true" ]]; then echo -e "${DIM}[DEBUG]${RESET} $*"; fi; }
|
||||
die() { err "$*"; exit 1; }
|
||||
|
||||
# ── Severity counters ────────────────────────────────────────────────
|
||||
TOTAL_CRIT=0
|
||||
TOTAL_WARN=0
|
||||
TOTAL_INFO=0
|
||||
TOTAL_OK=0
|
||||
|
||||
flag_crit() { ((TOTAL_CRIT++)) || true; }
|
||||
flag_warn() { ((TOTAL_WARN++)) || true; }
|
||||
flag_info() { ((TOTAL_INFO++)) || true; }
|
||||
flag_ok() { ((TOTAL_OK++)) || true; }
|
||||
|
||||
# ── Defaults ──────────────────────────────────────────────────────────
|
||||
RUN_MODE=""
|
||||
DANGEROUS_PORTS="${DANGEROUS_PORTS:-22,3389,3306,5432,1433,6379,27017,9200,8080,8443}"
|
||||
VERBOSE="${VERBOSE:-false}"
|
||||
COLOR="${COLOR:-auto}"
|
||||
RESOURCE_GROUP="${RESOURCE_GROUP:-}"
|
||||
SUBSCRIPTION="${SUBSCRIPTION:-}"
|
||||
|
||||
# ── State ─────────────────────────────────────────────────────────────
|
||||
SCRIPT_NAME="$(basename "$0")"
|
||||
readonly SCRIPT_NAME
|
||||
START_TIME=""
|
||||
|
||||
# ── Azure CLI helpers ────────────────────────────────────────────────
|
||||
az_cmd() {
|
||||
local cmd=("az" "$@")
|
||||
if [[ -n "$SUBSCRIPTION" ]]; then
|
||||
cmd+=(--subscription "$SUBSCRIPTION")
|
||||
fi
|
||||
verbose "Running: ${cmd[*]}"
|
||||
"${cmd[@]}"
|
||||
}
|
||||
|
||||
check_credentials() {
|
||||
az account show &>/dev/null || die "Not logged in to Azure CLI — run 'az login' first"
|
||||
}
|
||||
|
||||
check_deps() {
|
||||
command -v az &>/dev/null || die "az (Azure CLI) is required"
|
||||
command -v jq &>/dev/null || die "jq is required"
|
||||
}
|
||||
|
||||
# ── Port-to-service mapping ─────────────────────────────────────────
|
||||
port_to_service() {
|
||||
local port="$1"
|
||||
case "$port" in
|
||||
22) echo "SSH" ;;
|
||||
80) echo "HTTP" ;;
|
||||
443) echo "HTTPS" ;;
|
||||
3306) echo "MySQL" ;;
|
||||
5432) echo "PostgreSQL" ;;
|
||||
1433) echo "MSSQL" ;;
|
||||
3389) echo "RDP" ;;
|
||||
6379) echo "Redis" ;;
|
||||
27017) echo "MongoDB" ;;
|
||||
9200) echo "Elasticsearch" ;;
|
||||
8080) echo "HTTP-Alt" ;;
|
||||
8443) echo "HTTPS-Alt" ;;
|
||||
53) echo "DNS" ;;
|
||||
25) echo "SMTP" ;;
|
||||
5900) echo "VNC" ;;
|
||||
11211) echo "Memcached" ;;
|
||||
2379) echo "etcd" ;;
|
||||
9090) echo "Prometheus" ;;
|
||||
*) echo "" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# ── Check if port is in dangerous list ───────────────────────────────
|
||||
is_dangerous_port() {
|
||||
local port="$1"
|
||||
local IFS=','
|
||||
for dp in $DANGEROUS_PORTS; do
|
||||
if [[ "$port" == "$dp" ]]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# ── NSG helpers ──────────────────────────────────────────────────────
|
||||
get_all_nsgs() {
|
||||
local nsg_args=("network" "nsg" "list" "-o" "json")
|
||||
if [[ -n "$RESOURCE_GROUP" ]]; then
|
||||
nsg_args+=(--resource-group "$RESOURCE_GROUP")
|
||||
fi
|
||||
az_cmd "${nsg_args[@]}"
|
||||
}
|
||||
|
||||
get_all_nics() {
|
||||
local nic_args=("network" "nic" "list" "-o" "json")
|
||||
if [[ -n "$RESOURCE_GROUP" ]]; then
|
||||
nic_args+=(--resource-group "$RESOURCE_GROUP")
|
||||
fi
|
||||
az_cmd "${nic_args[@]}"
|
||||
}
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# OPEN PORTS AUDIT
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
audit_open_ports() {
|
||||
log "Auditing NSG rules for dangerous open ports..."
|
||||
log "Dangerous ports: ${DANGEROUS_PORTS}"
|
||||
echo ""
|
||||
|
||||
printf " %-20s %-22s %-8s %-8s %-18s %-12s %s\n" \
|
||||
"NSG" "RULE" "PORT" "PROTO" "SOURCE" "SERVICE" "SEVERITY"
|
||||
printf " %s\n" "$(printf '%.0s─' {1..100})"
|
||||
|
||||
local nsg_json
|
||||
nsg_json=$(get_all_nsgs)
|
||||
|
||||
echo "$nsg_json" | jq -c '.[]' 2>/dev/null | while IFS= read -r nsg; do
|
||||
local nsg_name
|
||||
nsg_name=$(echo "$nsg" | jq -r '.name // "unnamed"' 2>/dev/null)
|
||||
|
||||
echo "$nsg" | jq -c '.securityRules[]? // empty' 2>/dev/null | while IFS= read -r rule; do
|
||||
local rule_name direction access priority protocol port_str source_addr
|
||||
rule_name=$(echo "$rule" | jq -r '.name // "unnamed"' 2>/dev/null)
|
||||
direction=$(echo "$rule" | jq -r '.direction // "Inbound"' 2>/dev/null)
|
||||
access=$(echo "$rule" | jq -r '.access // "Deny"' 2>/dev/null)
|
||||
priority=$(echo "$rule" | jq -r '.priority // 65000' 2>/dev/null)
|
||||
protocol=$(echo "$rule" | jq -r '.protocol // "*"' 2>/dev/null)
|
||||
port_str=$(echo "$rule" | jq -r '.destinationPortRange // ""' 2>/dev/null)
|
||||
source_addr=$(echo "$rule" | jq -r '.sourceAddressPrefix // ""' 2>/dev/null)
|
||||
|
||||
[[ "$direction" != "Inbound" ]] && continue
|
||||
[[ "$access" != "Allow" ]] && continue
|
||||
[[ "$priority" -ge 65000 ]] && continue
|
||||
|
||||
if [[ "$source_addr" != "*" && "$source_addr" != "Internet" && "$source_addr" != "0.0.0.0/0" ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ "$port_str" == "*" ]]; then
|
||||
local IFS=','
|
||||
for dp in $DANGEROUS_PORTS; do
|
||||
local svc
|
||||
svc=$(port_to_service "$dp")
|
||||
printf " %-20s %-22s %-8s %-8s %-18s %-12s %b%s%b\n" \
|
||||
"${nsg_name:0:18}" "${rule_name:0:20}" "$dp" "$protocol" \
|
||||
"$source_addr" "${svc:-unknown}" "$RED" "CRITICAL" "$RESET"
|
||||
flag_crit
|
||||
done
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ "$port_str" == *-* ]]; then
|
||||
local range_start range_end
|
||||
range_start="${port_str%-*}"
|
||||
range_end="${port_str#*-}"
|
||||
local IFS=','
|
||||
for dp in $DANGEROUS_PORTS; do
|
||||
if [[ "$dp" -ge "$range_start" && "$dp" -le "$range_end" ]]; then
|
||||
local svc
|
||||
svc=$(port_to_service "$dp")
|
||||
printf " %-20s %-22s %-8s %-8s %-18s %-12s %b%s%b\n" \
|
||||
"${nsg_name:0:18}" "${rule_name:0:20}" "$dp" "$protocol" \
|
||||
"$source_addr" "${svc:-unknown}" "$RED" "CRITICAL" "$RESET"
|
||||
flag_crit
|
||||
fi
|
||||
done
|
||||
continue
|
||||
fi
|
||||
|
||||
if is_dangerous_port "$port_str"; then
|
||||
local svc
|
||||
svc=$(port_to_service "$port_str")
|
||||
printf " %-20s %-22s %-8s %-8s %-18s %-12s %b%s%b\n" \
|
||||
"${nsg_name:0:18}" "${rule_name:0:20}" "$port_str" "$protocol" \
|
||||
"$source_addr" "${svc:-unknown}" "$RED" "CRITICAL" "$RESET"
|
||||
flag_crit
|
||||
elif [[ "$port_str" == "80" || "$port_str" == "443" ]]; then
|
||||
local svc
|
||||
svc=$(port_to_service "$port_str")
|
||||
printf " %-20s %-22s %-8s %-8s %-18s %-12s %b%s%b\n" \
|
||||
"${nsg_name:0:18}" "${rule_name:0:20}" "$port_str" "$protocol" \
|
||||
"$source_addr" "${svc:-$port_str}" "$CYAN" "INFO" "$RESET"
|
||||
flag_info
|
||||
else
|
||||
local svc
|
||||
svc=$(port_to_service "$port_str")
|
||||
printf " %-20s %-22s %-8s %-8s %-18s %-12s %b%s%b\n" \
|
||||
"${nsg_name:0:18}" "${rule_name:0:20}" "$port_str" "$protocol" \
|
||||
"$source_addr" "${svc:-$port_str}" "$YELLOW" "WARN" "$RESET"
|
||||
flag_warn
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# UNPROTECTED NICs
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
audit_unprotected() {
|
||||
log "Checking for NICs without NSG..."
|
||||
echo ""
|
||||
|
||||
printf " %-28s %-28s %-16s %s\n" \
|
||||
"NIC_NAME" "RESOURCE_GROUP" "IP_CONFIG" "NSG"
|
||||
printf " %s\n" "$(printf '%.0s─' {1..95})"
|
||||
|
||||
local nic_json
|
||||
nic_json=$(get_all_nics)
|
||||
|
||||
echo "$nic_json" | jq -c '.[]' 2>/dev/null | while IFS= read -r nic; do
|
||||
local nic_name nic_rg nsg_id ip_config
|
||||
nic_name=$(echo "$nic" | jq -r '.name // "unknown"' 2>/dev/null)
|
||||
nic_rg=$(echo "$nic" | jq -r '.resourceGroup // "unknown"' 2>/dev/null)
|
||||
nsg_id=$(echo "$nic" | jq -r '.networkSecurityGroup.id // ""' 2>/dev/null)
|
||||
ip_config=$(echo "$nic" | jq -r '.ipConfigurations[0].name // "N/A"' 2>/dev/null)
|
||||
|
||||
if [[ -z "$nsg_id" || "$nsg_id" == "null" ]]; then
|
||||
printf " %-28s %-28s %-16s %b%s%b\n" \
|
||||
"${nic_name:0:26}" "${nic_rg:0:26}" "${ip_config:0:14}" \
|
||||
"$RED" "NONE — UNPROTECTED" "$RESET"
|
||||
flag_crit
|
||||
else
|
||||
local nsg_short
|
||||
nsg_short=$(basename "$nsg_id")
|
||||
printf " %-28s %-28s %-16s %b%s%b\n" \
|
||||
"${nic_name:0:26}" "${nic_rg:0:26}" "${ip_config:0:14}" \
|
||||
"$GREEN" "✓ ${nsg_short:0:20}" "$RESET"
|
||||
flag_ok
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# PERMISSIVE RULES AUDIT
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
audit_permissive() {
|
||||
log "Auditing overly permissive NSG rules..."
|
||||
echo ""
|
||||
|
||||
printf " %-20s %-22s %-10s %-8s %-18s %-14s %s\n" \
|
||||
"NSG" "RULE" "PORTS" "PROTO" "SOURCE" "ISSUE" "SEVERITY"
|
||||
printf " %s\n" "$(printf '%.0s─' {1..105})"
|
||||
|
||||
local nsg_json
|
||||
nsg_json=$(get_all_nsgs)
|
||||
|
||||
echo "$nsg_json" | jq -c '.[]' 2>/dev/null | while IFS= read -r nsg; do
|
||||
local nsg_name
|
||||
nsg_name=$(echo "$nsg" | jq -r '.name // "unnamed"' 2>/dev/null)
|
||||
|
||||
echo "$nsg" | jq -c '.securityRules[]? // empty' 2>/dev/null | while IFS= read -r rule; do
|
||||
local rule_name direction access priority port_str protocol source_addr
|
||||
rule_name=$(echo "$rule" | jq -r '.name // "unnamed"' 2>/dev/null)
|
||||
direction=$(echo "$rule" | jq -r '.direction // "Inbound"' 2>/dev/null)
|
||||
access=$(echo "$rule" | jq -r '.access // "Deny"' 2>/dev/null)
|
||||
priority=$(echo "$rule" | jq -r '.priority // 65000' 2>/dev/null)
|
||||
port_str=$(echo "$rule" | jq -r '.destinationPortRange // ""' 2>/dev/null)
|
||||
protocol=$(echo "$rule" | jq -r '.protocol // "*"' 2>/dev/null)
|
||||
source_addr=$(echo "$rule" | jq -r '.sourceAddressPrefix // ""' 2>/dev/null)
|
||||
|
||||
[[ "$direction" != "Inbound" ]] && continue
|
||||
[[ "$access" != "Allow" ]] && continue
|
||||
[[ "$priority" -ge 65000 ]] && continue
|
||||
|
||||
if [[ "$port_str" == "*" ]] && [[ "$source_addr" == "*" || "$source_addr" == "Internet" ]]; then
|
||||
printf " %-20s %-22s %-10s %-8s %-18s %-14s %b%s%b\n" \
|
||||
"${nsg_name:0:18}" "${rule_name:0:20}" "ALL" "$protocol" \
|
||||
"$source_addr" "all-ports" "$RED" "CRITICAL" "$RESET"
|
||||
flag_crit
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# UNUSED NSGs
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
audit_unused() {
|
||||
log "Checking for unused NSGs..."
|
||||
echo ""
|
||||
|
||||
printf " %-28s %-28s %-8s %s\n" \
|
||||
"NSG_NAME" "RESOURCE_GROUP" "RULES" "STATUS"
|
||||
printf " %s\n" "$(printf '%.0s─' {1..75})"
|
||||
|
||||
local nsg_json
|
||||
nsg_json=$(get_all_nsgs)
|
||||
|
||||
echo "$nsg_json" | jq -c '.[]' 2>/dev/null | while IFS= read -r nsg; do
|
||||
local nsg_name nsg_rg rule_count nic_count subnet_count
|
||||
nsg_name=$(echo "$nsg" | jq -r '.name // "unnamed"' 2>/dev/null)
|
||||
nsg_rg=$(echo "$nsg" | jq -r '.resourceGroup // "unknown"' 2>/dev/null)
|
||||
rule_count=$(echo "$nsg" | jq '[.securityRules[]?] | length' 2>/dev/null || echo 0)
|
||||
nic_count=$(echo "$nsg" | jq '[.networkInterfaces[]?] | length' 2>/dev/null || echo 0)
|
||||
subnet_count=$(echo "$nsg" | jq '[.subnets[]?] | length' 2>/dev/null || echo 0)
|
||||
|
||||
if [[ "$nic_count" -eq 0 && "$subnet_count" -eq 0 ]]; then
|
||||
printf " %-28s %-28s %-8s %b%s%b\n" \
|
||||
"${nsg_name:0:26}" "${nsg_rg:0:26}" "$rule_count" \
|
||||
"$YELLOW" "UNUSED" "$RESET"
|
||||
flag_warn
|
||||
else
|
||||
verbose "NSG ${nsg_name}: attached to ${nic_count} NIC(s), ${subnet_count} subnet(s)"
|
||||
flag_ok
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# LIST ALL RULES
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
list_rules() {
|
||||
log "Listing all custom NSG rules..."
|
||||
echo ""
|
||||
|
||||
printf " %-18s %-20s %-8s %-8s %-8s %-12s %-18s %s\n" \
|
||||
"NSG" "RULE" "DIR" "ACCESS" "PROTO" "PORTS" "SOURCE/DEST" "SERVICE"
|
||||
printf " %s\n" "$(printf '%.0s─' {1..105})"
|
||||
|
||||
local nsg_json
|
||||
nsg_json=$(get_all_nsgs)
|
||||
|
||||
echo "$nsg_json" | jq -c '.[]' 2>/dev/null | while IFS= read -r nsg; do
|
||||
local nsg_name
|
||||
nsg_name=$(echo "$nsg" | jq -r '.name // "unnamed"' 2>/dev/null)
|
||||
|
||||
echo "$nsg" | jq -c '.securityRules[]? // empty' 2>/dev/null | while IFS= read -r rule; do
|
||||
local rule_name direction access protocol port_str source_addr dest_addr priority
|
||||
rule_name=$(echo "$rule" | jq -r '.name // "unnamed"' 2>/dev/null)
|
||||
direction=$(echo "$rule" | jq -r '.direction // "Inbound"' 2>/dev/null)
|
||||
access=$(echo "$rule" | jq -r '.access // "Deny"' 2>/dev/null)
|
||||
protocol=$(echo "$rule" | jq -r '.protocol // "*"' 2>/dev/null)
|
||||
port_str=$(echo "$rule" | jq -r '.destinationPortRange // "*"' 2>/dev/null)
|
||||
source_addr=$(echo "$rule" | jq -r '.sourceAddressPrefix // "*"' 2>/dev/null)
|
||||
dest_addr=$(echo "$rule" | jq -r '.destinationAddressPrefix // "*"' 2>/dev/null)
|
||||
priority=$(echo "$rule" | jq -r '.priority // 0' 2>/dev/null)
|
||||
|
||||
[[ "$port_str" == "null" ]] && port_str="*"
|
||||
|
||||
local cidr_display
|
||||
if [[ "$direction" == "Inbound" ]]; then
|
||||
cidr_display="$source_addr"
|
||||
else
|
||||
cidr_display="$dest_addr"
|
||||
fi
|
||||
|
||||
local svc=""
|
||||
if [[ "$port_str" =~ ^[0-9]+$ ]]; then
|
||||
svc=$(port_to_service "$port_str")
|
||||
fi
|
||||
|
||||
local dir_color="$CYAN"
|
||||
[[ "$direction" == "Outbound" ]] && dir_color="$YELLOW"
|
||||
|
||||
local access_color="$GREEN"
|
||||
[[ "$access" == "Deny" ]] && access_color="$RED"
|
||||
|
||||
printf " %-18s %-20s %b%-8s%b %b%-8s%b %-8s %-12s %-18s %s\n" \
|
||||
"${nsg_name:0:16}" "${rule_name:0:18}" \
|
||||
"$dir_color" "$direction" "$RESET" \
|
||||
"$access_color" "$access" "$RESET" \
|
||||
"$protocol" "${port_str:0:10}" "${cidr_display:0:16}" "${svc}"
|
||||
done
|
||||
done
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# SUMMARY
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
print_summary() {
|
||||
local elapsed
|
||||
elapsed=$(( $(date +%s) - START_TIME ))
|
||||
|
||||
echo ""
|
||||
echo " ══════════════════════════════════════════"
|
||||
echo " NSG Audit Summary"
|
||||
echo " ══════════════════════════════════════════"
|
||||
printf " %-20s %b%d%b\n" "CRITICAL:" "$RED" "$TOTAL_CRIT" "$RESET"
|
||||
printf " %-20s %b%d%b\n" "WARN:" "$YELLOW" "$TOTAL_WARN" "$RESET"
|
||||
printf " %-20s %b%d%b\n" "INFO:" "$CYAN" "$TOTAL_INFO" "$RESET"
|
||||
printf " %-20s %b%d%b\n" "OK:" "$GREEN" "$TOTAL_OK" "$RESET"
|
||||
echo " ──────────────────────────────────────────"
|
||||
printf " Completed in %ds\n" "$elapsed"
|
||||
echo ""
|
||||
|
||||
if [[ "$TOTAL_CRIT" -gt 0 ]]; then
|
||||
echo -e " ${RED}${BOLD}Action required:${RESET} ${TOTAL_CRIT} critical finding(s)"
|
||||
echo ""
|
||||
echo " Top recommendations:"
|
||||
echo " • Assign NSGs to all unprotected NICs and subnets"
|
||||
echo " • Close */Internet rules on SSH (22), RDP (3389), and database ports"
|
||||
echo " • Replace all-port allow rules with specific port lists"
|
||||
echo " • Remove unused NSGs to reduce configuration sprawl"
|
||||
echo ""
|
||||
elif [[ "$TOTAL_WARN" -gt 0 ]]; then
|
||||
echo -e " ${YELLOW}Review recommended:${RESET} ${TOTAL_WARN} warning(s)"
|
||||
echo ""
|
||||
echo " Suggestions:"
|
||||
echo " • Review wide-open rules and narrow where possible"
|
||||
echo " • Delete unused NSGs"
|
||||
echo " • Restrict outbound where applicable"
|
||||
echo ""
|
||||
else
|
||||
echo -e " ${GREEN}All checks passed${RESET}"
|
||||
echo ""
|
||||
fi
|
||||
}
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# USAGE
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
show_help() {
|
||||
cat <<EOF
|
||||
${BOLD}${SCRIPT_NAME}${RESET} — Azure NSG Auditor
|
||||
|
||||
Audit Azure Network Security Group rules across all NSGs for risky
|
||||
configurations via the Azure CLI.
|
||||
|
||||
${BOLD}MODES${RESET}
|
||||
--full Run all audits
|
||||
--open-ports Find dangerous ports open to */Internet
|
||||
--unprotected Find NICs with no NSG assigned
|
||||
--permissive Find overly broad allow rules
|
||||
--unused Find NSGs not attached to any NIC or subnet
|
||||
--rules List all custom NSG rules
|
||||
|
||||
${BOLD}OPTIONS${RESET}
|
||||
--resource-group RG Limit audit to a specific resource group
|
||||
--subscription SUB Use a specific Azure subscription
|
||||
--ports PORTS Override dangerous ports (comma-separated)
|
||||
--verbose Debug output
|
||||
--no-color Disable colored output
|
||||
--help Show this help message
|
||||
|
||||
${BOLD}ENVIRONMENT VARIABLES${RESET}
|
||||
RESOURCE_GROUP Limit to a specific resource group
|
||||
SUBSCRIPTION Azure subscription ID or name
|
||||
DANGEROUS_PORTS Comma-separated ports to flag (default: 22,3389,...)
|
||||
VERBOSE Enable verbose output (true/false)
|
||||
COLOR Color mode: auto, always, never
|
||||
|
||||
${BOLD}EXAMPLES${RESET}
|
||||
# Full audit
|
||||
${SCRIPT_NAME} --full
|
||||
|
||||
# Check open ports only
|
||||
${SCRIPT_NAME} --open-ports
|
||||
|
||||
# Find unprotected NICs
|
||||
${SCRIPT_NAME} --unprotected
|
||||
|
||||
# Audit a specific resource group
|
||||
${SCRIPT_NAME} --full --resource-group my-rg
|
||||
|
||||
# Custom dangerous ports
|
||||
${SCRIPT_NAME} --open-ports --ports "22,3389,5432,6379"
|
||||
|
||||
# List all NSG rules
|
||||
${SCRIPT_NAME} --rules
|
||||
|
||||
${BOLD}EXIT CODES${RESET}
|
||||
0 All checks passed
|
||||
1 Warnings found (review recommended)
|
||||
2 Critical findings (action required)
|
||||
EOF
|
||||
}
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# PARSE ARGS
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
parse_args() {
|
||||
local modes=()
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--full)
|
||||
modes=(open-ports unprotected permissive unused)
|
||||
shift ;;
|
||||
--open-ports)
|
||||
modes+=(open-ports); shift ;;
|
||||
--unprotected)
|
||||
modes+=(unprotected); shift ;;
|
||||
--permissive)
|
||||
modes+=(permissive); shift ;;
|
||||
--unused)
|
||||
modes+=(unused); shift ;;
|
||||
--rules)
|
||||
modes+=(rules); shift ;;
|
||||
--resource-group)
|
||||
RESOURCE_GROUP="${2:?--resource-group requires a value}"; shift 2 ;;
|
||||
--subscription)
|
||||
SUBSCRIPTION="${2:?--subscription requires a value}"; shift 2 ;;
|
||||
--ports)
|
||||
DANGEROUS_PORTS="${2:?--ports requires a value}"; shift 2 ;;
|
||||
--verbose)
|
||||
VERBOSE="true"; shift ;;
|
||||
--no-color)
|
||||
COLOR="never"; shift ;;
|
||||
--help|-h)
|
||||
setup_colors; show_help; exit 0 ;;
|
||||
*)
|
||||
die "Unknown option: $1 (see --help)" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ ${#modes[@]} -eq 0 ]]; then
|
||||
err "No audit mode specified"
|
||||
echo "Run ${SCRIPT_NAME} --help for usage" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
RUN_MODE="${modes[*]}"
|
||||
}
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# MAIN
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
main() {
|
||||
parse_args "$@"
|
||||
setup_colors
|
||||
check_deps
|
||||
check_credentials
|
||||
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
echo ""
|
||||
echo -e "${BOLD}Azure NSG Auditor${RESET}"
|
||||
echo -e "Mode: ${RUN_MODE}"
|
||||
[[ -n "$RESOURCE_GROUP" ]] && echo -e "RG: ${RESOURCE_GROUP}"
|
||||
[[ -n "$SUBSCRIPTION" ]] && echo -e "Sub: ${SUBSCRIPTION}"
|
||||
echo -e "Time: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
echo ""
|
||||
|
||||
for mode in $RUN_MODE; do
|
||||
case "$mode" in
|
||||
open-ports) audit_open_ports ;;
|
||||
unprotected) audit_unprotected ;;
|
||||
permissive) audit_permissive ;;
|
||||
unused) audit_unused ;;
|
||||
rules) list_rules ;;
|
||||
esac
|
||||
done
|
||||
|
||||
print_summary
|
||||
|
||||
if [[ "$TOTAL_CRIT" -gt 0 ]]; then
|
||||
exit 2
|
||||
elif [[ "$TOTAL_WARN" -gt 0 ]]; then
|
||||
exit 1
|
||||
fi
|
||||
exit 0
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user