Про то, что Linux изначально разрабатывалась как сетевая операционная система я думаю знают все. Поэтому в этой ОС можно вносить достаточно серьезные изменения в сетевую конфигурацию. Как говорится, в Линуксе можно все, главное знать как. Но прежде, чем начать обсуждение темы тонких настроек совершим небольшой экскурс в историю развития Линукс.
В прежние времена (а точнее до версии ядра 1.3.57) если пользователю требовалось внести какие-то изменения в системные параметры ОС необходимо было перекомпилировать ядро. Естественно, пересборка ядра была не самой тривиальной задачей и при неумелом обращении данная операция вполне могла привести к краху системы. Поэтому в качестве альтернативы разработчики предложили sysctl. Sysctl - это программная утилита, предназначенная для считывания и изменения атрибутов системного ядра, таких как номер версии, максимальные ограничения и параметры безопасности. Она доступна как в виде системного вызова для скомпилированных программ, так и в виде команды администратора для интерактивного использования и написания сценариев.
С помощью sysctl можно изменять различные параметры полный список которых можно получить с помощью команды
sysctl -a
Однако, результат вывода этой команды будет содержать много лишней информации, связанной с настройками ядра операционной системы. Но нас в рамках сегодняшней статьи интересуют сетевые параметры, для получения которых можно запустить команду с ключом:
sysctl net.ipv4
Если нужно посмотреть значение конкретного параметра, то воспользуемся:
sysctl net.ipv4.ip_forward
Помимо sysctl есть еще один способ узнать значение конкретного параметра
cat /proc/sys/net/ipv4/ip_forward
Соответственно для изменения значений параметров мы также можем воспользоваться sysctl:
sysctl net.ipv4.ip_forward=1
а можем изменить параметр непосредственно в файле:
echo 1 >/proc/sys/net/ipv4/ip_forward
Однако, значения этих параметров сохранятся в системе только до перезагрузки. Для того, чтобы сохранить их в системе необходимо внести соответствующие правки в файл /etc/sysctl.conf.
nano /etc/sysctl.conf
Также, для применения изменений необходимо воспользоваться командой sysctl -p [filename]
Но это было лишь вступление, рассказывающее о том, как работать с параметрами ядра, а дальше мы перейдем к непосредственно к тонкой настройке.
Боремся с затоплениями
Начнем нашу настройку мы с внесения изменений в параметры ICMP. Широковещательные ICMP пакеты могут использоваться для реализации атаки с затоплением. В чем заключается ее суть.
Злоумышленник посылает ICMP echo request-пакеты с адресом жертвы в качестве источника, на broadcast-адреса крупных сетей. В результате каждая из машин ответит на этот фальшивый запрос, и машина-отправитель (жертва) получит больше количество ответов. Посылка множество broadcast-echo requests от имени "жертвы" на broadcast-адреса крупных сетей, можно вызвать резкой заполнение канала "жертвы".
Для того, чтобы не принимать участия в подобном “мероприятии” необходимо настроить во первых игнорирование широковещательных запросов и во-вторых поддельные ответы на широковещательные кадры (нарушение RFC1122):
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
Продолжая тему затоплений не лишним будет вспомнить “старый добрый” SYN flood. Это атака на отказ в обслуживании, которая заключается в отправке большого количества SYN-запросов, то есть запросов на подключение по протоколу TCP в достаточно короткий срок.
Напомним, как устанавливается TCP соединение. Согласно процессу «трёхкратного рукопожатия» TCP, клиент посылает пакет с установленным флагом SYN (synchronize). В ответ на него сервер должен ответить комбинацией флагов SYN+ACK (acknowledges). После этого клиент должен ответить пакетом с флагом ACK, после чего соединение считается установленным.
Соответственно, злоумышленник, посылая SYN-запросы, переполняет на машине жертвы очередь на подключения. При этом он игнорирует SYN+ACK пакеты цели, не высылая ответные пакеты, либо подделывает заголовок пакета таким образом, что ответный SYN+ACK отправляется на несуществующий адрес. В очереди подключений появляются так называемые полуоткрытые соединения, ожидающие подтверждения от клиента. По истечении определенного тайм-аута эти подключения отбрасываются. Задача злоумышленника заключается в том, чтобы поддерживать очередь заполненной таким образом, чтобы не допустить новых подключений. Из-за этого клиенты, не являющиеся злоумышленниками, не могут установить связь, либо устанавливают её с существенными задержками.
Для защиты от SYN-flood в sysctl.conf необходимо включить SYN cookies (мы будем избегать сброса новых соединений, когда очередь TCP-соединений будет переполнена), изменить размер SYN backlog (размер очереди) и уменьшить количество повторных попыток SYN/ACK:
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_synack_retries = 3
Закручиваем другие гайки
Продолжая тему безопасных сетевых настроек, можно порекомендовать отключить перенаправление ICMP пакетов. Естественно, делать это можно только на узлах, не выполняющих маршрутизацию:
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
Аналогично можно запретить форвардинг в принципе
net.ipv4.ip_forward = 0
Далее нам необходимо отключить прием маршрутов для того, чтобы нам не подсунули неправильные маршруты. Злоумышленник может попытаться подсунуть поддельные маршруты для того, чтобы перенаправить весть трафик через узел, который он контролирует (атака Man In The Middle).
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
Включим проверку обратного маршрута, чтобы защититься от спуфинга. Однако, если у вас используется несимметричная маршрутизация (да, надо хорошо знать свою сеть), то лучше эти опции не включать:
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
Ну и вообще неплохо бы логировать пакеты, пришедшие с несуществующих адресов. Хотя здесь есть риск засорения логов ненужными сообщениями, так что лучше проверить опытным путем.
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1
Также включаем аналогичные настройки для IPv6.
net.ipv4.conf.default.secure_redirects = 0
net.ipv6.conf.all.accept_redirect = 0
net.ipv6.conf.default.accept_redirect = 0
net.ipv6.conf.all.accept_ra = 0
net.ipv6.conf.default.accept_ra = 0
А если IPv6 вообще не используется, то его проще отключить. Меньше сервисов - меньше проблем:
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
Улучшаем производительность
После того, как мы настроили безопасность, самое время поработать над производительностью сетевых компонентов. Начнем с общих настроек потребления памяти для протокола TCP.
При передаче пакетов существует требование фиксированного значения размера окна отправки и получения данных (TCP Window). Это связано с тем, что отправитель должен отслеживать отправленные им байты до тех пор, пока не получит подтверждение обратно. Потому что, если подтверждение не приходит, тогда отправитель должен повторно отправить все байты (если они в буфере, он может отправить их повторно. Следовательно, эти данные буфера не сбрасываются до тех пор, пока не придет подтверждение.)
Для начала включим масштабирование окна TCP, тем самым мы увеличим объем данных, передаваемых получателю:
net.ipv4.tcp_window_scaling = 1
Однако, даже после включения опции масштабирования окна максимальный объем данных, который может быть отправлен получателю без получения обратного подтверждения, зависит еще от размеров окна приема. Это максимальный объем данных, который получатель может буферизировать перед обработкой принимающим приложением. Следовательно, нам нужно изменить размер окна приема на большее максимальное значение.
net.core.rmem_max = 16777216
Аналогично, нам необходимо указать максимальное значение окна отправки, и эти значения должны совпадать.
net.core.wmem_max = 16777216
И еще несколько переменных, изменение значения которых может повлиять на производительность.
Переменная net.ipv4.tcp_rmem имеет три значения: минимум, по умолчанию, максимум и определяет размер приемного буфера сокетов TCP. Каждый сокет TCP при создании имеет право использовать минимальный объем памяти. Размер минимального буфера по умолчанию составляет 8 Кбайт (8192). Значение по умолчанию определяет количество памяти, допустимое для буфера передачи сокета TCP. И максимум это максимальный размер буфера, который может быть автоматически выделен для приема сокету TCP.
net.ipv4.tcp_rmem = 4096 87380 16777216
Переменная net.ipv4.tcp_wmem также содержит три значения, определяющих минимальное, принятое по умолчанию и максимальное количество памяти, резервируемой для буферов передачи сокета TCP. Здесь аналогично предыдущему при минимуме каждый сокет TCP имеет право использовать память по факту своего создания. Но размер минимального буфера по умолчанию составляет только 4 Кбайт (4096). Размер принятого по умолчанию буфера обычно составляет 16 Кбайт (16384). И максимум это максимальное количество памяти, которое может быть автоматически выделено для буфера передачи сокета TCP.
net.ipv4.tcp_wmem = 4096 65536 16777216
На сильно загруженных серверах имеет смысл уменьшить число неудачных попыток, после которого уничтожается соединение TCP, закрытое на стороне клиента. Это значение можно указать с помощью параметра net.ipv4.tcp_orphan_retries. По умолчанию обычно указывают 7, но если система сильно загружена, имеет смысл уменьшить это значение так как закрытые соединения могут поглощать достаточно много ресурсов.
net.ipv4.tcp_orphan_retries = 0
И напоследок еще один параметр ядра для оптимизации. Если интерфейс получает много пакетов, ядро может обрабатывать их недостаточно быстро. Вы можете увеличить количество пакетов, удерживаемых в очереди (backlog), изменив значение net.core.netdev_max_backlog:
net.core.netdev_max_backlog = 5000
Заключение
С помощью представленных в статье параметров можно усилить защищенность системы и увеличить ее производительность. Однако, многие значения параметров требуют определенного времени для получения оптимальных значений производительности.
Что такое инфраструктура как код? Что значит «сервера снежинки»? Как автоматизировать работу с серверами? Ответы на эти и другие вопросы дадим на бесплатном уроке, после которого вы узнаете как автоматизировать рутинные процессы создания и настройки серверов с помощью инструментов vagrant, terraform, ansible.