Задача — запустить EC2 с OpenBSD, установить NGINX, добавить настройки для его безопасной работы.
Позже — сюда же можно добавить Fail2ban, PSAD и AIDE. Кроме того — у AWS имеется сервис AWS WAF (Amazon Web App Firewall), пример его использования можно найти тут>>>.
Описание создания EC2 и сети можно найти тут>>>.
Базовые пакеты для установки:
# pkg_add vim bash curl git wget python-2.7.12 py-pip py-virtualenv
Содержание
OpenBSD basic security
Версия OpenBSD:
# uname -mrs OpenBSD 6.0 amd64
# sysctl kern.version kern.version=OpenBSD 6.0 (GENERIC.MP) #2319: Tue Jul 26 13:00:43 MDT 2016 [email protected]:/usr/src/sys/arch/amd64/compile/GENERIC.MP
Обновляем установленные пакеты:
# pkg_add -Uu quirks-2.271 signed on 2016-12-09T15:55:27Z quirks-2.271: ok
Хотя OpenBSD является системой «Secure by Default» — некоторые изменения можно внести.
Неплохой обзор по работе с OpenBSD можно почитать тут>>>.
Аккаунты, sudo и root логин
Проверяем список пользователей, которые могут логиниться в систему:
# cat /etc/passwd | grep -v nologin root:*:0:0:Charlie &:/root:/bin/ksh
В OpenBSD имеется пакет doas
, как более простая альтернатива sudo
, но если sudo
привычнее — то устанавливаем его:
# pkg_add sudo quirks-2.271 signed on 2016-12-09T15:55:27Z Ambiguous: choose package for sudo a 0: <None> 1: sudo-1.8.18.1 2: sudo-1.8.18.1-gettext 3: sudo-1.8.18.1-gettext-ldap Your choice: 1 sudo-1.8.18.1: ok
doas
установлен по умолчанию.
Добавляем нового пользователя setevoy
, добавив его в группу wheel
:
# adduser ... Enter username []: setevoy Enter full name []: Enter shell bash csh ksh nologin sh [bash]: Uid [1000]: Login group setevoy [setevoy]: Login group is ``setevoy''. Invite setevoy into other groups: guest no [no]: wheel ... Name: setevoy Password: **** Fullname: setevoy Uid: 1000 Gid: 1000 (setevoy) Groups: setevoy wheel Login Class: default HOME: /home/setevoy Shell: /usr/local/bin/bash OK? (y/n) [y]: Added user ``setevoy'' Copy files from /etc/skel to /home/setevoy Add another user? (y/n) [y]: n Goodbye!
Подробнее о работе с пользователями в OpenBSD — тут>>>.
Проверяем логин:
bash-4.4# su -l setevoy -bash-4.4$ su Password: Sorry
Добавляем правило для doas
:
# echo "permit keepenv :wheel" > /etc/doas.conf
Больше о правилах doas
— тут>>> и тут>>>.
Проверяем ещё раз:
$ cat /var/log/daily.out cat: /var/log/daily.out: Permission denied
И через doas
:
$ doas cat /var/log/daily.out doas ([email protected]) password: Checking subsystem status: disks: Filesystem 1K-blocks Used Avail Capacity iused ifree %iused Mounted on /dev/wd0a 8254030 640686 7200644 8% 25482 1039860 2% / ...
Меняем пароль root
:
$ doas passwd root doas ([email protected]) password: Changing password for root. New password: Retype new password:
Запрещаем вход root
по SSH и меняем порт — редактируем /etc/ssh/sshd_config
и устанавливаем:
... Port 2222 ... AllowUsers setevoy ... PermitRootLogin no ...
Перезапускаем sshd
:
# /etc/rc.d/sshd check sshd(ok) # /etc/rc.d/sshd restart sshd(ok) sshd(ok)
Проверяем с рабочей машины под рутом:
$ ssh [email protected] -p 2222 [email protected]'s password: Permission denied, please try again.
Под новым пользователем:
$ ssh [email protected] -p 2222 [email protected]'s password: OpenBSD 6.0-current (GENERIC.MP) #2553: Sun Oct 9 20:50:35 MDT 2016 ... -bash-4.4$
OpenBSD firewall — PF
PF (Packer Filter) — фаервол в OpenBSD по умолчанию.
Основные команды для работы с ним.
Отключить:
# rcctl disable pf
Либо через pfctl
:
# pfctl -d
Включить:
# pfctl -e
pfctl -f /etc/pf.conf
— загрузитьpf.conf
pfctl -nf /etc/pf.conf
— прочитать, но не применять правилаpfctl -sr
— отобразить текущие наборы правилpfctl -ss
— отобразить текущие таблицы состоянияpfctl -si
— вывести статистику пакетов и счётчиковpfctl -sa
— вывести всё
Основные правила доступа к хосту будут заданы через настройки самого AWS, поэтому PF можно использовать только для ручного бана (и Fail2ban).
Редактируем файл /etc/pf.conf
, добавляем описание таблицы и файла, в котором будут хранится правила:
... table <manual_banned> persist file "/etc/pf.banned" block on xnf0 from <manual_banned> to any ...
Перезапускаем PF:
# pfctl -d pf disabled # pfctl -e -f /etc/pf.conf pf enabled
Проверяем. Баним IP:
# pfctl -t manual_banned -T add 77.120.103.20 1/1 addresses added.
Проверяем:
# cat /etc/pf.banned 77.120.103.20
И пробуем подключиться с 77.120.103.20:
$ telnet 52.213.7.108 2222 Trying 52.213.7.108... telnet: connect to address 52.213.7.108: Connection timed out
Просмотреть таблицу:
# pfctl -t manual_banned -T show 77.120.103.20
Удалить правило:
# pfctl -t manual_banned -T del 77.120.103.20
Ссылки по PF:
How to block IP address with pf on FreeBSD, NetBSD and OpenBSD
Ссылки по OpenBSD:
OpenBSD Virtual Server on Vultr Runbook
How to install OpenBSD and make yourself comfortable
#ToDo
- пересылку почтовых уведомлений root
- автоапдейт пакетов
NGINX на OpenBSD
Устанавливаем NGINX:
# pkg_add -v nginx Update candidates: quirks-2.241 -> quirks-2.241 quirks-2.241 signed on 2016-07-26T16:56:10Z Ambiguous: choose package for nginx a 0: <None> 1: nginx-1.10.1 2: nginx-1.10.1-lua 3: nginx-1.10.1-naxsi 4: nginx-1.10.1-passenger ...
Описание всех пакетов можно найти тут>>> (naxsi
— интересное решение, почитать тут>>>).
Выбираем 1:
... Your choice: 1 nginx-1.10.1:pcre-8.38p0: ok nginx-1.10.1: ok The following new rcscripts were installed: /etc/rc.d/nginx See rcctl(8) for details. Look in /usr/local/share/doc/pkg-readmes for extra documentation. Extracted 4897592 from 4899471
В файл /etc/rc.conf.local
добавляем строку:
nginx_flags=""
Добавляем автозагрузку в файл /etc/rc.conf
:
pkg_scripts=nginx
Запускаем, проверяем:
# /etc/rc.d/nginx start nginx(ok) # curl localhost <html> <head><title>403 Forbidden</title></head> <body bgcolor="white"> <center><h1>403 Forbidden</h1></center> <hr><center>nginx</center> </body> </html>
SSL для NGINX — Let’s encrypt
Настраиваем NGINX.
Создаём каталоги для файлов настроек и логов:
# mkdir /etc/nginx/conf.d # mkdir /var/log/nginx/
В файл /etc/nginx/nginx.conf
добавляем:
... include /etc/nginx/conf.d/*.conf; ...
В файл /etc/nginx/nginx.conf
добавляем:
server { listen 80; listen [::]:80; server_name localhost; root /var/www/htdocs; # Allow access to the letsencrypt ACME Challenge location ~ /\.well-known\/acme-challenge { allow all; } ...
Перезапускаем NGINX:
# /etc/rc.d/nginx restart nginx(ok) nginx(ok)
Устанавливаем клиент ACME (Automated Certificate Management Environment protocol).
Полный список клиентов можно найти тут>>>, в данном случае используем certbot
.
Устанавливаем certbot
:
# pkg_add certbot
Запускаем:
# /usr/local/bin/certbot certonly --agree-tos --webroot -w /var/www/openbsdtest.setevoy.org.ua/ -d openbsdtest.setevoy.org.ua Enter email address (used for urgent notices and lost key recovery) (Enter 'c' to cancel):[email protected] IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at /etc/letsencrypt/live/openbsdtest.setevoy.org.ua/fullchain.pem. Your cert will expire on 2017-03-13. ...
В случае ошибки вида:
# /usr/local/bin/certbot certonly --agree-tos --webroot -w /var/www/openbsdtest.setevoy.org.ua/ -d openbsdtest.setevoy.org.ua Enter email address (used for urgent notices and lost key recovery) (Enter 'c' to cancel):[email protected] Abort trap (core dumped)
Добавьте в /etc/fstab
параметр wxallowed
:
# cat /etc/fstab /dev/wd0a / ffs rw,wxallowed 1 1
Проверяем сертификаты:
# ls -l /etc/letsencrypt/live/openbsdtest.setevoy.org.ua/ total 0 lrwxr-xr-x 1 root wheel 50 Dec 13 15:17 cert.pem -> ../../archive/openbsdtest.setevoy.org.ua/cert1.pem lrwxr-xr-x 1 root wheel 51 Dec 13 15:17 chain.pem -> ../../archive/openbsdtest.setevoy.org.ua/chain1.pem lrwxr-xr-x 1 root wheel 55 Dec 13 15:17 fullchain.pem -> ../../archive/openbsdtest.setevoy.org.ua/fullchain1.pem lrwxr-xr-x 1 root wheel 53 Dec 13 15:17 privkey.pem -> ../../archive/openbsdtest.setevoy.org.ua/privkey1.pem
Создаём файл настроек виртуалхоста /etc/nginx/conf.d/openbsdtest.setevoy.org.ua.conf
:
server { listen 443 ssl; server_name openbsdtest.setevoy.org.ua; access_log /var/log/nginx/openbsdtest.setevoy.org.ua-access.log; error_log /var/log/nginx/openbsdtest.setevoy.org.ua-error.log; root /var/www/openbsdtest.setevoy.org.ua; ssl_certificate /etc/letsencrypt/live/openbsdtest.setevoy.org.ua/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/openbsdtest.setevoy.org.ua/privkey.pem; location / { index index.htm; } location ~ /.well-known { allow all; } }
Создаём индексный файл:
# echo "Hello" > /var/www/openbsdtest.setevoy.org.ua/index.html
Проверяем и перезапускаем NGINX:
# nginx -t && /etc/rc.d/nginx reload nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful nginx(ok)
Проверяем:
# netstat -an | grep 443 tcp 0 0 *.443 *.* LISTEN
# curl https://openbsdtest.setevoy.org.ua Hello
С помощью openssl
:
# openssl s_client -showcerts -connect openbsdtest.setevoy.org.ua:443 ... Start Time: 1481643931 Timeout : 300 (sec) Verify return code: 0 (ok) --- closed
Ссылки по теме Let’s Encrypt и OpenBSD:
Easy Secure Web Serving with OpenBSD’s acme-client and Let’s Encrypt
Автообновление сертификата
В cron
добавляем задачу:
@weekly /usr/local/bin/certbot renew --quiet --post-hook "/etc/rc.d/nginx reload"
NGINX security
По умолчанию — NGINX сообщает свою версию:
# curl localhost -I ... Server: nginx/1.11.6
Отключаем, добавив в server {}
файла /etc/nginx/nginx.conf
строку:
... server_tokens off; ...
Проверяем:
# curl -s -D- https://openbsdtest.setevoy.org.ua/ | grep Strict Strict-Transport-Security: max-age=31536000; includeSubdomains
Включаем HSTS (HTTP Strict Transport Security):
server { listen 443 ssl; server_name openbsdtest.setevoy.org.ua; add_header Strict-Transport-Security "max-age=31536000; includeSubdomains"; ...
Добавляем заголовок X-Frame-Options
для запрета отображения страниц в frame/iframe:
server { listen 443 ssl; server_name openbsdtest.setevoy.org.ua; add_header Strict-Transport-Security "max-age=31536000; add_header X-Frame-Options "DENY"; ...
Отключаем автоматическую проверку типа контента для IE, Chrome, Safari:
... add_header X-Content-Type-Options nosniff; ...
Полезным может быть заголовок Content-Security-Policy
(устаревшие — X-Content-Security-Policy
и X-WebKit-CSP
).
Настройка SSL
Добавляем переадресацию с HTTP на HTTPS:
server { listen 80; server_name openbsdtest.setevoy.org.ua; server_tokens off; return 301 https://openbsdtest.setevoy.org.ua$request_uri; } server { listen 443 ssl; server_name openbsdtest.setevoy.org.ua; ...
Проверяем тут: https://www.ssllabs.com/ssltest/analyze.html
Рейтинг B.
Генерируем ключ параметров для установления сессии по протоколу Diffie-Hellman:
# mkdir /etc/ssl/certs # cd /etc/ssl/certs # openssl dhparam -out dhparam.pem 4096
Посмотреть его можно так:
# openssl dhparam -inform PEM -in /etc/ssl/certs/dhparam.pem -check -text PKCS#3 DH Parameters: (4096 bit) prime: 00:ec:d0:cb:10:12:82:63:33:2f:42:2f:8e:40:02: 9f:84:bd:e5:60:9d:76:e3:92:3d:c5:f8:9b:34:06: ... c5:87:dc:de:b8:37:85:94:33:6c:4b:a6:31:c0:4e: da:d7:0b:f7:94:65:14:95:70:12:e2:b2:ac:2a:79: 66:75:7b generator: 2 (0x2) DH parameters appear to be ok
Добавляем в файл настроек:
... ssl_dhparam /etc/ssl/certs/dhparam.pem; ...
Добавляем список поддерживаемых протоколов:
... ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ...
Задаём поддерживаемые алгоритмы шифрования:
... ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH !RC4"; ssl_prefer_server_ciphers on; ...
Включаем кеширование сессий SSL (1MB под кеш, хранить 1 час):
... ssl_session_cache shared:SSL:10m; ssl_session_timeout 1h; ...
Доабвляем OCSP Stapling:
... ssl_stapling on; ssl_stapling_verify on; ...
Проверяем:
# nginx -t && /etc/rc.d/nginx reload nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful nginx(ok)
Рейтинг А+:
Другие параметры
Параметры ниже больше касаются проивзодительности, но имеет смысл добавить их сейчас.
Что бы не выполнять SSL handshake каждый раз для одного клиента — можно добавить keepalive_timeout
:
... keepalive_timeout 70; ...
Запрещаем доступ, если запрос к серверу не включает в себя имя виртуалхоста:
... server_name openbsdtest.setevoy.org.ua; if ($host !~ ^(openbsdtest.setevoy.org.ua|www.openbsdtest.setevoy.org.ua)$ ) { return 444; } ...
HTTP код 444 — закрыть соединение без ответа.
Разрешаем только определённые типы запросов к серверу:
... if ($request_method !~ ^(GET|HEAD|POST)$ ) { return 444; } ...
DELETE
, SEARCH
и прочие — будут отбрасываться.
Заблокировать hotlink-и изображений (за трафик картинок с нашего сервера платим мы, поэтому разрешаем доступ только со своего домена):
... # block hotlinks location ~ .(gif|png|jpe?g)$ { valid_referers none blocked .openbsdtest.setevoy.org.ua; if ($invalid_referer) { return 403; } } ...
Не проверял, подробнее — тут>>>.
Конфигурация, получившаяся в результате:
server { listen 80; server_name openbsdtest.setevoy.org.ua; server_tokens off; return 301 https://openbsdtest.setevoy.org.ua$request_uri; } server { listen 443 ssl; server_name openbsdtest.setevoy.org.ua; if ($host !~ ^(openbsdtest.setevoy.org.ua|www.openbsdtest.setevoy.org.ua)$ ) { return 401; } # Only allow these request methods # Do not accept DELETE, SEARCH and other methods if ($request_method !~ ^(GET|HEAD|POST)$ ) { return 444; } # block hotlinks location ~ .(gif|png|jpe?g)$ { valid_referers none blocked .openbsdtest.setevoy.org.ua; if ($invalid_referer) { return 403; } } keepalive_timeout 70; add_header Strict-Transport-Security "max-age=31536000; includeSubdomains"; add_header X-Content-Type-Options nosniff; add_header X-Frame-Options "DENY"; access_log /var/log/nginx/openbsdtest.setevoy.org.ua-access.log; error_log /var/log/nginx/openbsdtest.setevoy.org.ua-error.log; root /var/www/openbsdtest.setevoy.org.ua; ssl_certificate /etc/letsencrypt/live/openbsdtest.setevoy.org.ua/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/openbsdtest.setevoy.org.ua/privkey.pem; ssl_dhparam /etc/ssl/certs/dhparam.pem; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH !RC4"; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_session_timeout 1h; ssl_stapling on; ssl_stapling_verify on; location / { index index.html; } location ~ /.well-known { allow all; } }
Ссылки по NGINX/TLS:
Top 20 Nginx WebServer Best Security Practices
Nginx SSL and TLS Deployment Best Practices
Strong SSL Security on nginx
How To Secure Nginx on Ubuntu 14.04
Прямая секретность или как достичь максимальной безопасности сайта (про Diffie-Hellman)
Как HTTPS обеспечивает безопасность соединения: что должен знать каждый Web-разработчик (2013 год, но интересные комментарии)
nginx Tuning (производительность)