StackPractices
intermediate Por Mathias Paulenko

Configurar Reglas de Firewall iptables con Bash

Configura reglas básicas de firewall con iptables y scripts bash.

Temas: security

Visión General

iptables es el framework de firewall por defecto en Linux. Filtra tráfico de red a nivel kernel usando cadenas de reglas. Esta recipe cubre configurar un firewall básico: permitir SSH y HTTP, bloquear todo lo demás, configurar NAT y persistir reglas tras reinicios.

Cuándo Usar

  • Estás configurando un servidor Linux nuevo y necesitas protección básica de firewall
  • Quieres restringir tráfico entrante a puertos específicos
  • Necesitas configurar NAT o port forwarding
  • Estás endureciendo un servidor antes de deployar a producción

Solución

Configuración básica de firewall

#!/bin/bash

# Flush existing rules
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X

# Set default policies
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# Allow loopback
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

# Allow established connections
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# Allow SSH (port 22)
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# Allow HTTP and HTTPS
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# Allow DNS queries
iptables -A INPUT -p udp --dport 53 -j ACCEPT
iptables -A INPUT -p tcp --dport 53 -j ACCEPT

# Log dropped packets (optional, rate-limited)
iptables -A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables-dropped: " --log-level 4

echo "Firewall configured. SSH, HTTP, HTTPS, DNS allowed."

Rate limiting de conexiones SSH

#!/bin/bash

# Allow only 3 SSH connections per minute, drop the rest
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --set --name SSH
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 --name SSH -j DROP

# Allow established SSH
iptables -A INPUT -p tcp --dport 22 -m state --state ESTABLISHED,RELATED -j ACCEPT

echo "SSH rate limiting configured: max 3 new connections per minute"

Port forwarding con NAT

#!/bin/bash

# Enable IP forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward

# Forward port 8080 to port 80 on 192.168.1.100
iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 192.168.1.100:80
iptables -t nat -A POSTROUTING -p tcp -d 192.168.1.100 --dport 80 -j MASQUERADE

# Allow forwarding
iptables -A FORWARD -p tcp -d 192.168.1.100 --dport 80 -j ACCEPT

echo "Port forwarding: 8080 -> 192.168.1.100:80"

Bloquear IPs específicas

#!/bin/bash

BLOCKED_IPS=(
    "203.0.113.50"
    "198.51.100.23"
    "192.0.2.100"
)

for ip in "${BLOCKED_IPS[@]}"; do
    iptables -A INPUT -s "$ip" -j DROP
    echo "Blocked: $ip"
done

Permitir tráfico solo de un subnet específico

#!/bin/bash

# Only allow SSH from 10.0.0.0/24
iptables -A INPUT -p tcp --dport 22 -s 10.0.0.0/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j DROP

echo "SSH restricted to 10.0.0.0/24"

Persistir reglas tras reinicios

#!/bin/bash

# Save rules
iptables-save > /etc/iptables/rules.v4
ip6tables-save > /etc/iptables/rules.v6

# Install persistence package (Debian/Ubuntu)
apt-get install -y iptables-persistent

# Or restore manually on boot via systemd
cat > /etc/systemd/system/iptables-restore.service << 'EOF'
[Unit]
Description=Restore iptables rules
Before=network-pre.target

[Service]
Type=oneshot
ExecStart=/sbin/iptables-restore /etc/iptables/rules.v4

[Install]
WantedBy=multi-user.target
EOF

systemctl enable iptables-restore.service

echo "Rules persisted to /etc/iptables/rules.v4"

Script de reset de firewall

#!/bin/bash

iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X

iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT

echo "All iptables rules cleared. Default: ACCEPT all."

Listar y verificar reglas

#!/bin/bash

echo "=== Filter table ==="
iptables -L -n -v --line-numbers

echo ""
echo "=== NAT table ==="
iptables -t nat -L -n -v --line-numbers

echo ""
echo "=== Mangle table ==="
iptables -t mangle -L -n -v --line-numbers

Explicación

iptables procesa reglas en orden, de arriba hacia abajo. La primera regla que coincide gana. Las políticas por defecto (-P) aplican cuando ninguna regla coincide.

