Categories
Uncategorized

How to make iptables configuration persistent using systemd

Make iptables configuration persistent using systemd file with additional possibility to disable firewall after defined period of time.

Shell script

Create /sbin/iptables-firewall.sh shell script. Edit firewall_start function to apply custom iptables configuration.

#!/bin/bash
# Configure iptables firewall

# Limit PATH
PATH="/sbin:/usr/sbin:/bin:/usr/bin"

# iptables configuration
firewall_start() {
  # Define chain to allow particular source addresses
  iptables -N chain-incoming-ssh
  iptables -A chain-incoming-ssh -s 192.168.1.149 -j ACCEPT -m comment --comment "local access"
  iptables -A chain-incoming-ssh -p tcp --dport 22 -j LOG  --log-prefix "[fw-inc-ssh] " -m limit --limit 6/min --limit-burst 4
  iptables -A chain-incoming-ssh -j DROP

  # Define chain to log and drop incoming packets
  iptables -N chain-incoming-log-and-drop
  iptables -A chain-incoming-log-and-drop -j LOG --log-prefix "[fw-inc-drop] " -m limit --limit 6/min --limit-burst 4
  iptables -A chain-incoming-log-and-drop -j DROP

  # Define chain to log and drop outgoing packets
  iptables -N chain-outgoing-log-and-drop
  iptables -A chain-outgoing-log-and-drop -j LOG --log-prefix "[fw-out-drop] " -m limit --limit 6/min --limit-burst 4
  iptables -A chain-outgoing-log-and-drop -j DROP

  # Drop invalid packets
  iptables -A INPUT -m conntrack --ctstate INVALID -j chain-incoming-log-and-drop

  # Accept everything on loopback
  iptables -A INPUT  -i lo -j ACCEPT
  iptables -A OUTPUT -o lo -j ACCEPT

  # ACCEPT incoming packets for established connections
  iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

  # Accept incoming ICMP
  iptables -A INPUT -p icmp -j ACCEPT

  # Accept incoming SSH
  iptables -A INPUT -p tcp --dport 22 -j chain-incoming-ssh

  # Accept outgoing packets for established connections
  iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

  # Accept outgoing DNS
  iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT
  iptables -A OUTPUT -p udp --dport 53 -j ACCEPT

  # Accept outgoing NTP
  iptables -A OUTPUT -p tcp --dport 123 -j ACCEPT
  iptables -A OUTPUT -p udp --dport 123 -j ACCEPT

  # Accept outgoing HTTP/S
  iptables -A OUTPUT -p tcp --dport 80  -j ACCEPT
  iptables -A OUTPUT -p tcp --dport 443 -j ACCEPT

  # Accept outgoing SSH
  iptables -A OUTPUT -p tcp --dport 22  -j ACCEPT

  # Accept outgoing ICMP
  iptables -A OUTPUT -p icmp -j ACCEPT

  # Log not accounted outgoing traffic
  iptables -A OUTPUT -j chain-outgoing-log-and-drop

  # Log not accounted forwarding traffic
  iptables -A FORWARD -j chain-incoming-log-and-drop

  # Drop everything else
  iptables -P INPUT   DROP
  iptables -P FORWARD DROP
  iptables -P OUTPUT  DROP
}

# clear iptables configuration
firewall_stop() {
  iptables -F
  iptables -X
  iptables -P INPUT   ACCEPT
  iptables -P FORWARD ACCEPT
  iptables -P OUTPUT  ACCEPT
}

# execute action
case "$1" in
  start|restart)
    echo "Starting firewall"
    firewall_stop
    firewall_start
    ;;
  stop)
    echo "Stopping firewall"
    firewall_stop
    ;;
esac

Ensure that shell script owned by root.

$ sudo chown root:root /sbin/iptables-firewall.sh

Ensure that script is executable.

$ sudo chmod 750 /sbin/iptables-firewall.sh

systemd configuration

Create iptables-firewall service.

$ cat << EOF | sudo tee /etc/systemd/system/iptables-firewall.service
[Unit]
Description=iptables firewall service
After=network.target

[Service]
Type=oneshot
ExecStart=/home/milosz/iptables-firewall.sh start
RemainAfterExit=true
ExecStop=/home/milosz/iptables-firewall.sh stop
StandardOutput=journal

[Install]
WantedBy=multi-user.target
EOF

Create iptables-firewall-test service.

$ cat << EOF | sudo tee /etc/systemd/system/iptables-firewall-test.service
[Unit]
Description=iptables firewall service test
BindsTo=iptables-firewall.service
After=iptables-firewall.service

[Service]
Type=oneshot
ExecStart=/usr/bin/systemd-run --on-active=180 --timer-property=AccuracySec=1s /bin/systemctl stop iptables-firewall.service
StandardOutput=journal

[Install]
WantedBy=multi-user.target
EOF

Reload systemd manager configuration.

$ sudo systemctl daemon-reload

Usage

Test iptables firewall using iptables-firewall-test service.

$ sudo systemctl start iptables-firewall-test

It will start iptables-firewall service.

$ sudo systemctl status iptables-firewall
‚óŹ iptables-firewall.service - iptables firewall service
   Loaded: loaded (/etc/systemd/system/iptables-firewall.service; disabled; vendor preset: enabled)
   Active: active (exited) since Tue 2018-01-02 07:14:42 CST; 2min 32s ago
  Process: 772 ExecStart=/home/milosz/iptables-firewall.sh start (code=exited, status=0/SUCCESS)
 Main PID: 772 (code=exited, status=0/SUCCESS)
    Tasks: 0 (limit: 4915)
   CGroup: /system.slice/iptables-firewall.service

Jan 02 07:14:41 debian systemd[1]: Starting iptables firewall service...
Jan 02 07:14:41 debian iptables-firewall.sh[772]: Starting firewall
Jan 02 07:14:42 debian systemd[1]: Started iptables firewall service.

It will also schedule temporary timer to stop iptables-firewall service after 3 minutes.

$ sudo systemctl list-timers
NEXT                         LEFT          LAST                         PASSED      UNIT
Tue 2018-01-02 07:17:42 CST  2min 21s left n/a                          n/a         run-rb4c64fbca4ee4c
Tue 2018-01-02 10:58:01 CST  3h 42min left Mon 2018-01-01 18:54:12 CST  12h ago     apt-daily.timer
Wed 2018-01-03 06:29:06 CST  23h left      Tue 2018-01-02 06:10:06 CST  1h 5min ago apt-daily-upgrade.t
Wed 2018-01-03 06:59:14 CST  23h left      Tue 2018-01-02 06:59:14 CST  16min ago   systemd-tmpfiles-cl

4 timers listed.
Pass --all to see loaded but inactive timers, too.

Enable iptables-firewall service at boot.

$ sudo systemctl enable iptables-firewall

Start iptables-firewall service.

$ sudo systemctl start iptables-firewall

There is nothing more than standard systemd operations. Use iptables-firewall-test service to test iptables configuration, but remember that it will stop iptables-firewall service after 3 minutes.