Задача — запустить EC2 с OpenBSD, установить NGINX, добавить настройки для его безопасной работы.
Позже — сюда же можно добавить Fail2ban, PSAD и AIDE. Кроме того — у AWS имеется сервис
Описание создания 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 deraadt@amd64.openbsd.org:/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
Неплохой обзор по работе с 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 (setevoy@ip-172-31-32-110.eu-west-1.compu) 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 (setevoy@ip-172-31-32-110.eu-west-1.compu) 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 root@52.213.7.108 -p 2222 root@52.213.7.108's password: Permission denied, please try again.
Под новым пользователем:
$ ssh setevoy@52.213.7.108 -p 2222 setevoy@52.213.7.108'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:
Ссылки по OpenBSD:
#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):user@setevoy.kiev.ua 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):user@domain.kiev.ua 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:
Автообновление сертификата
В 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
server { listen 443 ssl; server_name openbsdtest.setevoy.org.ua; add_header Strict-Transport-Security "max-age=31536000; includeSubdomains"; ...
Добавляем заголовок X-Frame-Options
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; ...
Проверяем тут:
Рейтинг B.
Генерируем ключ параметров для установления сессии по протоколу
# 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 код
Разрешаем только определённые типы запросов к серверу:
... 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:
Strong SSL Security on nginx