Conceptos clave:

  • Chains: INPUT (entrante), OUTPUT (saliente), FORWARD (ruteado).
  • Tables: filter (por defecto), nat (traducción de direcciones), mangle (modificación de paquetes).
  • Targets: ACCEPT, DROP, REJECT, LOG, MASQUERADE.
  • State matching: ESTABLISHED,RELATED permite tráfico de retorno para conexiones iniciadas desde el servidor.

El módulo -m recent trackea IPs de origen y habilita rate limiting. Guarda intentos de conexión en /proc/net/xt_recent/.

Variantes

EnfoqueHerramientaComplejidadUsar Cuando
iptablesiptablesMediaServidores Linux estándar
nftablesnftMediaLinux moderno (reemplaza iptables)
UFWufwBajaSetup rápido Ubuntu/Debian
firewalldfirewall-cmdBajaRHEL/CentOS/Fedora

Pautas

  • Siempre permite SSH antes de setear DROP como política por defecto. Puedes bloquearte fuera.
  • Testea reglas en una sesión SSH separada antes de cerrar la actual.
  • Usa iptables -L -n -v para verificar que las reglas se aplicaron correctamente.
  • Persiste reglas con iptables-persistent o un servicio systemd. Las reglas se pierden al reiniciar.
  • Loguea paquetes dropeados con rate limiting para evitar llenar el log.
  • Usa REJECT en vez de DROP para redes internas. REJECT envía respuesta; DROP descarta silenciosamente.

Errores Comunes

  • Setear política DROP antes de permitir SSH. Pierdes acceso inmediatamente.
  • No persistir reglas. Desaparecen al reiniciar y el servidor queda desprotegido o inalcanzable.
  • Permitir todas las conexiones establecidas antes de verificar el origen. Un paquete spoofed puede bypassar reglas.
  • Olvidar IPv6. ip6tables es separado. Un puerto IPv6 abierto bypassa las reglas IPv4 de iptables.
  • Usar DROP en todos lados. DROP hace el troubleshooting más difícil. Usa REJECT para tráfico interno.

Mejores Prácticas Adicionales

  1. Usa conntrack en vez de state para setups nuevos. El módulo state está deprecado en favor de conntrack que provee la misma funcionalidad con mejor performance:
# Viejo (deprecado)
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# Nuevo (recomendado)
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
  1. Setea parámetros del kernel para hardening. Combina iptables con settings de sysctl para defensa en profundidad:
# Habilitar SYN cookies
echo 1 > /proc/sys/net/ipv4/tcp_syncookies
# Deshabilitar IP forwarding (a menos que sea un router)
echo 0 > /proc/sys/net/ipv4/ip_forward
# Ignorar broadcasts ICMP (ataques smurf)
echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
# Reverse path filtering
echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter

Preguntas frecuentes

¿Cuál es la diferencia entre iptables y nftables?

nftables es el sucesor de iptables, introducido en Linux kernel 3.13. Usa una sintaxis unificada, soporta IPv4 e IPv6 en una sola tabla y tiene mejor performance. Las reglas de iptables se pueden traducir a nftables con iptables-translate.

¿Cómo permito un rango de puertos?
iptables -A INPUT -p tcp --dport 8000:8100 -j ACCEPT

Esto permite tráfico TCP en los puertos 8000 a 8100.

¿Cómo bloqueo todo el tráfico de un país?

Usa ipset con una lista de rangos IP del país:

ipset create blocklist hash:net
# Add IP ranges (from a geoip database)
ipset add blocklist 203.0.113.0/24
iptables -A INPUT -m set --match-set blocklist src -j DROP
¿Cómo depuro por qué un paquete está siendo dropeado?

Agrega una regla LOG antes de la regla DROP:

iptables -A INPUT -p tcp --dport 22 -j LOG --log-prefix "SSH-DROP: "
iptables -A INPUT -p tcp --dport 22 -j DROP

Revisa /var/log/syslog o /var/log/messages para las entradas de log. Remueve la regla LOG después de debuggear.