Развертывание CA сервера (EasyRSA)

CA (Certification Authority) = ЦС (Центр Сертификации) = Удостоверяющий центр
В криптографии это сторона, чья честность неоспорима, а public key широко известен. Это компонент, отвечающий за управление криптографическими ключами юзеров.
Ее задача - подтверждать подлинность ключей шифрования с помощью сертификатов электронной подписи. Открытые ключи и др. инфа о юзерах хранится центрами сертификации в виде цифровых сертификатов.
Lets Encrypt - тот же CA.

sudo apt install easy-rsa -y
 
mkdir "${HOME}/easy-rsa" \
  && ln -s /usr/share/easy-rsa/* "${HOME}/easy-rsa/" \
  && sudo chown -R "${USER}:${USER}" "${HOME}/easy-rsa" \
  && chmod 700 "${HOME}/easy-rsa"
 
cd "${HOME}/easy-rsa" \
  && ./easyrsa init-pki \
  && cp vars.example pki/vars

./easyrsa init-pki создал директорию инфраструктуры открытых ключей (PKI - Public Key Infrastructure).
Все готово для создания CA - значит, пора создавать пару “секретный ключ и сертификат”.

Конфигурация содержимого сертификата:

vars
set_var EASYRSA_REQ_COUNTRY "RUS"
set_var EASYRSA_REQ_PROVINCE "Moscow"
set_var EASYRSA_REQ_CITY "Moscow"
set_var EASYRSA_REQ_ORG "SomeCompany"
set_var EASYRSA_REQ_EMAIL "admin@SomeCompany.net"
set_var EASYRSA_REQ_OU "LLC"
set_var EASYRSA_ALGO "ec"
set_var EASYRSA_DIGEST "sha512"

Build the CA:

./easyrsa build-ca
# Нужно будет ввести passphrase, остальная инфа возьмется из pki/vars

Появится pki/ca.crt - открытый ключ CA. Он будет использоваться клиентами и серверами для проверки при авторизации. Его нужно будет доставить и на сервер OpenVPN, в нашем случае.
Теперь на CA сервере можно будет подписывать запросы сертификатов.

Подпись запроса серверных сертификатов

./easyrsa sign-req server server
# Подпись request-а на серверный сертификат сервера "server"

Пример

# Передача на CA сервер запроса, подпись там и возврат на VPN сервер
scp -P <port> pki/reqs/server.req test@test:/home/test/easy-rsa/pki/reqs/
ssh test@test -p <port> "cd ${HOME}/easy-rsa && ./easyrsa sign-req server server"
scp -P <port> test@test:"${HOME}/easy-rsa/pki/issued/server.crt" .

В чем смысл подписи?

Полученный файл server.crt содержит открытый ключ шифрования сервера OpenVPN, а также новую подпись от сервера ЦС.
Смысл подписи состоит в том, чтобы сообщить всем, кто доверяет серверу ЦС, что они также могут доверять серверу OpenVPN при подключении к нему.

Подпись запроса клиентских сертификатов

./easyrsa sign-req client SomeClient
# Подпись request-а на клиентский сертификат клиента "SomeClient"

Развертывание VPN сервера (OpenVPN)

У OpenVPN есть 3 вида аутентификации:

  1. Предустановленный ключ
  2. Аутентификация по сертификатам
    Для шифрования соединения и клиент, и сервер юзают сертификаты
  3. Аутентификация с помощью пары “логин и пароль”
    Может использоваться без создания сертификата для клиента, но серверный сертификат всё равно нужен

Буду использовать аутентификацию по сертификатам - способ, который наиболее гибок в настройках.

sudo apt install easy-rsa openvpn -y

Здесь EasyRSA нужен чисто для создания запросов.

mkdir "${HOME}/easy-rsa" \
  && ln -s /usr/share/easy-rsa/* "${HOME}/easy-rsa/" \
  && sudo chown "${USER}:${USER}" "${HOME}/easy-rsa" \
  && chmod 700 "${HOME}/easy-rsa"
cd "${HOME}/easy-rsa" && ./easyrsa init-pki

Генерация запроса на серверный сертификат

./easyrsa gen-req server nopass
# Passphrase

Этой командой создадутся файл запроса на серверный сертификат (server.req) и секретный ключ (server.key).

Что дальше делать с этим?

Нужно передать этот запрос (server.req) на сервер CA, подписать там и забрать сертификат (server.crt): Подпись запроса серверных сертификатов
P.S. Это еще и безопасно тем, что запрос и подписанный сертификат не являются секретными данными - можно спокойно осуществлять передачу.

TLS Crypt

Для доп. защиты нужно создать доп. секретный ключ для аутентификации и шифрования данных, передаваемых между клиентом и сервером OpenVPN (что и зовется TLS Crypt):

openvpn --genkey secret ta.key
sudo chown $USER:$USER ta.key

Теперь нужно положить указанные файлы в папку с конфигами OpenVPN (/etc/openvpn/server/):

  • серверный сертификат (server.crt)
  • секретный ключ сервера (server.key)
  • сертификат CA (ca.crt)
  • секретный ключ для TLS Crypt (ta.key)
sudo cp path/to/server.crt path/to/server.key path/to/ca.crt path/to/ta.key /etc/openvpn/server

Генерация клиентских сертификатов

cd ${HOME}/easy-rsa \
  && mkdir -p "${HOME}/clients/{keys,files}" \
  && chmod -R 700 "${HOME}/clients"
./easyrsa gen-req SomeClient nopass
cp pki/private/SomeClient.key ${HOME}/clients/keys

Подпись запроса клиентских сертификатов

После подписи запроса:

cp \
  path/to/ta.key \
  path/to/SomeClient.crt \
  path/to/SomeClient.key \
  path/to/ca.crt \
  "${HOME}/clients/keys"
sudo chown -R "${USER}:${USER}" "${HOME}/clients/keys"

Конфигурация OpenVPN и системы (для работы VPN)

Соус server.conf: /usr/share/doc/openvpn/examples/sample-config-files/server.conf

Содержимое моего конфига:

/etc/openvpn/server/server.conf
port 1194
proto udp
dev tun
ca ca.crt
cert server.crt
key server.key
dh none
server 10.8.0.0 255.255.255.0
keepalive 10 120
tls-crypt ta.key
cipher AES-256-GCM
auth SHA256
user nobody
group nogroup
persist-key
persist-tun
verb 3
explicit-exit-notify 1
ifconfig-pool-persist /var/log/openvpn/ipp.txt
status /var/log/openvpn/openvpn-status.log
log /var/log/openvpn/openvpn.log

Включение IPv4 forwarding (чтобы VPN работал):

echo "net.ipv4.ip_forward = 1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

Firewall (ufw):

sudo ufw allow 1194/udp
sudo ufw reload
openvpn-iptables.sh
#!/bin/bash -
ETH="$1"
PROTO="$2"
PORT="$3"
 
# OpenVPN
iptables \
    -A INPUT -i "$ETH" -m state --state NEW \
    -p "$PROTO" --dPORT "$PORT" -j ACCEPT
# Allow TUN interface connections to OpenVPN server
iptables -A INPUT -i tun+ -j ACCEPT
# Allow TUN interface connections to be forwarded through other interfaces
iptables -A FORWARD -i tun+ -j ACCEPT
iptables \
    -A FORWARD -i tun+ -o "$ETH" \
    -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables \
    -A FORWARD -i "$ETH" -o tun+ \
    -m state --state RELATED,ESTABLISHED -j ACCEPT
# NAT the VPN client traffic to the internet
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o "$ETH" -j MASQUERADE

Usage

sudo ./openvpn-iptables.sh <net_interface_name> udp 1194

Запуск OpenVPN

sudo systemctl -f enable openvpn-server@server.service
sudo systemctl restart openvpn-server@server.service
sudo systemctl status openvpn-server@server.service

Клиентские конфиг-файлы (.ovpn)

Соус client.conf: /usr/share/doc/openvpn/examples/sample-config-files/client.conf

Мой шаблон клиентского конфига:

client.conf
client
dev tun
proto udp
remote remote_server_ip 1194
resolv-retry infinite
nobind
user nobody
group nogroup
persist-key
persist-tun
remote-cert-tls server
cipher AES-256-GCM
auth SHA256
key-direction 1
verb 3
;tls-crypt ta.key 1

Надо будет поменять remote_server_ip на IP адрес VPN сервера:

VPN_SERVER_IP="$(dig +short myip.opendns.com @resolver1.opendns.com)" \
  sed -i "s/remote_server_ip/${VPN_SERVER_IP}/" client.conf

На digitalocean предоставили такой скрипт для создания клиентских конфигов (.ovpn файлов):

make_ovpn.sh
#!/bin/bash -
CLIENT_NAME="$1"
KEY_DIR="${HOME}/clients/keys"
OUTPUT_DIR="${HOME}/clients/files"
BASE_CONFIG="${HOME}/clients/client.conf"
 
cat "${BASE_CONFIG}" \
  <(echo -e '<ca>') "${KEY_DIR}/ca.crt" \
  <(echo -e '</ca>\n<cert>') "${KEY_DIR}/${CLIENT_NAME}.crt" \
  <(echo -e '</cert>\n<key>') "${KEY_DIR}/${CLIENT_NAME}.key" \
  <(echo -e '</key>\n<tls-crypt>') "${KEY_DIR}/ta.key" \
  <(echo -e '</tls-crypt>') \
    > "${OUTPUT_DIR}/${CLIENT_NAME}.ovpn"

Usage

./make_ovpn.sh SomeClient

Создастся конфиг ~/client-configs/files/SomeClient.ovpn, который содержит:

  • Сертификат CA сервера (ca.crt)
  • Клиентский сертификат (SomeClient.crt)
  • Клиентский секретный ключ (SomeClient.crt)
  • Секретный ключ для TLS Crypt (ta.key)

Всё, осталось его доставить на нужное устройство (которое хочет подключится к VPN) и импортировать этот .ovpn файл в клиентское приложение OpenVPN.

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

Соус: https://www.digitalocean.com/community/tutorials/how-to-set-up-and-configure-an-openvpn-server-on-ubuntu-20-04-ru#15

Troubleshoot

OpenVPN tls-crypt unwrap error

Описание ошибки

В “ при подключении клиента к нему можно увидеть такое сообщение:

tls-crypt unwrap error: packet authentication failed
TLS Error: tls-crypt unwrapping failed from [AF_INET]<ip-address>:1047

Логгирование включается в /etc/openvpn/server/server.conf:

log /var/log/openvpn/openvpn.log

Решение

Надо проверить, чтобы iptables и ufw не мешали трафику OpenVPN.

Надо проверить клиентский конфиг .ovpn, а именно:

  1. Чтобы была закомментирована строка:
    ;tls-crypt ta.key 1
    
  2. Чтобы OpenVPN static key был обернут не в <tls-auth></tls-auth>, а в <tls-crypt></tls-crypt>. Наглядно:
    <tls-crypt>
    #
    # 2048 bit OpenVPN static key
    #
    -----BEGIN OpenVPN Static key V1-----
    635e6ed65b6dddd5e9d44e8de84dd111
    15a131387427a5...
    -----END OpenVPN Static key V1-----
    </tls-crypt>
    

Нераздельная легкая установка OpenVPN + EasyRSA

wget https://git.io/vpn -O openvpn-install.sh && sudo bash ./openvpn-install.sh

Соусы: