Установка и настройка knockd

Для чего нужен knockd? Для реализации метода port knocking — «стука» в фаервол для открытия определённых портов. Это обычное применение данной программы, но этим оно не ограничивается и можно придумать более экзотическое её использование.

Для начала установовим пакеты knockd и iptables-persistent. Последний нужен для постоянного хранения правил фаервола в случае перезагрузки сервера.

apt-get install knockd iptables-persistent

Минимальный набор правил для iptables при это будет выглядеть так:

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

iptables -P INPUT DROP

iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

iptables -A INPUT -i eth0 -j DROP

В данном случае eth0 — это название сетевого интерфейса. На свежих системах название будет другое. Например enp3s0 или подобное. 😉

После того, как правила изменены, нужно их сохранить. Делается это командой

iptables-save > /etc/iptables/rules.v4

Теперь можно перейти непосредственно к настройке knockd. Для примера рассмотрим использование port knocking для открытия порта ssh сервиса.

Разрешим запуск knockd в режиме демон. Для этого отредактируем файл /etc/default/knockd и поменяем в нём строку на следующую:

START_KNOCKD=1

Если у вас, как и у меня, используется systemd, приведём файл /lib/systemd/system/knockd.service, который выглядит вот так:

[Unit]
Description=Port-Knock Daemon
After=network.target
Documentation=man:knockd(1)

[Service]
EnvironmentFile=-/etc/default/knockd
ExecStart=/usr/sbin/knockd $KNOCKD_OPTS
ExecReload=/bin/kill -HUP $MAINPID
KillMode=mixed
SuccessExitStatus=0 2 15
ProtectSystem=full
CapabilityBoundingSet=CAP_NET_RAW CAP_NET_ADMIN

к следующему виду:

[Unit]
Description=Port-Knock Daemon
After=network.target
Requires=network.target
Documentation=man:knockd(1)

[Service]
EnvironmentFile=-/etc/default/knockd
ExecStartPre=/bin/sleep 1
ExecStart=/usr/sbin/knockd $KNOCKD_OPTS
ExecReload=/bin/kill -HUP $MAINPID
KillMode=mixed
SuccessExitStatus=0 2 15
ProtectSystem=full
CapabilityBoundingSet=CAP_NET_RAW CAP_NET_ADMIN

[Install]
WantedBy=multi-user.target

После редактирования нужно, чтобы systemd узнал об изменении в конфигурационных файлах. Для этого выполним:

systemctl daemon-reload

Теперь можно разрешить запускать knockd как сервис:

systemctl enable knockd.service

И осталось последнее — отредактировать конфигурационный файл knockd /etc/knockd.conf. Так он выглядит при установке:

[options]
        UseSyslog

[openSSH]
        sequence    = 7000,8000,9000
        seq_timeout = 5
        command     = /sbin/iptables -A INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
        tcpflags    = syn

[closeSSH]
        sequence    = 9000,8000,7000
        seq_timeout = 5
        command     = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
        tcpflags    = syn

Но я предпочитаю не убиать доступ к открытым портам вручную, а использую встроенную возможность «закрытия». Конфигурационный файл при этом выглядит так:

[options]
    UseSyslog
    Interface = eth0

[opencloseSSH]
    sequence      = 7000,8000,9000
    seq_timeout   = 10
    cmd_timeout   = 60
    tcpflags      = syn
    start_command = /sbin/iptables -I INPUT 3 -s %IP% -p tcp --dport 22 -j ACCEPT
    stop_command  = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT

В sequence можно указать любые свободные порты, которые вам нравятся. Через 60 секунд после выполнения команды, указанной в start_command, выполнится команда stop_command, которая уберёт правило, открывающее доступ к 22 порту.

Запустим knockd сервис:

systemctl start knockd.service

И проверим, что он работает корректно:

root@tests:~# systemctl status knockd.service 
● knockd.service - Port-Knock Daemon
     Loaded: loaded (/lib/systemd/system/knockd.service; enabled; vendor preset: enabled)
     Active: active (running) since Sat 2023-02-04 08:41:19 MSK; 53s ago
       Docs: man:knockd(1)
    Process: 1762844 ExecStartPre=/bin/sleep 1 (code=exited, status=0/SUCCESS)
   Main PID: 1762845 (knockd)
      Tasks: 1 (limit: 9507)
     Memory: 768.0K
        CPU: 25ms
     CGroup: /system.slice/knockd.service
             └─1762845 /usr/sbin/knockd

Feb 04 08:41:18 tests systemd[1]: Starting Port-Knock Daemon...
Feb 04 08:41:19 tests systemd[1]: Started Port-Knock Daemon.
Feb 04 08:41:19 tests knockd[1762845]: starting up, listening on eth0

Теперь проверим, что сервис действительно работает. Для этого «постучим» на сервер снаружи:

knock  7000:tcp 8000:tcp 9008:tcp

На сервере в /var/log/syslog мы увидим следующее:

Feb  4 08:43:43 tests knockd: xx.xx.xx.xx: opencloseSSH: Stage 1
Feb  4 08:43:43 tests knockd: xx.xx.xx.xx: opencloseSSH: Stage 2
Feb  4 08:43:43 tests knockd: xx.xx.xx.xx: opencloseSSH: Stage 3
Feb  4 08:43:43 tests knockd: xx.xx.xx.xx: opencloseSSH: OPEN SESAME
Feb  4 08:43:43 tests knockd: opencloseSSH: running command: /sbin/iptables -I INPUT 3 -s xx.xx.xx.xx -p tcp --dport 22 -j ACCEPT

Это означает, что 22 порт открылся. Убедимся в этом, посмотрев список правил iptables:

iptables -nL
Chain INPUT (policy DROP)
target     prot opt source               destination         
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
ACCEPT     tcp  --  xx.xx.xx.xx          0.0.0.0/0            tcp dpt:22
DROP       all  --  0.0.0.0/0            0.0.0.0/0           

Chain FORWARD (policy DROP)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Продолжая наблюдать логи в /var/log/syslog, через 60 секунд мы увидим отработку команды stop_command, указанной в конфиге:

Feb  4 08:44:43 tests knockd: xx.xx.xx.xx: opencloseSSH: command timeout
Feb  4 08:44:43 tests knockd: opencloseSSH: running command: /sbin/iptables -D INPUT -s xx.xx.xx.xx -p tcp --dport 22 -j ACCEPT

Правило для открытия 22 порта удалилось. Проверям в iptables:

iptables -nL
Chain INPUT (policy DROP)
target     prot opt source               destination         
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
DROP       all  --  0.0.0.0/0            0.0.0.0/0           

Chain FORWARD (policy DROP)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Так и есть. Всё работает отлично. 🙂

Теперь пару слов о том, как ещё можно использовать knockd. В start_command в /etc/knockd.conf можно необязательно указывать добавление/удаление правил iptables. Можно сделать, например, выключение сервера в экстренной ситуации, указав:

start_command = /sbin/shutdown -h now

Выключением можно не ограничиваться. В случае получения уведомления о взломе сервера, можно блокировать все соединения с внешним миром, удалить данные с диска, если её раскрытие критично. В общем, возможны любые действия, которые только можно придумать. 🙂

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *