Сервер в кармане, или просто о сложном!

главная - Статьи - Удаленный доступ (VPN)

Установка OpenVPN в CentOS 7

Теги: Linux OpenVPN

На этом сайте уже неоднократно публиковались статьи по настройке OpenVPN, но время летит, инструменты немного изменяются, узнаются новые опции, поэтому решил обновить кладовую пошаговых how-to. Большинство из того, что здесь описано, касается не только CentOS, но и других дистрибутивов Linux, но у меня традиционно все для CentOS. С примерами рабочих конфигов сервера и клиента, разумеется.

Актуальность статьи: май 2016. ПО: CentOS 7 minimal, OpenVPN 2.3.10, SELinux включен. Все ПО обновлено с помощью yum update.

Оглавление:

Установка
Инфраструктура публичных ключей PKI
Сертификаты сервера OpenVPN
Клиентские ключи
Конфигурационный файл сервера
Конфигурационный файл клиента
Запускаем сервер
Отзыв сертификата
Справка по Easy-RSA
Настройка iptables

Установка

Устанавливаем openvpn:

# yum install epel-release
# yum install openvpn

Вспомогательные утилиты:

# yum install wget
# yum install unzip zip

Инфраструктура публичных ключей PKI

Директория для ключей:

# mkdir /etc/openvpn/keys
# cd /etc/openvpn/keys

Вообще, все операции с ключами OpenVPN можно совершать с помощью OpenSSL. Но есть утилита Easy-RSA, которая раньше шла в составе с OpenVPN, а теперь это отдельный проект https://github.com/OpenVPN/easy-rsa. Вот эту утилиту мы и скопируем себе на сервер:

# wget https://github.com/OpenVPN/easy-rsa/archive/master.zip
# unzip master.zip
# cd /etc/openvpn/keys/easy-rsa-master/easyrsa3
# cp vars.example vars

По желанию, правим содержимое файла vars (длину ключей, дефолтные сроки валидности ключей и др.), например:

set_var EASYRSA_KEY_SIZE        4096

set_var EASYRSA_REQ_COUNTRY     "RU"
set_var EASYRSA_REQ_PROVINCE    "NW"
set_var EASYRSA_REQ_CITY        "City"
set_var EASYRSA_REQ_ORG         "Org"
set_var EASYRSA_REQ_EMAIL       "contact@localhost.local"
set_var EASYRSA_REQ_OU          "OU"

set_var EASYRSA_DIGEST          "sha512"

Сложного ничего там нет, посмотрите сами.

Создаем инфраструктуру публичных ключей (PKI, Public Key Infrastructure):

# ./easyrsa init-pki

При этом будет создан каталог /etc/openvpn/keys/easy-rsa-master/easyrsa3/pki/.

Чтобы при подключении клиентов к серверу OpenVPN можно было бы быть уверенным, что сертификат сервера и клиента - не поддельные, нужен кто-то, кто отвечает за "кристальную чистоту партийных рядов". Этот кто-то - удостоверяющий центр, CA (Certificate Authority). CA бывают свои (чаще самоподписанные) и публичные, типа Thawte, StartSSL и др. В данном примере рассмотрим ситуацию, когда используется свой CA - как минимум, это значительно дешевле. Даже свой CA не обязан быть на том же сервере, где будет запущен сервер OpenVPN, но чаще всего расположение CA для OpenVPN на том же сервере, что и сам OpenVPN.

Создаем свой CA:

# ./easyrsa build-ca

Можно было бы избежать ввода пароля (./easyrsa build-ca nopass), но при этом если кто-то скопирует секретный ключ вашего CA, он сможет подписывать "левые" ключи. Вы должны охранять приватный ключ CA как зеницу ока, ведь все остальное верифицируется именно им. Поэтому пароль должен быть стойким к перебору. В конце концов, вы не каждый день будете им пользоваться.

