Hatred's Log Place

DON'T PANIC!

Jan 10, 2020 - 4 minute read -

Let's Encrypt for GitLab Pages

Буквально сегодня состоялся разговор по поводу того, что на GitLab Pages нет возможности автоматически обновлять сертификаты Let's Encrypt (которые протухают каждые 90 дней) и что данная возможность есть на GitHub Pages.

Кроме того, сегодня как раз подошла череда обновления сертификата, заодно что-то меня потянуло поглядеть статью в документации GitLab по настройке интеграции с Let's Encrypt: Let's Encrypt for GitLab Pages

И что же я там вижу:

Let's Encrypt for GitLab Pages (manual process, deprecated)

Warning: This method is still valid but was deprecated in favor of the Let’s Encrypt integration introduced in GitLab 12.1.

Воу! С радостным предчувствием иду по указанной ссылке и таки да, они завезли автообновление сертификатов!

Но если интересно, как это было сделано вручную, добро пожаловать под кат.

Итак, старая ссылка описывает метод ручного получения сертификата, используя certbot и метод подтверждения через HTTP (.well-known/acme-challenge/ID). Но для этого, нужно каждый раз пересоздавать этот файл и публиковать сайт, ждать появления и только потом продолжать процедуру получения сертификата.

Я пошёл другим путём.

Подтверждать можно через DNS. Но есть загвоздка: certbot должен смочь модифицировать запись в DNS, а для этого должен быть API к сервисами DNS-провайдера (или написать свой, если используется собственный DNS). Подобный функционал может отличаться у различных провайдеров и логично его поместить в какое-то подобие плагинов. К счастью, задел на расширение уже реализован в certbot и даже есть пачка Authenticator плагинов для certbot. Часть из них даже есть в репозиториях Manjaro:

community/certbot-dns-sakuracloud 1.0.0-1 (7.9 KiB 16.0 KiB) 
    Sakura Cloud DNS Authenticator plugin for Certbot
community/certbot-dns-route53 1.0.0-1 (10.5 KiB 23.5 KiB) 
    Route53 DNS Authenticator plugin for Certbot
community/certbot-dns-rfc2136 1.0.0-1 (10.7 KiB 28.6 KiB) (Installed)
    NS1 DNS Authenticator plugin for Certbot
community/certbot-dns-ovh 1.0.0-1 (8.4 KiB 17.4 KiB) 
    OVH DNS Authenticator plugin for Certbot
community/certbot-dns-nsone 1.0.0-1 (8.0 KiB 15.1 KiB) 
    NS1 DNS Authenticator plugin for Certbot
community/certbot-dns-luadns 1.0.0-1 (8.0 KiB 15.4 KiB) 
    LuaDNS DNS Authenticator plugin for Certbot
community/certbot-dns-linode 1.0.0-1 (8.4 KiB 17.6 KiB) 
    Linode DNS Authenticator plugin for Certbot
community/certbot-dns-google 1.0.0-1 (11.9 KiB 32.7 KiB) 
    Google Cloud DNS Authenticator plugin for Certbot
community/certbot-dns-gehirn 1.0.0-1 (7.9 KiB 16.1 KiB) 
    Gehirn DNS Authenticator plugin for Certbot
community/certbot-dns-dnsmadeeasy 1.0.0-1 (8.1 KiB 16.4 KiB) 
    DNS Made Easy DNS Authenticator plugin for Certbot
community/certbot-dns-dnsimple 1.0.0-1 (7.9 KiB 15.2 KiB) 
    DNSimple DNS Authenticator plugin for Certbot
community/certbot-dns-digitalocean 1.0.0-1 (9.4 KiB 22.8 KiB) 
    DigitalOcean DNS Authenticator plugin for Certbot
community/certbot-dns-cloudxns 1.0.0-1 (8.0 KiB 15.8 KiB) 
    CloudXNS DNS Authenticator plugin for Certbot
community/certbot-dns-cloudflare 1.0.0-1 (9.9 KiB 25.1 KiB) 
    Cloudflare DNS Authenticator plugin for Certbot

Беда в том, что у меня используется DNS от Hurricane Electric (или просто he.net). Но беглый поиск дал наличие плагина в AUR:

aur/certbot-dns-henet-git r16.931e2c7-1 (+0 0.00%) (Installed: r17.e2cd097-1)
    he.net DNS Authenticator plugin for Certbot

Установка самого плагина не сложная. Настройка, когда уже всё знаешь, тоже.

Для начала создадим скрипты помощники, что бы не запоминать все команды.

Итак, выбираем директорию, пусть это будет ~/home/blog/certbot и переходим в неё (предварительно создав!).

Начнём со скрипта cert-get-dns-henet.sh для первоначального запроса сертификата:

#!/usr/bin/env bash

mail="your_email@somedomain.com"
site="domain.su"

certbot certonly -d $site --email $mail \
    --authenticator certbot-dns-henet:dns-henet \
    --certbot-dns-henet:dns-henet-credentials dns-credentials/henet \
    --work-dir work-dir \
    --logs-dir logs-dir \
    --config-dir config-dir

Скрипт обращается только к файлам в текущей директории, поэтому нет необходимости запускать с правами супер-пользователя.

Существенными особенностями этого скрипта являются два параметра:

  1. --authenticator certbot-dns-henet:dns-henet который выбирает нужный нам плагин-authenticator
  2. и --certbot-dns-henet:dns-henet-credentials dns-credentials/henet который задаёт файл с креденшиналами для доступа к админке he.net. Попросту: логин и пароль, так как сам плагин сделан, ЕМНИП, через парсинг сайта и запросов через форму.

Создаём файл для хранения креденшиналов:

mkdir dns-credentials
touch dns-credentials/henet
chmod 600 dns-credentials/henet

Содержимое dns-credentials/henet такое:

certbot_dns_henet:dns_henet_username=HE_NET_LOGIN
certbot_dns_henet:dns_henet_password=HE_NET_PASSWORD

Всё, после этого достаточно запустить скрипт, что бы получить сертификаты. Его запускать нужно только единожды.

Второй скрипт носит имя cert-renew-all.sh и служит для обновления сертификатов:

#!/usr/bin/env bash

certbot renew \
    --work-dir work-dir \
    --logs-dir logs-dir \
    --config-dir config-dir

Его содержимое будет идентичным для всех форм подтверждения прав на домен.

Ну и последний скрипт использует возможности GitLab API в части управления пользовательскими страницами, что бы в одно движение обновить сертификат на странице.

Скрипт назвал gitlab-pages-update.sh:

#!/usr/bin/env bash

set -e

domain=domain.su
# url-encoded, replace '/' with '%2F':
# GITLAB_USER/GITLAB_USER.gitlab.io -> GITLAB_USER%2FGITLAB_USER.gitlab.io
project=GITLAB_USER%2FGITLAB_USER.gitlab.io
cert=config-dir/live/$domain/fullchain.pem
key=config-dir/live/$domain/privkey.pem
token=$(cat gitlab-credentials/token)

curl --request PUT --header "PRIVATE-TOKEN: $token" --form "certificate=@$cert" --form "key=@$key" \
    https://gitlab.com/api/v4/projects/$project/pages/domains/$domain | sed 's|\\n|\n|g'
echo

Обращение к API через токен, который хранится в файле gitlab-credentials/token. Получить его можно:

  1. Идём на <gitlab.com> и логинимся
  2. Щёлкаем мышью по иконке с вашим аватаром в правом верхнем углу и в выпадающем списке выбираем Settings
  3. В User settings меню выбираем пункт Access Tokens
  4. Вводим параметры токена и обязательно указываем область (Scope) api
  5. Кликаем по кнопке Create personal access token
  6. И сохраняем токен в файл выше.

Посмотреть токен повторно вы не можете. Только отозвать его.

На этом вспомогательные скрипты закончены. Процедура обновления будет заключаться в последовательном вызове двух скриптов:

./cert-renew-all.sh
./gitlab-pages-update.sh

При желании можно поместить данные вызовы в задание Cron. Что не нравится, так это необходимость хранить пароль открытым текстом для he.net.