---
title: "Первые 10 минут на сервере"
date: 2022-10-09T00:38:39+03:00
tag: [linux]
---

Исходная статься на [Хабрахабре](https://habrahabr.ru/company/rootwelt/blog/303462/).

{{< toc >}}

## Азбука безопасности Ubuntu

«[Мои первые 5 минут на сервере](http://plusbryan.com/my-first-5-minutes-on-a-server-or-essential-security-for-linux-servers)» Брайана Кеннеди — отличное введение, как быстро обезопасить сервер от большинства атак. У нас есть несколько исправлений для этой инструкции, чтобы дополнить ею наше [полное руководство](https://github.com/codelittinc/incubator-resources). Также хочется подробнее объяснить некоторые вещи для более юных инженеров.

Каждое утро я проверяю почтовые уведомления logwatch и получаю основательное удовольствие, наблюдая несколько сотен (иногда тысяч) безуспешных попыток получить доступ. (Многие довольно прозаичны — попытки авторизоваться как `root` с паролем `1234` снова и снова). Приведённая здесь общая методика подходит для серверов Debian/Ubuntu, которые лично мы предпочитаем всем остальным. Они обычно служат только хостами для контейнеров Docker, но принципы те же.

На больших масштабах лучше использовать полностью автоматические установки с инструментами вроде [Ansible](https://github.com/ansible/ansible) или [Shipyard](https://shipyard-project.com/), но иногда вы просто поднимаете единственный сервер или подбираете задачи для Ansible — для таких ситуаций предназначена инструкция.

**Примечание: Эта справка создана как базовая азбука. Её следует расширить и дополнить в соответствие с вашими потребностями.**

## В первую очередь

У нас ещё даже нет пароля для рута. Хотелось бы выбрать что-нибудь случайное и сложное. Используем генератор менеджера паролей с настройками максимальной сложности. Менеджер паролей сохраняет пароль и шифрует его, доступ к нему возможен только по длинному мастер-паролю. Здесь предусмотрена пара избыточных мер защиты (длинный, сложный случайный пароль + защита пароля шифрованием и другим длинным паролем). Используете вы парольный менеджер или другие инструменты, сохраняйте пароль в безопасности, применяя какую-нибудь форму шифрования. Вам понадобится только этот рутовый пароль в случае потери пароля sudo.

```bash
# passwd
```

{{< hint title=Примечание >}}
На [HN](https://news.ycombinator.com/item?id=11909543) и [Reddit](https://www.reddit.com/r/netsec/comments/4o7wpo/my_first_10_minutes_on_a_server/) развернулась интересная дискуссия о рутовых паролях. Её стоит почитать.
{{< /hint >}}

Теперь следует обновить репозитории и накатить последние патчи. Далее будет отдельный раздел по автоматизации установки обновлений безопасности.

```bash
apt-get update
apt-get upgrade
```

## Добавляем пользователя

Вам никогда не следует заходить на сервер как рут. Мы следуем тем же правилам при создании пользователей, которые установил Брайан Кеннеди, но вы можете использовать собственные. У нашей маленькой команды не было проблем с использованием единственного пользователя для авторизации, но в больших командах лучше создать разных пользователей с разными уровнями привилегий, где только избранные получают привилегии sudo.

```bash
useradd deploy
mkdir /home/deploy
mkdir /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
```

Устанавливаем предчтительную оболочку для пользователя deploy, мы используем bash:

```bash
usermod -s /bin/bash deploy
```

Помните: `chmod 700` означает, что владелец аккаунта обладает правами на чтение, запись и запуск программ. Мы всё ещё находимся с правами рута, но через минуту мы запустим команду chown рекурсивно на этой папке для пользователя deploy и группы deploy. Только этот пользователь должен иметь право работать с папкой .ssh.

## Аутентификация по ключу ssh

Мы стараемся не использовать пароли для входа на сервер. Насчёт этого было много споров после того как вышла инструкция Брайана, но я тоже склонен согласиться с такой позицией. Вот несколько замечаний на этот счёт:

1. Ключи ssh лучше паролей только потому, что они содержат и требуют больше информации.
1. Пароли можно подобрать брутфорсом. Гадать по публичному ключу по существу невозможно, так что их можно считать полностью безопасными.
1. Что насчёт кражи компьютера? Да, там ваши секретные ключи, но отозвать ssh-key легко, достаточно просто удалить открытый ключ из authorized_keys. Вам следует также защитить секретный ключ безопасной и длинной парольной фразой. См. следующий пункт.
1. Всё это работает ТОЛЬКО ПРИ УСЛОВИИ БЕЗОПАСНОЙ И ДЛИННОЙ ПАРОЛЬНОЙ ФРАЗЫ, ЗАЩИЩАЮЩЕЙ КЛЮЧ. Повторяем второй раз, потому что это критически важно.

Итак, оставим в прошлом аутентификацию по паролю. Скопируйте содержимое id_rsa.pub[^1] со своей локальной машины на серверы в файл authorized_keys.
[^1]: Убедитесь, что указан именно `.pub`. Это кажется очень простым, но я встречал двух товарищей (оба **не** работают в нашей компании — они бы быстро прекратили здесь работать) за свою карьеру, которые прислали мне свои секретные ключи (`id_rsa` без расширения .pub), когда я попросил прислать открытый ключ.

```bash
vim /home/deploy/.ssh/authorized_keys
```

Установим правильные привилегии, руководствуясь принципом безопасности Linux, известным как [принцип минимальных привилегий](https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B8%D0%BD%D1%86%D0%B8%D0%BF_%D0%BC%D0%B8%D0%BD%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D1%85_%D0%BF%D1%80%D0%B8%D0%B2%D0%B8%D0%BB%D0%B5%D0%B3%D0%B8%D0%B9):

```bash
chmod 400 /home/deploy/.ssh/authorized_keys
chown deploy:deploy /home/deploy -R
```

`chmod 400` устанавливает разрешения, так что файл может прочитать только владелец. Другая команда `chown` делает пользователя deploy и группу deploy владельцами (рекурсивно) их домашней директории. Мы упоминали об этом ранее, когда устанавливали разрешения на чтение, запись и исполнение для владельца этой директории.

Вернёмся к этому чуть позже, когда правильно протестируем нашего пользователя deploy и sudo для отключения авторизации рута и установки авторизации только по ключу ssh.

## Тестирование пользователя deploy и установка sudo

Мы собираемся проверить, как происходит авторизация пользователя deploy, в то же время сохраняя открытым соединение по ssh для рута на всякий случай. Если всё работает нормально, мы используем наше открытое подключение рута, чтобы установить пароль для deploy. Поскольку мы отключаем авторизацию по паролю, то этот пароль будет использован при применении sudo. Снова мы запускаем парольный менеджер для генерации сложного и случайного пароля, сохраняем его в зашифрованном виде и сообщаем коллегам (синхронизация зашифрованного файла с паролем).

```bash
passwd deploy
```

Установка sudo простая. Открываем файл sudo:

```bash
visudo
```

Добавляем группу `%sudo` под рутовым пользователем, как показано ниже. Убедитесь, что все остальные пользователи и группы отбиты комментариями с символом `#` (у пользователей нет префиксов, а группы начинаются с %). На большинстве свежих установок там ничего нет, но на всякий случай.

```bash
root ALL=(ALL) ALL
%sudo ALL=(ALL:ALL) ALL
```

Теперь добавим пользователя `deploy` в группу `sudo`.

```bash
usermod -a -G sudo deploy
```

Это предоставит пользователю deploy доступ к sudo после введения пароля, который мы только что создали.

{{< hint title="Замечание к исправлению" >}}
Спасибо пользователю [ackackacksyn](https://www.reddit.com/r/netsec/comments/4o7wpo/my_first_10_minutes_on_a_server/d4aeajf) на Reddit за верное замечание, что не следует добавлять пользователей напрямую в список sudo.
{{< /hint >}}

## Активируем вход по ключу ssh

Конфигурация ssh для этой машины хранится здесь:

```bash
vim /etc/ssh/sshd_config
```

Вы захотите добавить туда несколько строк. Мне кажется, они довольно понятны сами по себе. Это IP-адрес, который вы используете для подключения. У нас в компании используется VPN-конфигурация с OpenVPN и криптографической аутентификацией, так что для подключения к серверу нужно также пройти аутентификацию и быть подключённым к VPN.

```bash
PermitRootLogin no
PasswordAuthentication no
AllowUsers deploy@(your-VPN-or-static-IP)
```

Активируйте все эти правила, перезапустив службы ssh. Вероятно, придётся переподключиться (делайте это через пользователя deploy!).

```bash
service ssh restart
```

## Установка файрвола

Обычно здесь два лагеря. Одни используют IPtables напрямую, а другие применяют удобный интерфейс под названием `ufw`, который представляет собой слой над IPtables для упрощения процесса настройки. Более простой вариант обычно предпочтительнее с точки зрения безопасности. [ufw от DigitalOcean](https://www.digitalocean.com/community/tutorials/how-to-setup-a-firewall-with-ufw-on-an-ubuntu-and-debian-cloud-server) действительно неплох и помогает в основных вещах.

`ufw` установлен по умолчанию на Ubuntu, а на Debian достаточно запустить команду `apt-get install ufw`.

По умолчанию `ufw` должен отказывать во всех входящих подключениях и разрешать все исходящие, однако, он не будет запущен (потому что иначе как бы вы подключились?). Мы пройдёмся и явно разрешим соединения, которые считаются нормальными.

Во-первых, следует убедиться в поддержке IPv6. Откройте конфигурационный файл.

```bash
sudo vim /etc/default/ufw
```

Установите IPv6 в значение **yes**.

```bash
IPV6=yes
```

Для остальных портов, которые мы собираемся открыть, можно просто использовать инструмент `ufw` из командной строки, что очень удобно.

```bash
sudo ufw allow from {your-ip} to any port 22
sudo ufw allow 80
sudo ufw allow 443
sudo ufw disable
sudo ufw enable
```

Первое — это избыточная мера, которая гарантирует, что только соединения с нашего IP-адреса могут соединяться по SSH (стандартный порт SSH)[^2] Вторая и третья команда открывают трафик http и https.
[^2]: Мнения расходятся, назначать ли для соединений SSH стандартный или нестандартный порт. См. [здесь](https://www.adayinthelifeof.nl/2012/03/12/why-putting-ssh-on-another-port-than-22-is-bad-idea/) и [здесь](https://major.io/2013/05/14/changing-your-ssh-servers-port-from-the-default-is-it-worth-it/) аргументы обеих сторон.

{{< hint title=Примечание >}}
Спасибо [chrisfosterelli](https://news.ycombinator.com/item?id=11910341) за замечание, что если вы собираетесь установить первое правило (а вам следует это сделать), то убедитесь, что у вас статичный IP-адрес или безопасный VPN, к которому вы подключаетесь. Динамический IP-адрес оставит вас без доступа к серверу когда-нибудь в будущем.
{{< /hint >}}

## Автоматические обновления безопасности

Мне они нравятся. Они не идеальны, но это лучше, чем пропустить патчи после их выхода.

```bash
sudo apt-get install unattended-upgrades
vim /etc/apt/apt.conf.d/10periodic
```

Обновите этот файл следующим образом:

```bash
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Download-Upgradeable-Packages "1";
APT::Periodic::AutocleanInterval "7";
APT::Periodic::Unattended-Upgrade "1";
```

Я в целом согласен с Брайаном, что лучше отключить обычные обновления, а оставить только обновления безопасности. Идея в том, что будет не очень хорошо, если приложение внезапно перестанет работать из-за обновления какого-то пакета с зависимостями, в то время как обновления безопасности очень редко создают проблемы с зависимостями на уровне приложения.

```bash
sudo vim /etc/apt/apt.conf.d/50unattended-upgrades
```

Отредактируйте файл следующим образом:

```bash
Unattended-Upgrade::Allowed-Origins {
"Ubuntu lucid-security";
//"Ubuntu lucid-updates";
};
```

Всё готово.

## Fail2ban

![Fail2ban](https://hsto.org/files/1f7/093/035/1f7093035bcb4e34888c55ba9a696639.png)

fail2ban — отличный пакет, который проактивно блокирует подозрительную активность, как только она обнаружена. В их [вики](http://www.fail2ban.org/wiki/index.php/Main_Page) сказано, что fail2ban сканирует файлы логов (например, `/var/log/apache/error_log`) и банит IP-адреса, которые проявляют подозрительные признаки — слишком много попыток ввода неправильного пароля, поиск эксплоитов и проч… Сразу после установки Fail2Ban оснащён фильтрами для различных сервисов (apache, courier, ssh и др.).

```bash
sudo apt-get install fail2ban
```

## Двухфакторная аутентификация

Двухфакторная аутентификация обязательна, если мы проектируем систему, которая соответствует нормам безопасности. Теоретически, если вы активируете двухфакторную аутентификацию поверх всех остальных защитных мер, то тогда для получения доступа к серверу (через вскрытие уязвимостей в приложениях), нападающим придётся также иметь:

1. Доступ к вашему сертификату и ключу для доступа к VPN.
1. Доступ к вашему компьютеру, чтобы получить секретный ключ.
1. Доступ к вашей парольной фразе для секретного ключа.
1. Доступ к вашему телефону для двухфакторной аутентификации.

Это немало барьеров (четыре), которые придётся преодолеть. Даже если они получат рутовый доступ через sudo, им придётся найти пароль deploy, который защищён шифрованием AES (пятый барьер).

Устанавливаем пакет.

```bash
sudo apt-get install libpam-google-authenticator
```

Для установки запускаем команду и следуем инструкциям:

```bash
su deploy
google-authenticator
```

Двухфакторная аутентификация устанавливается очень легко и добавляет хороший дополнительный уровень безопасности.

## Logwatch

Этот инструмент скорее для удовольствия и мониторинга постфактум. Logwatch отслеживает логи и в соответствии с настройками высылает по почте ежедневную красиво структурированную сводку. Это довольно занимательные данные, и вы удивитесь, как много попыток доступа к серверу происходит каждый день. Я установил его только для того, чтобы продемонстрировать коллегам, насколько важно иметь хорошую безопасность.

У DigitalOcean есть [отличное описание установки и настройки Logwatch](https://www.digitalocean.com/community/tutorials/how-to-install-and-use-logwatch-log-analyzer-and-reporter-on-a-vps), но если мы хотим уложиться в 10 минут, то просто установим его и сделаем задание cron для ежедневного запуска и отправки письма по электронной почте.

```bash
sudo apt-get install logwatch
```

Добавляем задание cron.

```bash
sudo vim /etc/cron.daily/00logwatch
```

Добавьте следующую строку в файл cron:

```bash
sudo /usr/sbin/logwatch --output mail --mailto you@example.com --detail high
```

## Всё готово

Ну вот. После завершения всего вышеперечисленного вашей основной заботой и точкой сбоя станет ваше приложение и сервисы. Это совершенно другая область.

Мы пытаемся максимально формализовать и описать наши лучшие практики и процессы, если хотите узнать больше, изучите наш [репозиторий](https://github.com/codelittinc/incubator-resources). Всё в открытом доступе, и мы продолжаем пополнять его.
