Начну с причин написания оной. Очень часто на форумах и в комментариях к новостям и статьям я вижу отзывы об OpenBSD что это не нужно, и её разработка - бесполезная трата времени.
Я категорически не согласен с этой группой товарищей. Глубоко познакомившись с этой системой и сравнив её достоинства и недостатки с другими nix системами я могу в полной уверенности заявить что OpenBSD лучшая их них!
И дело не в безопасности, и некорректно ставить безопасность этой системы на первое место хотя это безусловно её плюс. А основное её достоинство в "правильности" этой системы.
Когда мы говорим о линукс, я прежде всего представляю себе сильное ядро, которое держится на лесе из различных костылей которые то один то другой пытается под него подставить. Взять к примеру бесконечные споры о системе инициализации, тут давно уже ассортимент более чем наполнен, тут и systemv, и openrc, и systemd и upstart, но главное остаётся главным, если их всё ещё переписывают, значит имеются причины по которым это нужно делать. А бесконечные баги в убунтах по типу отказывающегося авторизовывать vsftpd или постоянно вылезающих косяках pam из-за самбы, или вот эта интересная история с centos, где первые строки в абсолютно любому рецепту в ней - "выключите selinux" Да вобщем за время работы со многими дистрибутивами я словил много непонятных проблем, которые в основном конечно вылезали именно из-за слишком большой запутанности этих костылей друг над другом. Кроме того до пришествия systemd я ни разу не видел нормальной консольной утилиты для управления демонами по время запуска. В основном тот же убунту сервер считает что если демон установлен - значит должен быть включен, и никаких исключений быть не может. А если тебе вдруг надо написать скрипт для запуска какого-нибудь жава приложения, нужно весьма и весьма постаратся чтобы разобраться как вообще это написать и как потом заставить работать.
В OpenBSD этих проблем нет. Они просто написали раз и навсегда нормальную систему инициализации, где всё чётко, понятно, и не возникает вопросов. Точно так же написаны и все остальные части системы. Попробовав хоть раз разобраться в ней и обнаружив что для любой мелочи в этой системе есть своя инструкция, вы останетесь довольны! Система как будто прозрачна, пользуясь ей вы замечаете, что всё работает именно так, как нужно! И всё сделано так, как следует!
Что будет рассказано в цикле статей:
Я уже достаточно давно зарегистрирован на тогда ещё "linuxforum" и теперь переименованным в "unixforum" и надеюсь никто не будет против если я воспользуюсь знаменитостью ресурса для написания этих статей. Это будет не одна статья, я постараюсь рассказать о многих аспектах с которыми может столкнутся системный администратор, и расскажу новичкам как правильно и красиво настроить тот или иной сервис. Тут будет и фаервол, и фильтрация http, и подсчёт трафика по netflow, и настройка почтового сервера, а так же я расскажу как сделать "домашний серверок" со всеми необходимыми сервисами.
Для кого предназначены и не предназначены эти статьи: В основном я делаю упор на новичков в системном администрировании, а так же тех кто симпатизирует к OpenBSD но не может разобраться с ней самостоятельно. Если у вас бомбит от того что система не умеет "компрессия на лету, дедупликация, бла-бла-бла частное облако, бла-бла-бла эластичность, бла-бла-бла виртуальное окружение" то эта статья не для вас.
Об авторе: Я всегда был двоечником и, к сожалению, не обладаю ни грамотностью, ни красноречием, поэтому излагать свои мысли буду как умею. Я противник всего микрософтовского, противник идиотских трат типа покупок "клиентских терминалов" по 40 тысяч в том месте где сотрудникам можно раздать ноутбуки по 20. Я всегда считал что IT службы должны экономить ресурсы а не тратить их. Я стараюсь всегда использовать открытое ПО там где это возможно. Моя личка всегда открыта по любому вопросу по поводу OpenBSD или linux. Я безвозмездно помогу любому кто интересуется open source и хочет изменить мир к лучшему!
Итак поехали! Я пропущу простую процедуру установки операционки, потому что несколько раз нажать ентер должно быть справится любой. На сегодняшний день актуальная версия системы 5.6. С ней и будем работать!
Во время установки полезно чтобы инсталятор создал обычного пользователя, не root. Теперь этому пользователю надо дать привилегии. Заходим под root и запускаем visudo. Там раскоментируем следующее:
Код: Выделить всё
# Uncomment to allow people in group wheel to run all commands
# and set environment variables.
%wheel ALL=(ALL) SETENV: ALL
После чего добавим нашего пользователя в группу wheel:
Код: Выделить всё
usermod -G wheel kasak
Сейчас и далее я считаю что наш юзер - kasak. Тут же кстати сразу видна разница между linux и bsd. В линуксе кроме параметра -G нужно было бы добавить ещё -a.
Выходим из root и переключаемся на нашего юзера.
Далее все приведённые команды должны начинаться с sudo, если мы работаем не под рутом.
Первое что нужно сделать - обеспечить себе возможность удобной установки пакетов.
Для этого откроем файл .profile, который находится в домашней папке пользователя, при помощи vi, и добавим в самый конец такие строки:
Код: Выделить всё
export PKG_PATH=http://mirror.yandex.ru/openbsd/`uname -r`/packages/`uname -m`/
Теперь если выйти и войти обратно, можно будет ставить пакеты через pkg_add <somepackage>
Я для удобства сразу же ставлю nano, но тут уже каждому своё.
Сейчас я предполагаю что у нас компьютер с двумя сетевыми картами. Если это сетевые карты Intel, то драйвер для них называется em, и соотвественно именоваться они будут em0 и em1.
Посмотреть какие сетевые интерфейсы наличиствуют в компьютере можно через
Код: Выделить всё
ifconfig -a
Настроить интерфейсы в openbsd очень просто. Для настройки любого интерфейса достаточно создать файл
Код: Выделить всё
/etc/hostname.<int name>
В моём случае, первый интерфейс был настроен при установке, у него статичный адрес и он смотрит в интернет.
Следующий интефейс будет смотреть в локалку. В моём случае это em1 и файлик /etc/hostname.em1
Добавим туда следующее:
Код: Выделить всё
inet 192.168.0.1 255.255.255.0 NONE description "LAN Link"
В данном случае inet означает что мы добавляем ipv4 адрес, далее идёт сам адрес и маска подсети. NONE означает что не указан специфичный broadcast адрес, и в нашем случае он автоматически становится 192.168.0.255. Description это просто описание интерфейса для нагладности. Его будет видно в ifconfig.
Я подразумеваю что первый интефейс был настроен при установке. Но если это не так, то адрес ему надо присвоить аналогичным образом, после чего вписать адрес основного шлюза в файл /etc/mygate и так же вписать собственное имя хоста в /etc/myname.
Днс настраивается точно так же как и в linux, через /etc/resolv.conf. В формате nameserver <server> Я думаю логично вписать туда
Код: Выделить всё
nameserver 127.0.0.1
Код: Выделить всё
/etc/rc.d/unbound start
Теперь нужно дать разрешение ядру форвардить пакеты. Для этого нужно создать /etc/sysctl.conf.
Но сами мы этого делать не будем. К счастью для этого у нас есть папка /etc/examples, откуда мы этот sysctl.conf и скопируем.
Код: Выделить всё
cp /etc/examples/sysctl.conf /etc
И в нём раскоментируем строку
Код: Выделить всё
net.inet.ip.forwarding=1
Ативируем изменения командой
Код: Выделить всё
sysctl -a
Теперь наш шлюз может перенаправлять пакеты. Настало время сконфигурировать сам pf.
Начнём с очень простой конфигурации. Вначале файлика сделаем простые объявления, чтобы в случае изменения конфиругации компьютера, не пришлось бы долго изменять весь конфиг. А openbsd очень просто и лихо переносится на другой компьютер!
Код: Выделить всё
wan=em0
lan=em1
lan_net=$lan:network
А вот в самый конец файла будем добавлять нашу фильтрацию!
Я всегда начинаю с очень простого правила:
Код: Выделить всё
block in on $wan
Невооружённым глазом видно что это правило блокирует весь входящий трафик на внешний интерфейс. И тут мы уже используем не имя интерфейса а макро, которое прописали вначале.
Теперь нам нужно разрешить доступ извне к ssh серверу, но при этом защитить его от нежелательных гостей:
Код: Выделить всё
table <ssh-brute> persist
block in quick from <ssh-brute>
pass in quick on $wan inet proto tcp to port ssh flags S/SA keep state (max-src-conn-rate 2/60, overload <ssh-brute> flush global )
Объясняю как это работает:
Первая строка это объявление таблицы, в которой будет хранится список врагов, persist означает что таблицу надо держать в памяти постоянно, иначе она может быть сброшена, когда перестанет использоваться правило с которым она связана.
Вторая строка это "быстрая" блокировка всех кто есть в таблице. PF работает с правилами по очереди. Тут подходит логика "использовать последнее подходящее правило" соотвественно, чтобы он не искал других правил, добавляем quick и это правило сработает сразу же.
Ну а теперь нужно в эту таблицу врагов воткнуть! Для этого и есть третья строка. Пока врага нет в таблице, второе правило не работает и применятся именно это правило, давайте разберём его по пунктам:
pass in quick - это понятно, пускаем входящий пакет быстро, чтобы правила которые имеются далее, нечаянно не помешали нам фильтровать.
on $wan inet. Это тоже не кажется сложным. on $wan означает что интерфейс внешний, inet означает ipv4 адреса. Кстати обратите внимание, этим же правилом мы разрешаем доступ к ssh только по ipv4! ipv6 будет заблокирован нашим первым правилом! block in on $wan
Далее идёт связка proto tcp to port ssh, то есть мы разблокируем именно tcp, и порт ssh. Описание какой порт как называется можно подсмотреть в /etc/services.
Далее уже посложнее, flasg S/SA, эта связка указывает как нужно работать в флагами tcp. Это касается именно tcp протокола, и работает по схеме check/mask. Грубо говоря этим правилом мы указываем pf чтобы он обращал внмание на пакеты с флагами S и A (вторая часть дроби) а правило совпадало если пакет с флагом S. Всё таки поскольку эта статья для новичков, давайте не углублятся в основы tcp, а просто поверьте что это должно быть именно так.
Далее идёт кусок keep state. Это поведение pf по умолчанию, и оно здесь только затем, чтобы pf не ругался на синтаксис, потому что после keep state идут скобки, которые односятся именно к keep state.
А что в скобках: max-src-conn-rate это ограничение на количество срабатывания данного правила. а нашем случае 2 раза на 60 секунд. overload означает что при перегрузке нужно отправить адрес источника в указанную таблицу. flush global означает что все уже созданные подключения этим хостом должны быть сброшены. Когда правило сработает, злоумышленник уже будет в таблице ssh-brute, и pf проверив его - не пустит.
Только обратите внимание на то, что ssh сервер сбрасывает соединение не сразу. У источника будет несколько попыток ввести пароль за одну сессию! Это число регулируется через maxauthtries в /etc/ssh/sshd_config. То есть в нашем случае 2/60 вовсе не означает 2 раза неправильно введённый пароль. Это означает двукратное подключение! Обратите так же внимание что правило не защищает от подбора пароля из локалки! Блокировка у нас стоит только снаружи.
Защищать или не защищать ssh изнутри - это уже дело читателя.
Это совсем немного сложно, но согласитесь, это же намного проще дебрей iptables где куча бестолковых таблиц и нет нормального конфига, не правда ли?
Поехали дальше!
Добавим правила чтобы разрешить icmp, потому что он как правило безвредный (напомню, правилом block in on $wan мы заблокировали абсолютно всё!) а так же разрешим доступ в ftp и к dns (подразумевается что наш шлюз будет ещё и dns
Код: Выделить всё
pass proto icmp
pass in on $wan inet proto {tcp,udp} to port domain
pass in on $wan inet proto tcp to port { ftp, www, https, 49151:65535 }
правила совсем простые. Я не думаю что надо дополнительно что-то тут разъяснять. открываем tcp и udp порт для domain, открываем tcp порты для ftp, www, https (21, 80, 443 порты) а так же диапазон, этот диапазон - для родного встроенного в openbsd ftpd.
И теперь когда мы разрешили доступ к необходимым сервисам, разрешим клиентам из локалки попадать в интернет!
Код: Выделить всё
pass out on $wan from $lan_net nat-to $wan:0
pass out on $wan означает что нужно пропускать пакеты на выход из внешнего интерфейса, from $lan_net - этим мы указываем какой сети разрешено выходить во внешнюю сеть, впереди у нас будут и другие сети, поэтому это имеет значение.
nat-to $wan:0 это особенность pf, означает что мы будем транслировать адреса в первый адрес интерфейса $wan. бывает такое что на интерфейсе wan может быть присвоен не один ip, данное правило транслирует адреса именно в первый адрес.
Обычно достаточно указать просто интерфейс, или просто ип адрес в который нужно транслировать. Однако я хочу показать насколько гибок pf, к тому же далее нас ждут новые и новые правила, которые придётся добавить по мере добавления других статей.
Всё, теперь можно наконец применять наши правила. Сначала давайте проверим синтаксис:
Код: Выделить всё
pfctl -n -f /etc/pf.conf
Нужно писать именно в такой последовательности! Сначала -n , потом -f, потом файл.
Если будут ошибки, pf скажет в какой строке. Если нет, мы просто получим очередное приглашение команднкой строки.
Теперь если всё в порядке применяем правила:
Код: Выделить всё
pfctl -f /etc/pf.conf
Если теперь добавить клиентам локальной сети нужный ip и шлюз, должен пойти пинг до ip адресов в интернете. Давайте добавим нашему шлюзу возможность обеспечивать локальную сеть dns сервером.
Для этого отредактируем /var/unbound/etc/unbound.conf
И добавим всего две строки в нужные места. Это
Код: Выделить всё
interface: 192.168.0.1
и
Код: Выделить всё
access-control: 192.168.0.0/24 allow
Куда их добавить будет очень видно. Теперь перезапускаем unbound и вуаля, имеем dns.
В качестве последей ступени можно добавить dhcpd, пример его конфига можно так же взять в /etc/examples.
Давайте я не буду останавливаться на этом, думаю с такой простой задачей читатель разберётся самостоятельно.
Теперь у нас есть замечательный шлюз, и настала пора рассказать как расширить функциональность!
Иногда бывает полезным функция upnp. Она позволяет клиентам из локальной сети запрашивать у шлюза перенаправление нужного им порта "на себя" это может быть полезно например если есть плейстейшн или вражеский скайп в сети. Или та же торрентилка. Ну я бы сказал что всё это полезно именно дома, в условиях предприятия такой функционал совершенно не нужен. Однако настройка этого действа затрагивает такую вещь как якоря, о которых то я как раз и хотел поведать.
Для активации upnp ставим сначала miniupnpd
Код: Выделить всё
pkg_add miniupnpd
Теперь его нужно сконфигурировать.
Указываем ему внешний интерфейс: ext_ifname=em0
интерфейс который будет слушать запросы с локалки: listening_ip=192.168.0.1/24
а так же разрешаем локалке открывать порты: allow 1024-65535 192.168.0.0/24 1024-65535
Это означает что можно открывать внешние порты 1024-65535, адресам 192.168.0.0 и перенаправлять их на порты 1024-65535. Надеюсь понятно.
Переходим к pf.
Нужно где-нибудь после правила block in on $wan вписать правило:
Код: Выделить всё
anchor "miniupnpd"
Теперь постарайтесь понять как будет работать это правило.
miniupnpd прекрасно знает синтаксис pf, и pf теперь знает, что miniupnpd будет давать ему правила.
когда кто-то из локальной сети попросит перенаправить порт на внутренний комп, miniupnpd создаст правило вида
pass in quick on em0 (это то что мы указали вначале конфига miniupnpd) proto tcp port <какой-либо порт> rdr-to <комп из локалки>
и на месте, где в конфиге pf указан anchor miniupnpd появится это правило! Сгенерированные таким образом правила можно посмотреть коммандой
Код: Выделить всё
pfctl -a miniupnpd -s rules
Очень просто! Было бы гениальным решением если бы кто-то из разработчиков fail2ban добавил бы в него возможность работы с якорями pf, но пока к сожалению нет

Последнее о чём я собирался рассказать в этой статье это туннели. Часто для этого используют openvpn и это очень хорошее решение! Однако в OpenBSD есть родной способ организовать шифрованный тоннель, и это очень просто (как и всё в OpenBSD)
Для огранизации туннеля средствами openbsd достаточно отредактировать /etc/ipsec.conf и внести туда вот такие коррективы:
Код: Выделить всё
local_gw = "1.2.3.4"
remote = "5.6.7.8"
lan = "192.168.1.0/24"
remote_lan = "192.168.2.0/24"
ike esp from $lan to $remote_lan peer $remote
ike esp from $local_gw to $remote_lan peer $remote
ike esp from $local_gw to $remote
Только разумеется подстроить свой и удалённый адреса соотвественно! Подразумевается что на обоих машинах есть реальные ip адреса. На удалённой машине нужно сделать всё тоже самое, но адреса разумеется прописать зеркально!
После чего нужно файл /etc/isakmpd/local.pub скопировать на удалённую машину в папку /etc/isakmpd/pubkes/ipv4/1.2.3.4
Аналогичное дейвствие проделываете с удалённой машиной, её local.pub копируете себе в /etc/isakmpd/ipv4/5.6.7.8
разумеется в обоих случаях ip адреса нужно заменять нужными адресами.
После чего запускаете демон isakmpd и вписываете в rc.conf.local примерно так:
Код: Выделить всё
isakmpd_flags="-K"
ipsec=YES
После перезапуска обоих систем должен появится пинг до удалённой сети! Очень просто!
Чтож, я не описал много того что хотел бы, но в целом положил начало моему циклу статей! Постараюсь в будущих статьях более полно рассказать о всех нюансах системы. Но во всех них я буду опираться на этот минимальный конфиг, который сейчас был создан.
Спасибо за внимание
Конец 1й части.