OpenVPN: Let’s Encrypt DNS verification с certbot и AWS Route53 и обновление сертификата в OpenVPN Access Server

Автор: | 24/05/2019

В продолжение темы об установке и настройке OpenVPN Access Server, см. OpenVPN: настройка SSL и hostname.

Прошло три месяца, строк действия сертификата от Let’s Encrypt закончился, надо его обновить (см. Prometheus: Alertmanager и blackbox-exporter — проверка срока действия SSL и нотификация в Slack).

Можно было бы использовать привычную мне схему с webroot, но OpenVPN AS сам принимает подключения – NGINX тут нет, а устанавливать NGINX чисто ради Let’s Encrypt верификацию через webroot – так себе идея.

Сделаем по другому: используем DNS-авторизацию.

AWS IAM и certbot-пользователь

У нас домен обслуживается AWS Route53 – используем плагин certbot-dns-route53.

Получаем ID зоны:

Создаём IAM-policy, в ChangeResourceRecordSets указываем ID зоны:

{
    "Version": "2012-10-17",
    "Id": "certbot-dns-route53 sample policy",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "route53:ListHostedZones",
                "route53:GetChange"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect" : "Allow",
            "Action" : [
                "route53:ChangeResourceRecordSets"
            ],
            "Resource" : [
                "arn:aws:route53:::hostedzone/Z30***LB6"
            ]
        }
    ]
}

(уже позже подумал, что каждая политика создаётся на отдельную зону, потому в имени политики лучше добавлять имя домена, и если пользователей создавать отдельных – то тоже указывать имя домена, к которому есть доступ)

Создаём юзера c Programmatic access:

В Permissions выбираем Attach existing policies directly, и подключаем созданную политику:

Для проверки – устанавливаем aws-cli:

[simterm]

root@openvpnas2:~# apt -y install awscli

[/simterm]

Под пользователем openvpnas настраиваем default-профайл:

[simterm]

openvpnas@openvpnas2:~$ aws configure
AWS Access Key ID [None]: AKI***JEL
AWS Secret Access Key [None]: Lry***ide
Default region name [None]: 
Default output format [None]: json

[/simterm]

Проверяем конфиг:

[simterm]

root@openvpnas2:~# cat /home/openvpnas/.aws/config 
[default]
output = json

[/simterm]

Профиль есть, настроен. Далее его будет использовать certbot.

Для проверки прав доступа – пробуем получить зону:

[simterm]

openvpnas@openvpnas2:~$ aws route53 list-hosted-zones --output text
HOSTEDZONES     33C2D264-C922-FCDE-8654-3052BEA607A9    /hostedzone/Z30KLN6M3D0LB6      example.com. 103
...

[/simterm]

Окей.

certbot DNS verification

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

[simterm]

openvpnas@openvpnas2:~$ sudo apt -y install certbot

[/simterm]

И сам плагин:

[simterm]

openvpnas@openvpnas2:~$ sudo apt -y install python3-certbot-dns-route53

[/simterm]

Авторизируемся, и получаем сертификат:

[simterm]

root@openvpnas2:~# certbot certonly --dns-route53 -d vpn.example.com
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Found credentials in shared credentials file: ~/.aws/credentials
Plugins selected: Authenticator dns-route53, Installer None
Attempting to parse the version 0.31.0 renewal configuration file found at /etc/letsencrypt/renewal/vpn.example.com.conf with version 0.23.0 of Certbot. This might not work.
Cert is due for renewal, auto-renewing...
Renewing an existing certificate
Performing the following challenges:
dns-01 challenge for vpn.example.com
Waiting 10 seconds for DNS changes to propagate
Waiting for verification...
Cleaning up challenges

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/vpn.example.com/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/vpn.example.com/privkey.pem
 ...

[/simterm]

Проверяем зону в Route53 – certbot создал TXT-запись, которая используется ддля авторизации, и далее certbot будет обновлять её каждые три месяца:

Проверяем конфиг для обновлений:

[simterm]

root@openvpnas2:~# cat /etc/letsencrypt/renewal/vpn.example.com.conf 
# renew_before_expiry = 30 days
...
# Options used in the renewal process
[renewalparams]
authenticator = dns-route53
account = 6bc***4f6
installer = None

[/simterm]

Для обновления – достаточно вызвать certbot renew.

OpenVPN Access Server SSL update

Для обновления сертификата в OpenVPN AS потребуются:

  1. загрузить сертификат:
    sacli --key "cs.cert" --value_file "/etc/letsencrypt/live/vpn.example.com/cert.pem" ConfigPut
  2. загрузить сертификат Let’s Ecnrypt:
    sacli --key "cs.ca_bundle" --value_file "/etc/letsencrypt/live/vpn.example.com/chain.pem" ConfigPut
  3. и загрузить приватный ключ нашего сертификата:
    sacli --key "cs.priv_key" --value_file "/etc/letsencrypt/live/vpn.example.com/privkey.pem" ConfigPut
  4. перезагрузить OpenVPN сервер

Соберём все команды в скрипт, который потом будем вызывать из cron.

Переходим в каталог скриптов OpenVPN:

[simterm]

root@openvpnas2:~# cd  /usr/local/openvpn_as/scripts/

[/simterm]

Создаём скрипт ssl_renew.sh:

#!/usr/bin/env bash

SCRIPTS="/usr/local/openvpn_as/scripts/"

$SCRIPTS/sacli --key "cs.cert" --value_file "/etc/letsencrypt/live/vpn.example.com/cert.pem" ConfigPut
$SCRIPTS/sacli --key "cs.ca_bundle" --value_file "/etc/letsencrypt/live/vpn.example.com/chain.pem" ConfigPut
$SCRIPTS/sacli --key "cs.priv_key" --value_file "/etc/letsencrypt/live/vpn.example.com/privkey.pem" ConfigPut

$SCRIPTS/sacli start

Чисто на всякий случай – бекапим текущие ключи:

[simterm]

root@openvpnas2:/usr/local/openvpn_as/scripts# cp /usr/local/openvpn_as/etc/web-ssl/server.crt /usr/local/openvpn_as/etc/web-ssl/server.crt.OLD
root@openvpnas2:/usr/local/openvpn_as/scripts# cp /usr/local/openvpn_as/etc/web-ssl/server.key /usr/local/openvpn_as/etc/web-ssl/server.key.OLD

[/simterm]

Запускаем скрипт для проверки:

[simterm]

root@openvpnas2:/usr/local/openvpn_as/scripts# ./ssl_renew.sh 
[True, {}]
[True, {}]
[True, {}]
RunStart warm None
{
  "active_profile": "ProfileName", 
  "errors": {}, 
  "service_status": {
    ...
    "web": "restarted"
  }
}
WILL_RESTART ['web', 'client']

[/simterm]

Проверяем в браузере:

Далее, добавляем хук для certbot, что бы он вызывал скрипт после обновления сертификата.

Редактируем /etc/letsencrypt/renewal/vpn.example.com.conf:

...
[renewalparams]
authenticator = dns-route53
account = 6bc***4f6
installer = None
renew_hook = /usr/local/sbin/openvpnas_renewcerts.sh

И последним шагом – добавляем вызов certbot в cron – вызываем crontab -e:

0 0 * * * /usr/bin/certbot renew &> /var/log/letsencrypt/letsencrypt.log

Готово.