ownCloud, как утверждает Википедия — это Свободное и открытое веб-приложение для синхронизации данных, расшаривания файлов и удалённого хранения документов в «облаке». И, как мне кажется, довольно интересное решение для организации собственного домашнего облака.
Однако, ownCloud, устанавливающийся в виде плагина в системе FreeNAS, да и просто из коробки, имеет ряд недостатков, от которых хотелось бы избавится даже при использовании дома:
- Во-первых, устанавливается в связке с SQLite, что подходит только если у вас небольшое кол-во файлов и пользователей, и абсолютно не подходит, если вы планируете синхронизацию с помощью клиента. У меня же хранилище уже расползлось почти на 5Tb и установленный таким образом ownCloud просто отказывался видеть часть файлов. Да и без синхронизации отдача от облака не велика. Заменим базу данных на MariaDB.
- Во-вторых, отсутствует работа по https, а мне совсем не нравится мысль о том, что кто-то может перехватить мои файлы. Включим https.
- В-третьих, начисто отсутствует защита от банального подбора пароля методом брутфорса. Защитимся от брутфорса с помощью fail2ban.
- В-четвёртых, мне лень часто просматривать логи на предмет взлома, но очень хочется оперативно узнавать о таких попытках. Настроим push-оповещения о попытках подбора пароля с помощью сервиса pushover.net.
Хочу сразу оговориться. Я не являюсь IT-специалистом, я всего лишь менеджер проектов в одном из российских системных интеграторов, а данная «инструкция» родилась в попытках настроить все 4 указанных пункта на своей домашней системе, FreeNAS работающей из-под Esxi. Инструкция написана новичком для новичков, поэтому если где-то есть явные ляпы или ошибки в командах и конфигах, то прошу указать их в комментариях.
Все настройки будем делать из консоли, ручками, максимально приближено к тому, как это, как мне видится, делают «взрослые» айтишники.
1 Подготовка Jail для ownCloud
1.1 Создаём Jail
Данный шаг описывать не буду. Если у вас получилось установить FreeNAS и он у вас работает, то проблем с данным шагом у вас быть не должно. Создание первого Jail может занять довольно продолжительное время.
1.2 Открываем доступ по SSH к данному Jail
Удобнее всего дальнейшую настройку выполнять не через web-терминал, а через полноценную программу-терминал. Например, putty. Для этого откроем доступ по SSH к нашему Jail и создадим нового пользователя, от которого и будем проводить дальнейшую настройку.
Выбираем в web-интерфейсе FreeNAS созданный нами Jail и нажимаем внизу кнопку Shell.
В веб-консоли Jail вводим:
# sysrc sshd_enable="YES"
Запускаем демон для работы ssh:
# service sshd start
Создаём пользователя от имени которого будем потом настраивать нашу систему. Пользователь будет иметь привилегии superuser, для чего мы включим его в группу wheel.
# adduser
Настройки adduser
Usrname: Новый пользователь от имени которого мы будем производить все манипуляции в терминале. Вводим, например, superstepa.
Full name: Полное имя этого пользователя. Вводим, например, Dyadya Stepa Policeman.
Uid (Leave empty for default): Ну раз просят оставить пустым, то так и сделаем. Смело жмём Enter.
Login group [superstepa]: Мы хотим чтобы наш пользователь обладал всеми правами местного администратора — superuser, а следовательно включаем его в группу wheel.
Login group is wheel. Invite superstepa into other groups? []: Нажимаем Enter.
Login class [default]: Жмём Enter.
Shell (sh csh tcsh git-shell nologin) [sh]: Оставляем по-умолчанию sh. Просто жмём Enter.
Home directory [/home/superstepa]: И опять Enter.
Home directory permissions (Leave empty for default): И снова Enter.
Use password-based athentications? [yes]: Хотим чтобы аутентификация этого пользователя проходила по паролю? Конечно да! Жмём Enter.
Use an empty password? (yes/no) [no]: Мы же за безопасность и не хотим чтобы у нового пользователя с правами superuser был пустой пароль. А значит очередной раз жмём Enter.
Use a random password? (yes/no) [no]: Я просто уверен, что придуманный нами пароль самый надежный. И мы хотим использовать именно его. А следовательно Enter.
Enter password: Ага, а вот и он. Вводим свой пароль.
Enter password again: Вводим его снова.
Lock out the account after creation? [no]: Нет, блокировать этот аккаунт не нужно. Просто Enter.
OK? (yes/no): Проверяем всё ли верно и если да, то пешем yes.
Add another user? (yes/no): Других пользователей нам не надо. No.
2 Установка и подготовка к работе ownCloud
Присоединяемся с помощью программы-терминала к нашему Jail.
Вводим имя созданного нами пользователя и его пароль.
На приглашение командной строки $ пишем su. Теперь приглашение командной строки сменится на что-то типа root@ownCloud:/usr/home/superstepa #, а все наши команды будут выполняться от имени superuser.
Для упрощения, приглашение командной строки я буду обозначать символом #, а мои комментарии, которые вводить не надо, буду начинать с //.
2.1 Устанавливаем необходимые пакеты
Сначала обновляем текущие пакеты:
# pkg upgrade
Затем устанавливаем необходимые для работы ownCloud пакеты (на все возникающие вопросы отвечаем yes):
# pkg install mariadb100-server php56-extensions php56-bz2 php56-curl php56-exif php56-fileinfo php56-gd php56-mbstring php56-mcrypt php56-pdo_mysql php56-openssl php56-zip php56-zlib pecl-APCu pecl-intl
Для того, чтобы включить работу по https, собираем с нужными нам пакетами, а затем и устанавливаем из портов, web-сервер nginx:
# portsnap fetch extract // скачиваем копию коллекции портов, это может занять много времени
# cd /usr/ports/www/nginx && make config // конфигурируем и собираем web-сервер nginx
В процессе сборки убеждаемся, что выбраны следующие пакеты:
IPV6
HTTP
HTTP_CACHE
HTTP_DAV
HTTP_FLV
HTTP_GZIP_STATIC
HTTP_PERL
HTTP_REWRITE
HTTP_SSL
HTTP_STATUS
WWW
# make install
2.2 Создаём самоподписанные ключи и сертификаты
# cd /usr/local/etc/nginx/
Создаём корневой ключ server.key (алгоритм шифрования des3, длиной 1024 bit):
# openssl genrsa -des3 -out server.key 1024
Для этого система дважды попросит ввести парольную фразу. Придумываем её и вводим.
Создаём корневой сертификат:
# openssl req -new -key server.key -out server.csr
Отвечать на вопросы можно как угодно. Главное:
— на первый запрос Enter pass phrase for server.key ввести правильный пароль от корневого ключа созданного ранее,
— обязательно ответить на все вопросы, иначе клиент ownCloud в дальнейшем может отказаться от синхронизации файлов,
— запомнить введённые данные, чтобы в дальнейшем можно было легко вспомнить, что сертификат именно Ваш,
— запомнить пароль введённый на вопросе A challenge password []:.
Можно изменить срок действия нашего сертификата, например до 10000 дней, добавив в команду выше аргумент -days 10000.
# cp server.key server.key.org //копируем наш ключ
# openssl rsa -in server.key.org -out server.key //удаляем пароль из ключа
# openssl x509 -req -days 3650 -in server.csr -signkey server.key -out server.crt // Генерируем сертификат
2.3 Включаем автозапуск web-сервера, PHP и базы данных
# sysrc nginx_enable="YES" php_fpm_enable="YES" mysql_enable="YES"
2.4 Устанавливаем редактор для удобного редактирования конфигов
Всё-таки мы еще «маленькие» и пользоваться предустановленным редактором vi нам еще сложновато, поэтому поставим простенький редактор nano (на все возникающие вопросы отвечаем yes).
# pkg install nano
Внимание:
После установки редактора, попробуйте его запустить командой nano. В каких-то непонятных пока мне случаях что-то идёт не так и вместо запуска появляется следующая ошибка:
Для того чтобы это исправить выполним всего 2 команды:
Shared object «libiconv.so.2» not found, required «libgmoudle-2.0.so.0
Для того чтобы это исправить выполним всего 2 команды:
# pkg delete -f gettext
# pkg upgrade
2.5 Корректируем конфиг веб-сервера nginx
Как настоящие администраторы, всегда перед корректировкой конфига делаем его копию, чтобы в случае возникновения проблем всегда можно было откатиться назад:
# cp /usr/local/etc/nginx/nginx.conf /usr/local/etc/nginx/nginx.old
И редактируем файл конфига:
# nano /usr/local/etc/nginx/nginx.conf
Всё содержимое конфига заменяем на следующее:
worker_processes 2;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
access_log logs/access.log main;
sendfile off;
keepalive_timeout 65;
gzip off;
ssl_certificate /usr/local/etc/nginx/server.crt; // для того чтобы работал https
ssl_certificate_key /usr/local/etc/nginx/server.key; // для того чтобы работал https
server {
listen 443 ssl; // для того чтобы работал https
root /usr/local/www;
location = /robots.txt { allow all; access_log off; log_not_found off; }
location = /favicon.ico { access_log off; log_not_found off; }
location ^~ /owncloud {
index index.php;
try_files $uri $uri/ /owncloud/index.php$is_args$args;
client_max_body_size 512M; // максимальный размер файла для загрузки
location ~ ^/owncloud/(?:\.|data|config|db_structure\.xml|README) {
deny all;
}
location ~ \.php(?:$|/) {
fastcgi_split_path_info ^(.+\.php)(/.*)$;
fastcgi_pass unix:/var/run/php-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
include fastcgi_params;
fastcgi_param MOD_X_ACCEL_REDIRECT_ENABLED on;
}
location ~* \.(?:jpg|gif|ico|png|css|js|svg)$ {
expires 30d; add_header Cache-Control public;
}
}
}
}
Выход из редактора по нажатию Ctrl+X. Не забываем при выходе сохранять изменения.
2.6 Корректируем конфиг php
# cp /usr/local/etc/php.ini-production /usr/local/etc/php.ini
# nano /usr/local/etc/php.ini
В файле находим следующие строки (используем Ctrl+W для поиска) и даём им указанные значения:
always_populate_raw_post_data = -1 // не забываем убирать ; в начале строки
date.timezone = Europe/Moscow // либо указать Ваш часовой пояс
cgi.fix_pathinfo=0
upload_max_filesize = 512M // либо указать максимальный размер файла доступный для загрузки в наше облако
post_max_size = 512M // либо указать максимальный размер файла доступный для загрузки в наше облако
2.7 Корректируем php-fpm.conf:
# cp /usr/local/etc/php-fpm.conf /usr/local/etc/php-fpm.old
# nano /usr/local/etc/php-fpm.conf
В файле находим следующие строки (используем Ctrl+W для поиска) и даём им указанные значения:
listen = /var/run/php-fpm.sock
listen.owner = www // не забываем убирать ; в начале строки
listen.group = www
env[PATH] = /usr/local/bin:/usr/bin:/bin
2.8 Корректируем /var/db/mysql/my.cnf:
# cp /var/db/mysql/my.cnf /var/db/mysql/my.old
# nano /var/db/mysql/my.cnf
В файле будет пусто, поэтому внесём в него следующие строки:
[server]
skip-networking
skip-name-resolve
innodb_flush_method = O_DIRECT
skip-innodb_doublewrite
innodb_flush_log_at_trx_commit = 2
innodb_file_per_table
expire_logs_days = 1
2.9 Запускаем веб-сервер nginx, PHP, MariaDB и настраиваем базу данных:
# service nginx start && service php-fpm start && service mysql-server start
Если всё было сделано верно, то всё запустится без ошибок и можно попробовать пройти в браузере по адресу https://<YOUR_JAIL_IP>.
Нам напомнят, что сертификат у нас самоподписанный, но приняв его мы попадём на страницу с надписью 403 Forbidden.
Настраиваем базу данных MariaDB:
# mysql_secure_installation
Настройки MariaDB:
Enter current password for root (enter for none): По умолчанию пароля нет, жмём Enter.
Set root password? [Y/n]: Вводим Y.
New password: Вводим новый пароль root.
Re-enter new password: Повторяем введённый ранее пароль.
На все остальные вопросы отвечаем Y, либо просто жмём Enter
Set root password? [Y/n]: Вводим Y.
New password: Вводим новый пароль root.
Re-enter new password: Повторяем введённый ранее пароль.
На все остальные вопросы отвечаем Y, либо просто жмём Enter
Настраиваем базу данных ownСloud введя свои значения, где owncloud — название базы, ownclouduserdb — имя пользователя для работы с базой, а passwordownclouddb — пароль этого пользователя:
# mysql -u root -p
CREATE DATABASE owncloud;
GRANT ALL PRIVILEGES ON owncloud.* TO 'ownclouduserdb' IDENTIFIED BY 'passwordownclouddb';
FLUSH PRIVILEGES;
quit;
2.10 Скачиваем и устанавливаем актуальную версию OwnCloud
По ссылке смотрим текущую актуальную версию ownCloud. На момент написания статьи это была версия 8.0.2.
Скачиваем архив, где вместо 8.0.2 указываем текущую актуальную версию:
# fetch "http://download.owncloud.org/community/owncloud-8.0.2.tar.bz2"
Разархивируем:
# tar jxf owncloud-*.tar.bz2 -C /usr/local/www
Удаляем ненужный теперь нам архив:
# rm owncloud-*.tar.bz2
Назначаем системных владельцев (пользователя и группу) ownCloud:
# chown -R www:www /usr/local/www/owncloud /mnt/files
2.11 Создаём задание в crone:
# setenv EDITOR nano // для редактирования будем использовать установленный нами редактор nano
# crontab -u www -e
Прописываем в нём:
*/15 * * * * /usr/local/bin/php -f /usr/local/www/owncloud/cron.php
Если всё было прописано верно, то мы получим следующее системное сообщение:
crontab: installing new crontab
Идём теперь в браузере по адресу https://<YOUR_JAIL_IP>/owncloud и производим там последние настройки. Не забываем, что нам надо изменить тип применяемой базы данных, а для этого нажмём Хранилище и база данных и выберем наш тип базы: MySQL/MariaDB.
Заполняем поля
Имя пользователя: Имя администратора нашего облака. Например, Stepanadministratovich.
Пароль: Пароль администратора.
Каталог с данными: Я предпочитаю /mnt/files/. В этот каталог я потом монтирую существующие у меня Volumes хранилища FreeNAS. Если надо объяснить как, то пишите в комментариях.
Пользователь базы данных: Мы его создавали ранее на шаге 2.9 ownclouduserdb.
Пароль базы данных: Также назначали ранее на шаге 2.9 passwordownclouddb.
Название базы данных: Всё тот-же шаг 2.9 owncloud.
Наш ownCloud уже готов к работе.
3 Дополнительные настройки
3.1 Просим поисковых роботов (Yandex, Google и т.д.) не индексировать наш сайт:
# ln -s /usr/local/www/owncloud/robots.txt /usr/local/www
4 Защита от подбора пароля
4.1 Устанавливаем fail2ban из портов:
# cd /usr/ports/security/py-fail2ban
# make install clean
Структура каталогов fail2ban
Fail2ban лежит по следующему пути: /usr/local/etc/fail2ban. Структура расположенных там каталогов и файлов:
папка action.d — содержит файлы действий
папка filter.d — файлы фильтров
файл fail2ban.conf — основной файл конфигурации
файл jail.conf — файл настройки защиты конкретных сервисов
папка action.d — содержит файлы действий
папка filter.d — файлы фильтров
файл fail2ban.conf — основной файл конфигурации
файл jail.conf — файл настройки защиты конкретных сервисов
4.2 Настраиваем логирование в ownCloud:
Создаём файл в который будут писаться логи ownCloud при неудачной попытке входа:
touch /var/log/owncloud-acces.log
Файл должен быть доступен для записи пользователю www:
# cd /var/log/
# chown www:www owncloud-acces.log
Включаем логирование неудачных входов в ownCloud:
# nano /usr/local/www/owncloud/config/config.php
В файле находим или добавляем перед самой последней строкой следующие строки (пользуйтесь поиском Ctrl+W) и даём им указанные значения:
'logtimezone' => 'Europe/Moscow', // или другой Ваш часовой пояс
'logfile' => '/var/log/owncloud-acces.log',
'loglevel' => '2',
'log_authfailip' => true,
Проверим ведётся ли логирование неудачных входов:
Несколько раз пробуем войти в web-интерфейс ownCloud с заведомо неправильным паролем или именем пользователя.
Затем выполним в консоли команду:
Если всё сделано правильно, то в файле появятся записи вида:
Затем выполним в консоли команду:
# nano /var/log/owncloud-acces.log
Если всё сделано правильно, то в файле появятся записи вида:
{»reqId":«es09787k250rv52fu0iu44124z494687»,«remoteAddr»:«192.168.1.1»,«app»:«core»,«message»:«Login failed: 'Admin' (Remote IP: '192.168.1.10', X-Forwarded-For: '')»,«level»:2,«time»:«2015-04-04T18:59:50+03:00»}
4.3 Создаём файл фильтра для fail2ban:
nano /usr/local/etc/fail2ban/filter.d/owncloud.conf
В файле пишем следующее:
[Definition]
failregex={"app":"core","message":"Login failed: user '.*' , wrong password, IP:<HOST>","level":2,"time":".*"} // для версий ownCloud<= 7.0.1
{"app":"core","message":"Login failed: '.*' \(Remote IP: '<HOST>', X-Forwarded-For: '.*'\)","level":2,"time":".*"} // для версий ownCloud=7.0.2-7.0.5
{"reqId":".*","remoteAddr":"<HOST>","app":"core","message":"Login failed: .*","level":2,"time":".*"} // для версий ownCloud>=8
По сути это парсер, который во всей той служебной информации, которую ownCloud пишет в свой лог, должен найти ip-адрес того, кто пытался подобрать пароль на вход. Те элементы, что никогда не меняются в записях лога — указаны тут в явном виде. Те, что меняются — заменены на *. Ну а собственно ip-адресс, который мы ищем, заменён на переменную <\HOST>\.
4.4 Редактируем файл настроек сервисов:
# cp /usr/local/etc/fail2ban/jail.conf /usr/local/etc/fail2ban/jail.old
# nano /usr/local/etc/fail2ban/jail.conf
Добавляем в самом низу файла jail.conf:
[owncloud]
enabled = true
filter = owncloud
port = https
logpath = /var/log/owncloud-acces.log // путь к файлу логов ownCloud, который указывали на шаге 4.2
ignoreip = 192.168.1.59 // здесь указываются ip-адреса которые банится не будут
maxretry = 2 // количество неудачных попыток до бана
bantime = 86400 // время бана в секундах
findtime = 600 // время в течение которого введено необходимое для бана к-во попыток в секундах
action = bsd-ipfw // указываем какие файлы действий выполнять
pushover-notify // описание данного файла действий будет ниже по тексту статьи, вводить здесь название данного действия необходимо с новой строки и после нажатия клавиши Tab.
4.5 Проверяем работает ли наш фильтр и может ли он найти в логе ownCloud нужные строки с попытками неудачного входа:
# fail2ban-regex /var/log/owncloud-acces.log /usr/local/etc/fail2ban/filter.d/owncloud.conf
Если всё верно, то внизу выдачи будет строка вида:
Lines: 2 lines, 0 ignored, 2 matches, 0 missed [processed in 0.0 sec]
4.6 Настраиваем действия, которые будут производится в случае неудавшихся попыток входа:
# cp /usr/local/etc/fail2ban/action.d/bsd-ipfw.conf /usr/local/etc/fail2ban/action.d/bsd-ipfw.local
# nano /usr/local/etc/fail2ban/action.d/bsd-ipfw.conf
Оставляем в нём всё по умолчанию. В нём уже прописано правило, что при отправке в бан, ip-адрес добавляется в table(1) файервола ipfw:
actionban = ipfw table \<table\> add \<ip\>
Добавляем в сам файервол ipfw правило, блокирующее все ip-адреса, находящиеся в таблице table(1), т.к. пока нет никаких правил у файервола что делать с адресами из этой нашей таблицы(1):
# ipfw add 1 deny all from table\(1\) to me
Немного примеров по работе с ipfw:
ipfw list //Просмотреть имеющиеся правила
ipfw delete 13 //Удалить правило 13
ipfw add 14 <правило> //Добавить правило 14
ipfw table 1 add 192.168.1.5 //добавление в таблицу
ipfw table 1 add 192.168.1.0/24 //добавление в таблицу подсеть
ipfw table 1 list //посмотреть что в таблице
ipfw add deny ip from table(10) to me //Всё с таблицы 50 ко мне
ipfw table 1 delete 192.168.1.5 //удаляем из таблицы
ipfw table 1 flush //чистим всю таблицу
4.7 Запускаем fail2ban:
Перед запуском создадим для fail2ban файл описывающий действие pushover-notify, о котором была уже речь выше и о котором мы ещё поговорим:
#touch /usr/local/etc/fail2ban/action.d/pushover-notify.conf
Прописываем автостарт fail2ban в /etc/rc.conf:
# sysrc fail2ban_enable="YES"
И запускаем его:
# /usr/local/etc/rc.d/fail2ban start
Если всё сделали правильно, то он запустится, если нет — разбирайтесь где ошибка. Если запустился, то проверяем на бан: заходим со стороннего ip-адреса с неправильным паролем. Должно забанить на время, которое мы указали в файле jail.conf.
Немного примеров по работе с fail2ban, которые могут пригодится в процессе отладки:
fail2ban-client status // Посмотреть какие джейлы активны
fail2ban-client status owncloud // Посмотреть статус конкретного джейла, где owncloud - это имя нашего джейла
fail2ban-client set owncloud unbanip MYIP // Удалить конкретный ip-адрес из бана, где MYIP - этот самый ip-адрес
Собственно теперь у нас есть ownCloud, работающий на «взрослой» базе данных по https с защитой от подбора паролей.
Почти всё, но давайте ещё добавим уведомление о блокировке при неправильном вводе пароля в виде push-уведомлений на наш телефон.
5 Уведомление о блокировке ip-адреса
Для push-уведомлений будем использовать сервис pushover.net. Я думаю Вам теперь не составит труда разобраться с его API. Но если возникнут сложности, то пишите в комментариях и я добавлю соотвествующее описание по работе с данным сервисом.
5.1 Настраиваем уведомления pushover о неудачных попытках входа и бане:
# nano /usr/local/etc/fail2ban/action.d/pushover-notify.conf
В файле прописываем следующее:
[Definition]
actionstart=
actionstop=
actioncheck=
actionban = url -k https://api.pushover.net/1/messages.json -F token=<token> -F user=<user> -F title="ownCloud Alarm" -F message="<ip> is banned after <failures> attemts against <name>"
actionunban = url -k https://api.pushover.net/1/messages.json -F token=<token> -F user=<user> -F title="ownCloud Alarm" -F message="<ip> is unbanned"
[Init]
name = default
token = [API Token/key (application key)]
user = [User key]
, где [API Token/key (application key)] и [User key] соответствующие значения с сайта pushover.net.
Перезапускаем fail2ban
# /usr/local/etc/rc.d/fail2ban restart
Проверяем работу уведомлений выполнив несколько неудачных попыток входа в ownCloud:
Вот и всё. Не забываем пробросить на роутере порты 80 и 443 для доступа к ownCloud.
И да, для большей безопасности можно заменить стандартные порты на что-то более экзотическое.