Задача
Обеспечить доступ из «везде где есть интернет» к некоему ПО. Шифровать траффик между клиентской и серверной частью приложения, которое не умеет работать через SSL. Так же нужно иметь возможность ограничивать доступ некоторым пользователям при необходимости. По различным причинам основные реализации VPN отпали. В процессе поиска решения наткнулся на Stunnel, который идеально подошел. В данной статье постараюсь детально описать процесс настройки.
Статья по большей части составлена из рабочих заметок в довесок с претензиями на туториал, поэтому прошу спокойно относится к капитанству вида — «Первое, что мы сделаем — обновим систему».
Общее представление схемы работы:
ПО клиент (windows) > Stunnel > Интернет > Stunnel > ПО Сервер (linux)
Система: свежеустановленная ubuntu server 14.04 x64.
Приложение трафик которого нужно шифровать я называть не буду. Вместо него буду указывать ssh. Для теста подходит идеально, на мой взгляд.
Приступим
Первое, что мы сделаем — обновим систему:
sudo apt-get update
sudo apt-get upgrade
Настроим и включим ufw:
sudo ufw allow 22/tcp
sudo ufw allow 443/tcp
sudo ufw enable
Установим stunnel:
sudo apt-get install stunnel4
При установке создаются:
— пользователь и группа stunnel4;
— интересные нам каталоги:
- /var/lib/stunnel4 здесь будет chroot окружение
- /etc/stunnel любой файл в этом каталоге оканчивающийся на .conf будет считаться конфигом
- /usr/share/doc/stunnel4/examples с примером конфига внутри
Проведем некоторые подготовительные мероприятия.
Разрешим автозапуск. В файле /etc/default/stunnel4 заменим ENABLED=0 на ENABLED=1:
sudo nano /etc/default/stunnel4
Создадим папки для клиентских сертификатов. certs — разрешенные, crls — запрещенные (отозванные). О самих сертификатах чуть позже.
sudo mkdir /var/lib/stunnel4/certs
sudo mkdir /var/lib/stunnel4/crls
Создадим лог-файл и сменим владельца.
Я не считаю размещение логов в месте отличном от /var/log хорошей идеей, но заставить stunnel писать логи за пределы окружения мне не удалось.
sudo touch /var/lib/stunnel4/stunnel.log
sudo chown stunnel4:stunnel4 /var/lib/stunnel4/stunnel.log
Я буду использовать свой конфиг, но если он вам не подходит можно взять пример в /usr/share/doc/stunnel4/examples
Создадим конфигурационный файл:
sudo nano /etc/stunnel/stunnel.conf
Со следующим содержимым:
; **************************************************************************
; * Global options *
; **************************************************************************
; Каталог chroot окружения.
chroot = /var/lib/stunnel4/
setuid = stunnel4
setgid = stunnel4
; Создается в окружении
pid = /stunnel4.pid
; Уровень болтливости
debug = 7
; Лог-файл
output = /stunnel.log
; Не использовать syslog
syslog = no
; **************************************************************************
; * Service defaults may also be specified in individual service sections *
; **************************************************************************
; Сертификат/ключ сервера
cert = /etc/stunnel/servercert.pem
key = /etc/stunnel/serverkey.pem
; Проверка сертификата. 0 - не проверять, 1 - проверять при наличии, 2 - проверять всегда, ...
verify = 2
; Каталог для разрешенных сертификатов.
; Находится в окружении. Для каждого сертификата должна быть хэш-ссылка
CApath = /certs
; Каталог для запрещенных (отозванных) сертификатов.
; Находится в окружении. Для каждого сертификата должна быть хэш-ссылка
CRLpath = /crls
; Не использвать SSLv2
options = NO_SSLv2
; **************************************************************************
; * Service definitions (remove all services for inetd mode) *
; **************************************************************************
[ssh]
; Принимать соединения на интерфейс:порт или просто порт. Например accept = 192.168.0.1:443
accept = 443
; Отдавать приложению на интерфейс:порт или просто порт. Например connect = 127.0.0.1:22
connect = 22
Ключи и сертификаты
Не большое отступление. В нашем случае stunnel проверяет только корректность пары сертификат/ключ и наличие сертификата в разрешенных или запрещенных. Самоподписанного сертификата более чем достаточно, и с технической стороны (stunnel) и со стороны поставленной задачи. Нет никакого смысла заморачиваться с собственным CA или с присутствием корневого сертификата в списке доверенных на клиенте или сервере.
Нам нужны пары сертификат/ключ для сервера и каждого клиента.
C помощью openssl создадим пару для сервера:
sudo openssl req -nodes -new -days 365 -newkey rsa:1024 -x509 -keyout serverkey.pem -out servercert.pem
Отвечаем на вопросы:
Generating a 1024 bit RSA private key
....................++++++
..............................++++++
writing new private key to 'serverkey.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:RU
State or Province Name (full name) [Some-State]:MyProvince
Locality Name (eg, city) []:MyCity
Organization Name (eg, company) [Internet Widgits Pty Ltd]:MyCompany
Organizational Unit Name (eg, section) []:IT dep
Common Name (e.g. server FQDN or YOUR name) []:server
Email Address []:
И переместим их по назначению:
sudo mv serverkey.pem /etc/stunnel/
sudo mv servercert.pem /etc/stunnel/
Как и где хранить клиентские сертификаты с ключами (за исключением каталогов certs и crls созданных ранее) решать вам. Я просто создам каталог clients в домашней директории своего пользователя и буду хранить их там на первых порах.
Создадим каталог и перейдем в него:
mkdir /home/myuser/clients
cd /home/myuser/clients
Создадим пару для клиента:
sudo openssl req -nodes -new -days 365 -newkey rsa:1024 -x509 -keyout clientkey.pem -out clientcert.pem
Как и при создании сертификата для сервера отвечаем на вопросы. Common Name будет другим например client.
Создадим еще одну пару:
sudo openssl req -nodes -new -days 365 -newkey rsa:1024 -x509 -keyout dnclientkey.pem -out dnclientcert.pem
Предположим, что clientcert.pem сертификат клиента которому доступ разрешен, а dnclientcert.pem сертификат клиента которому доступ запрещен. Скопируем сертификаты по нужным директориям.
sudo cp clientcert.pem /var/lib/stunnel4/certs
sudo cp dnclientcert.pem /var/lib/stunnel4/crls
Для каждого сертификата нужно создать хэш-ссылки (Возможно «хэш-ссылка» не корректное название, но оно очень точно передает суть). Это можно сделать с помощью утилиты c_rehash из пакета openssl. Мы же создадим небольшой скрипт для этих целей.
nano /home/myuser/certlink.sh
Со следующим содержимым:
#!/bin/sh
#
# usage: certlink.sh filename [filename ...]
for CERTFILE in "$@"; do
# Убедиться, что файл существует и это сертификат
test -f "$CERTFILE" || continue
HASH=$(openssl x509 -noout -hash -in "$CERTFILE")
test -n "$HASH" || continue
# использовать для ссылки наименьший итератор
for ITER in 0 1 2 3 4 5 6 7 8 9; do
test -f "${HASH}.${ITER}" && continue
ln -s "$CERTFILE" "${HASH}.${ITER}"
test -L "${HASH}.${ITER}" && break
done
done
Возможно будет более целесообразным разместить certlink.sh где нибудь в /usr/bin. Я пока не стал этого делать. Но выбор за вами.
Дадим права:
chmod +x /home/myuser/certlink.sh
Создаем ссылки:
cd /var/lib/stunnel4/certs
sudo /home/myuser/certlink.sh clientcert.pem
cd /var/lib/stunnel4/crls
sudo /home/myuser/certlink.sh dnclientcert.pem
В результате в каталогах у нас должны появится ссылки вида 7469493f.0.
Запустим stunnel:
sudo /etc/init.d/stunnel4 start
Stunnel на клиенте
На клиенте будем использовать версию stunnel аналогичную серверной. На сервере у нас 4.53. Забираем с одного из зеркал.
Если прямая ссылка перестанет работать, найти нужную версию можно так:
- Идем на stunnel.org в Downloads;
- В разделе Code Repositories выбираем зеркало и переходим. Например usenix.org.uk;
- Переходим в archive;
- Затем в 4.x;
- Забираем нужную версию.
Скачанный файл stunnel-4.53-installer.exe устанавливать не будем, просто распакуем содержимое в каталог stunnel4. В этот же каталог скопируем сертификат и ключ клиента, и сертификат сервера.
Редактируем файл stunnel.conf. У меня он имеет следующий вид:
debug = 7
; Пара сертификат/ключ клиента
cert = clientcert.pem
key = clientkey.pem
verify = 2
; Сертификат сервера
CAfile = servercert.pem
options = NO_SSLv2
[ssh]
client = yes
accept = 127.0.0.1:22
connect = 192.168.0.1:443
Здесь debug = 7 только на момент отладки, потом можно понизить до 3 или 4. Также есть опции для «тихого режима» и сокрытия значка в трее все есть в man'e.
Запускаем stunnel.exe, и пробуем с помощью putty подключится к 127.0.0.1. Тестируем. Можно попробовать подключится с запрещенным сертификатом.
Полезные материалы
- stunnel(8) manual. Без комментариев;
- Защита сетевых сервисов с помощью stunnel на opennet.ru. Большая, полезная статья. Автор подробно разбирает несколько сценариев применения stunnel. Must read;
- OpenSSL xgu.ru. Много полезной информации об openssl. Скрипт certlink.sh взят из этого источника.
Приведенные здесь инструкции полностью работоспособны. Проверено 26.12.2014 ubuntu 14.04.01, stunnel 4.53.
В данный момент работаю над парсингом логов stunnel с выводом отчетов и автоматизацией создания/управления сертификатами. Так как в последнее время мне интересен golang, реализовано будет с помощью него. Если материал на эту тему интересен — дайте знать.
Автор: mlsnoleg