Итак, у нас появились секретный ключ ca.key и сертификат ca.crt:
    /etc/openvpn/keys/easy-rsa-master/easyrsa3/pki/private/ca.key
    /etc/openvpn/keys/easy-rsa-master/easyrsa3/pki/ca.crt

Секретный ключ нужно оставить на сервере и никому не отдавать. Каждый раз при выпуске нового сертификата сервера или пользователя нам будет необходим пароль секретного ключа! Он важнее сертификата сервера, пользователя, да всего вообще.

Сертификат CA (ca.crt) — открытый, его мы будем вместе с пользовательскими сертификатами передавать клиентам.

Сертификаты сервера OpenVPN

Создаем запрос сертификата для сервера без пароля с помощью опции nopass, иначе придется вводить пароль с консоли при каждом запуске сервера:

# ./easyrsa gen-req server nopass
Keypair and certificate request completed. Your files are:
req: /etc/openvpn/keys/easy-rsa-master/easyrsa3/pki/reqs/server.req
key: /etc/openvpn/keys/easy-rsa-master/easyrsa3/pki/private/server.key

Подписываем запрос на получение сертификата у нашего CA:

# ./easyrsa sign-req server server

В процессе работы скрипта вводим пароль от CA, который указывали раньше и отвечаем на вопрос yes. Мы получили подписанный нашим удостоверяющим центром сертификат для сервера — /etc/openvpn/keys/easy-rsa-master/easyrsa3/pki/issued/server.crt

Создаем ключ Диффи-Хелмана:

# ./easyrsa gen-dh

