Add script to block koji for external user at the time of branching #12877
1 changed files with 165 additions and 0 deletions
165
scripts/branching/koji-http-toggle.sh
Executable file
165
scripts/branching/koji-http-toggle.sh
Executable file
|
|
@ -0,0 +1,165 @@
|
|||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# Koji HTTP Toggle (nftables)
|
||||
# -----------------------------------------------------------------------------
|
||||
# Purpose:
|
||||
# Quickly BLOCK or UNBLOCK external HTTP submissions to Koji by dropping
|
||||
# TCP/80 from specified proxies (proxy01/proxy10 by default) using nftables.
|
||||
#
|
||||
# What it does:
|
||||
# - Resolves hostnames to IPv4 addresses (via `getent ahostsv4`)
|
||||
# - Ensures `table inet filter` and `chain input` exist
|
||||
# - Creates a named set `koji_http_block_src` and a rule that drops
|
||||
# tcp dport 80 if ip saddr is in that set
|
||||
# - Adds/removes IPs to/from the set (idempotent)
|
||||
#
|
||||
# Usage:
|
||||
# sudo /usr/local/sbin/koji-http-toggle.sh block # block proxy01/proxy10
|
||||
# sudo /usr/local/sbin/koji-http-toggle.sh status # show current state
|
||||
# sudo /usr/local/sbin/koji-http-toggle.sh unblock # remove block
|
||||
#
|
||||
# Install:
|
||||
# sudo install -m 0755 koji-http-toggle.sh /usr/local/sbin/koji-http-toggle.sh
|
||||
#
|
||||
# Env overrides (optional):
|
||||
# PORT=<port> default: 80
|
||||
# PROXY01=<hostname> default: proxy01.rdu3.fedoraproject.org
|
||||
# PROXY10=<hostname> default: proxy10.rdu3.fedoraproject.org
|
||||
#
|
||||
# Examples:
|
||||
# sudo PROXY01=proxy01.example.org PROXY10=proxy10.example.org \
|
||||
# /usr/local/sbin/koji-http-toggle.sh block
|
||||
#
|
||||
# Notes:
|
||||
# - IPv4 only (adjust type to ip6_addr + `getent ahostsv6` if you need IPv6).
|
||||
# - If firewalld manages your host, prefer firewalld rich rules instead.
|
||||
# - To persist direct-nft config across reboot:
|
||||
# sudo sh -c 'nft list ruleset > /etc/nftables.conf'
|
||||
# sudo systemctl enable --now nftables
|
||||
#
|
||||
# Troubleshooting:
|
||||
# - "syntax error near `}'" → quote the chain creation command (we do).
|
||||
# - "No such file or directory" → table/chain likely missing; the script
|
||||
# creates them automatically.
|
||||
# =============================================================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Defaults (override with env vars if needed)
|
||||
PORT="${PORT:-80}"
|
||||
HOSTS=(
|
||||
"${PROXY01:-proxy01.rdu3.fedoraproject.org}"
|
||||
"${PROXY10:-proxy10.rdu3.fedoraproject.org}"
|
||||
)
|
||||
|
||||
TABLE="inet filter" # nft table and family
|
||||
CHAIN="input" # nft chain to hook into
|
||||
SET="koji_http_block_src" # named set of source IPs to block
|
||||
COMMENT="koji-http-block" # helpful tag for future auditing
|
||||
|
||||
# Resolve each hostname to a single IPv4 address (first match)
|
||||
resolve_ips() {
|
||||
local ip
|
||||
for h in "${HOSTS[@]}"; do
|
||||
ip="$(getent ahostsv4 "$h" | awk '{print $1; exit}')" || true
|
||||
if [[ -z "${ip:-}" ]]; then
|
||||
echo "ERROR: could not resolve IPv4 for $h" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "$ip"
|
||||
done
|
||||
}
|
||||
|
||||
# Ensure table and chain exist; chain hooks into input with default accept
|
||||
ensure_table_chain() {
|
||||
if ! nft list table $TABLE >/dev/null 2>&1; then
|
||||
nft add table $TABLE
|
||||
fi
|
||||
if ! nft list chain $TABLE $CHAIN >/dev/null 2>&1; then
|
||||
nft "add chain $TABLE $CHAIN { type filter hook input priority 0; policy accept; }"
|
||||
fi
|
||||
}
|
||||
|
||||
# Ensure the named set exists to hold source IPs
|
||||
ensure_set() {
|
||||
if ! nft list set $TABLE $SET >/dev/null 2>&1; then
|
||||
nft "add set $TABLE $SET { type ipv4_addr; comment \"$COMMENT\"; }"
|
||||
fi
|
||||
}
|
||||
|
||||
# Ensure a single drop rule exists that references the named set
|
||||
ensure_rule() {
|
||||
if ! nft list chain $TABLE $CHAIN | grep -q "tcp dport $PORT .* @$SET .* drop"; then
|
||||
nft add rule $TABLE $CHAIN tcp dport $PORT ip saddr @$SET drop comment \"$COMMENT\"
|
||||
fi
|
||||
}
|
||||
|
||||
# Add the proxies' IPs into the set (safe to run multiple times)
|
||||
block() {
|
||||
ensure_table_chain
|
||||
ensure_set
|
||||
ensure_rule
|
||||
|
||||
local ips=()
|
||||
mapfile -t ips < <(resolve_ips)
|
||||
|
||||
# Build "{ ip1,ip2,... }" for nft add element
|
||||
local elems
|
||||
elems="$(printf "{ %s }" "$(IFS=,; echo "${ips[*]}")")"
|
||||
|
||||
# Add elements; ignore if already present
|
||||
nft add element $TABLE $SET "$elems" 2>/dev/null || true
|
||||
|
||||
echo "Blocked HTTP (tcp/$PORT) from: ${ips[*]}"
|
||||
}
|
||||
|
||||
# Remove all IPs from the set and delete the drop rule
|
||||
unblock() {
|
||||
# Flush the set if it exists
|
||||
if nft list set $TABLE $SET >/dev/null 2>&1; then
|
||||
nft flush set $TABLE $SET
|
||||
fi
|
||||
|
||||
# Remove the rule by handle (safer than pattern-delete)
|
||||
if nft list chain $TABLE $CHAIN | grep -q "tcp dport $PORT .* @$SET .* drop"; then
|
||||
local handle
|
||||
handle="$(nft -a list chain $TABLE $CHAIN | awk '/tcp dport '"$PORT"'.* @'"$SET"'.* drop/ {print $NF}')"
|
||||
if [[ -n "${handle:-}" ]]; then
|
||||
nft delete rule $TABLE $CHAIN handle "$handle"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Unblocked. (Set cleared and rule removed if present.)"
|
||||
}
|
||||
|
||||
# Show current table, chain, and set contents
|
||||
status() {
|
||||
echo "=== nft: $TABLE ==="
|
||||
nft list table $TABLE 2>/dev/null || { echo "(no $TABLE)"; return; }
|
||||
echo
|
||||
echo "=== Elements in @$SET ==="
|
||||
nft list set $TABLE $SET 2>/dev/null || echo "(no set $SET)"
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: $0 {block|unblock|status}
|
||||
|
||||
Env overrides:
|
||||
PORT=<port> (default: 80)
|
||||
PROXY01=<hostname> (default: proxy01.rdu3.fedoraproject.org)
|
||||
PROXY10=<hostname> (default: proxy10.rdu3.fedoraproject.org)
|
||||
|
||||
Examples:
|
||||
sudo $0 block
|
||||
sudo $0 status
|
||||
sudo $0 unblock
|
||||
EOF
|
||||
}
|
||||
|
||||
case "${1:-}" in
|
||||
block) block ;;
|
||||
unblock) unblock ;;
|
||||
status) status ;;
|
||||
*) usage; exit 1 ;;
|
||||
esac
|
||||
Loading…
Add table
Add a link
Reference in a new issue