В применении к OpenVPN файл Диффи-Хелмана нужен для обеспечения защиты трафика от расшифровки, если ключи были похищены. Имеется в виду тот трафик, который был записан и сохранен еще до похищения ключей [https://habrahabr.ru/post/233971/]. Тема широкая, захламлять статью лирическими отступлениями не решился.

Генерация занимает приличное время (по отношению к другим ключам). В конце концов получаем ключ /etc/openvpn/keys/easy-rsa-master/easyrsa3/pki/dh.pem

Чтобы можно было отозвать клиентский сертификат (например, при утере мобильного устройства или при увольнении сотрудника), надо создать список отозванных сертификатов CRL:

# ./easyrsa gen-crl

Будет создан файл /etc/openvpn/keys/easy-rsa-master/easyrsa3/pki/crl.pem, который будет содержать список отозванных сертификатов. Этот файл необходимо скопировать в директорию /etc/openvpn/, указать в конфиге сервера OpenVPN и перезапустить сервер OpenVPN.

Копируем в папку /etc/openvpn все необходимые для работы openvpn сервера ключи (напомню, мы находимся в директории /etc/openvpn/keys/easy-rsa-master/easyrsa3):

# cp pki/ca.crt /etc/openvpn/
# cp pki/dh.pem /etc/openvpn/
# cp pki/crl.pem /etc/openvpn/
# cp pki/issued/server.crt /etc/openvpn/
# cp pki/private/server.key /etc/openvpn/

Создадим файл HMAC, для дополнительной верификации клиента и сервера (для защиты от DDoS, например):

# cd /etc/openvpn
# openvpn --genkey --secret ta.key

Файл ta.key должен быть скопирован и передан клиенту.

В нормальной конфигурации сервера после старта (от root) права меняются на непривилегированного пользователя (nobody или созданного специально). Этот пользователь должен иметь права на чтение к сертификатам для аутентификации клиентов:

# chmod 644 /etc/openvpn/ca.crt
# chmod 644 /etc/openvpn/crl.pem
# chmod 644 /etc/openvpn/dh.pem
# chmod 644 /etc/openvpn/server.crt

Ключи server.key, ta.key должны быть доступны только root (chmod 600).

Клиентские ключи

Создадим ключ для клиента openvpn:

# cd /etc/openvpn/keys/easy-rsa-master/easyrsa3
# ./easyrsa gen-req client1 nopass
# ./easyrsa sign-req client client1

Опять можно отметить, что могут быть ситуации, когда лучше ключ клиента защищать паролем, хотя бы несложным. Тогда всякий раз при подключении к VPN необходимо будет ввести пароль. Это может быть удобным, если вы не хотите, например, чтобы ваш ребенок случайно подключился к вашей рабочей сети и натворил делов. Для этого просто не надо указывать "nopass" в конце команды выше.

В итоге мы получим два файла:
Публичный сертификат клиента: /etc/openvpn/keys/easy-rsa-master/easyrsa3/pki/issued/client1.crt
Приватный ключ клиента: /etc/openvpn/keys/easy-rsa-master/easyrsa3/pki/private/client1.key

Клиенту вместе с конфигом (см ниже) нужно будет передать копии следующих файлов:
client1.crt;
client1.key;
ca.crt;
ta.key;
которые все используются в клиентском конфиге. Никакие иные файлы, кроме тех, которые указаны в конфиге клиента, передавать клиенту не надо!

Конфигурационный файл сервера

Конфигурационный файл сервера по-умолчанию: /etc/openvpn/server.conf. Скорее всего, у вас не будет необходимости менять его расположение.

Обратите внимание на общие опции для клиента и сервера. Это тип шифрования, сжатие трафика и др. Некоторые опции зеркальные. Например, на сервере ta.key 0, на клиенте ta.key 1 и др.

Пример 1 (конфиг сервера OpenVPN):

port 3876
proto udp
dev tun

ca ca.crt
cert server.crt
key server.key
dh dh.pem

# Проверка, не отозван ли сертификат клиента
crl-verify crl.pem

server 10.8.12.0 255.255.255.0
ifconfig-pool-persist ipp.txt

# Пусть весь трафик клиента идет через VPN
push "redirect-gateway def1"

# DNS хостинга сервера (или иные, по вашему усмотрению):
push "dhcp-option DNS 8.8.8.8"

keepalive 10 120

tls-server
tls-auth ta.key 0
tls-timeout 120
auth MD5

cipher BF-CBC

comp-lzo

max-clients 10

user nobody
group nobody

persist-key
persist-tun

status openvpn-status.log

log /var/log/openvpn.log

# 0 is silent, except for fatal errors
# 4 is reasonable for general usage
# 5 and 6 can help to debug connection problems
# 9 is extremely verbose
verb 4

Пример 2 (конфиг сервера OpenVPN):

port 3725
proto udp
dev tun
ca ca.crt
cert server.crt
key server.key
dh dh.pem
crl-verify crl.pem
server 10.8.0.0 255.255.255.0
ifconfig-pool-persist ipp.txt
push "redirect-gateway def1"
push "dhcp-option DNS 8.8.8.8"
remote-cert-eku "TLS Web Client Authentication"
keepalive 10 120
tls-server
tls-auth ta.key 0
tls-timeout 120
auth SHA512
cipher AES-256-CBC
comp-lzo
max-clients 10
user nobody
group nobody
persist-key
persist-tun
status openvpn-status.log
#log-append  openvpn.log
#log /dev/null
#log /var/log/openvpn.log
log openvpn.log
verb 6

Оба конфига рабочие.

Конфигурационный файл клиента

Некоторые опции должны быть симметричны опциям сервера, в частности тип шифрования (здесь BF-CBC), сжатия трафика и др. Все приведенные ниже конфиги рабочие.

Приведены примеры конфигов клиентов OpenVPN для Windows. Для Linux все то же, только пути до файлов ключей надо указать как в конфиге сервера (см. выше).

Пример 1 (конфиг клиента OpenVPN):

client
dev tun
proto udp
remote 1.2.3.4 3876
resolv-retry infinite
nobind
persist-key
persist-tun
mute-replay-warnings
ns-cert-type server
tls-auth "C:Program FilesOpenVPNconfigta.key" 1
auth MD5
ca "C:\\Program Files\\OpenVPN\\config\\ca.crt"
cert "C:\\Program Files\\OpenVPNconfig\\client1.crt"
key "C:\\Program Files\\OpenVPN\\config\\client1.key"
cipher BF-CBC
comp-lzo
verb 3

Пример 2 (соотв. примеру 2-го конфига сервера):

client
dev tun
proto udp
remote 1.2.3.4 3876
resolv-retry infinite
nobind
block-outside-dns
persist-key
persist-tun
mute-replay-warnings
remote-cert-eku "TLS Web Server Authentication"

remote-cert-tls server
tls-client
tls-auth "C:\\Program Files\\OpenVPN\\config\\ta.key" 1
auth SHA512
ca "C:\\Program Files\\OpenVPN\\config\\ca.crt"
cert "C:\\Program Files\\OpenVPN\\config\\client1.crt"
key "C:\\Program Files\\OpenVPN\\config\\client1.key"
cipher AES-256-CBC
comp-lzo
verb 3

Запускаем сервер

# systemctl start openvpn@server

Проверяем, запустился или нет (считаем, что в конфиге указан порт 3876/udp):

# netstat -tulnp | grep 3876
udp 0 0 0.0.0.0:3876 0.0.0.0:* 10431/openvpn

Отлично, запустился на указанном порту.

Ну, или так проверяем:

# systemctl status -l openvpn@server

Если все ок, разрешаем автозапуск:

# systemctl enable openvpn@server

Если что-то не так, смотрим лог. Возможно, SELinux не разрешает запускать OpenVPN на выбранном вами порте.

# semanage port -a -t openvpn_port_t -p udp 3876

и еще раз пробуем запустить OpenVPN.

В любом случае, файл лога вам в помощь. После отладки лог можно и отключить (log /dev/null). VPN - он такой...

Отзыв сертификата

Для того, чтобы отозвать сертификат client1:

# cd /etc/openvpn/keys/easy-rsa-master/easyrsa3/pki/
# ./vars
# ./easyrsa revoke client1

При этом будет создан новый файл crl.pem, который обязательно надо скопировать в директорию /etc/openvpn, заменив старый и перезапустить сервер OpenVPN.

Т.к. инфраструктура ключей OpenVPN это по сути обычный CA OpenSSL, то многое из того, что вы знаете про OpenSSL, подойдет и для OpenVPN. Например, список сертификатов с серийными номерами, указанием, отозваны ли они и другой информацией находится в файле index.txt.

При попытке подключиться к серверу с отозванным сертификатом в логе сервера могут быть такие события (уровень детализации verb 4):

TLS: Initial packet from [AF_INET]1.2.3.4:65454, sid=3e2e1135 a0086339
CRL CHECK OK: C=RU, ST=NW, L=City, O=Org, OU=OU, CN=Org CA, name=EasyRSA, emailAddress=admin@localhost.local
VERIFY OK: depth=1, C=RU, ST=NW, L=City, O=Org, OU=OU, CN=Org CA, name=EasyRSA, emailAddress=admin@localhost.local

CRL CHECK FAILED: C=RU, ST=NW, L=City, O=Org, OU=OU, CN=client1, name=EasyRSA, emailAddress=client1@localhost.local (serial 04) is REVOKED

TLS_ERROR: BIO read tls_read_plaintext error: error:140890B2:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:no certificate returned
TLS Error: TLS object -> incoming plaintext read error
TLS Error: TLS handshake failed

Обратите внимание на строчку "CRL CHECK FAILED" (Ошибка Проверки Списка Отозванных Сертификатов): сертификат с серийным номером 04 отозван (is REVOKED)!

Справка по Easy-RSA

Если вы хотите получить справку по утилите Easy-RSA, выполните команду:

# ./easyrsa

Для получения справки по конкретным командам, например build-ca:

# ./easyrsa help build-ca

Настройка iptables

Немного про настройку iptables. Чуть-чуть. По-умолчанию, таблицы INPUT, FORWARD (а порой и OUTPUT) должны быть в состоянии DROP. Поэтому необходимо разрешить прохождение пакетов из сети OpenVPN в интернет (eth0) и/или в локальную сеть (eth1). Пожалуйста, обратите внимание, это пример того, что вам может быть необходимо сделать. Все нижеприведенные команды уже не пошаговый how-to, как в разделах выше. Вы можете нарушить нормальную работу сети необдуманными действиями!

Разрешить доступ к серверу OpenVPN с внешнего интерфейса:

# iptables -A INPUT -i eth0 -p udp --dport 3876 -j ACCEPT

После этого клиенты OpenVPN смогут подключиться к серверу, но могут не иметь возможности выйти за его пределы, в зависимости от текущих настроек firewall.

Чтобы клиенты могли выходить в интернет или пользоваться ресурсами LAN, для начала на сервере OpenVPN разрешим маршрутизацию (действует до перезагрузки):

# echo 1 > /proc/sys/net/ipv4/ip_forward

или так (сохранится после перезагрузки):

# nano /etc/sysctl.conf

Добавить строку:

net.ipv4.ip_forward = 1

Перезагрузим сервис:

# systemctl restart network.service

Чтобы клиенты OpenVPN могли выходить в интернет от лица сервера (внешний интерфейс eth0):

# iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE

Возможно, у вас уже есть правило для NAT, что-то вроде:

# iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

В таком случае нет необходимости в создании отдельного правила для маскарада из сети OpenVPN.

Чтобы клиенты OpenVPN могли работать с локальной сетью (интерфейс LAN eth1):

iptables -A FORWARD -i tun0 -o eth1 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -i eth1 -o tun0 -m state --state ESTABLISHED,RELATED -j ACCEPT

Пример рабочего скрипта для сервера OpenVPN (без подключения к локальной сети):

#!/bin/sh

IF_EXT="eth0"
IF_OVPN="tun0"

OVPN_PORT="3876"

IPT="/sbin/iptables"
IPT6="/sbin/ip6tables"

# flush
$IPT --flush
$IPT -t nat --flush
$IPT -t mangle --flush
$IPT -X

$IPT6 --flush

# loopback
$IPT -A INPUT -i lo -j ACCEPT
$IPT -A OUTPUT -o lo -j ACCEPT

# default
$IPT -P INPUT DROP
$IPT -P OUTPUT DROP
$IPT -P FORWARD DROP

$IPT6 -P INPUT DROP
$IPT6 -P OUTPUT DROP
$IPT6 -P FORWARD DROP

# allow forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward

# NAT
# #########################################
# SNAT - local users to out internet
$IPT -t nat -A POSTROUTING -o $IF_EXT -j MASQUERADE

# INPUT chain
# #########################################
$IPT -A INPUT -p tcp ! --syn -m state --state NEW -j DROP
$IPT -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# ssh
$IPT -A INPUT -i $IF_EXT -p tcp --dport 2685 -j ACCEPT
# удобно для тестов связи icmp (vpn)
$IPT -A INPUT -i $IF_OVPN -p icmp -s 10.8.0.0/24 -j ACCEPT
# если openvpn - еще и dns (vpn)
$IPT -A INPUT -i $IF_OVPN -p udp --dport 53 -s 10.8.0.0/24 -j ACCEPT
# openvpn
$IPT -A INPUT -i $IF_EXT -p udp --dport $OVPN_PORT -j ACCEPT


# FORWARD chain
# #########################################
$IPT -A FORWARD -i $IF_OVPN -o $IF_EXT -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
$IPT -A FORWARD -i $IF_EXT -o $IF_OVPN -m state --state ESTABLISHED,RELATED -j ACCEPT


# OUTPUT chain
# #########################################

$IPT -A OUTPUT -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT

Дополняйте, улучшайте, делитесь с другими опытом :) Вот, вроде бы и все. Удачи!

Авторизуйтесь для добавления комментариев!


    забыли пароль?    новый пользователь?