Получение wildcard-сертификатов от удостоверяющего центра Let's Encrypt возможно только при подтверждение владения доменом, путём создания временной TXT записи вида _acme-challenge.oldfag.ru с определённым значением.
Самое простое решение для автоматизации получения сертификатов от Let’s Encrypt - использование Cetrbot или acme.sh.
Мой выбор пал на Certbot. Он имеет уже готовые плагины для работы с некоторыми DNS-провайдерами. К несчастью, он не имеет плагина для работы с DNS Яндекс.Коннект, но возможность использовать свои скрипты исправляет эту ситуацию.
Acme.sh умеет работать с DNS Яндекс.Коннект, дак зачем же использовать велосипед в виде Certbot и самописных скриптов?
Ответ прост. Проверка существования TXT записи производится запросом к NS серверам домена, в нашем случае dns1.yandex.net и dns2.yandex.net. Вот тут может возникнуть ошибка валидации домена, т.к. на одном из серверов запись уже существует, а на втором ещё нет. Тут нам на помощь и приходит Certbot с самописными скриптами.
Для использования собственных скриптов создания DNS-записей у certbot есть 2 ключа:
Все предварительные этапы завершены, приступим к созданию скриптов для работы с dns-записями. Первым создадим скрипт создания необходимых записей
Теперь создадим скрипт для удаления временных записей
Последний файл, который осталось создать - хранилище API-токенов
После того, как сертификат будет успешно выпущен, в каталоге /etc/letsencrypt/renewal будет создан файл с параметрами перевыпуска сертификата. Отслеживая срок действия сертификата в /etc/letsencrypt/live/имя домена/cert.pem можно автоматизировать перевыпуск сертификатов при помощи команды
Для автоматического перевыпуска сертификата, без участия пользователя, нужно в файле /etc/letsencrypt/renewal/домен.conf раскомментировать строку, указывающую оставшийся срок действия сертификата, при достижении которого будет предпринята поптка его обновления
Самое простое решение для автоматизации получения сертификатов от Let’s Encrypt - использование Cetrbot или acme.sh.
Мой выбор пал на Certbot. Он имеет уже готовые плагины для работы с некоторыми DNS-провайдерами. К несчастью, он не имеет плагина для работы с DNS Яндекс.Коннект, но возможность использовать свои скрипты исправляет эту ситуацию.
Acme.sh умеет работать с DNS Яндекс.Коннект, дак зачем же использовать велосипед в виде Certbot и самописных скриптов?
Ответ прост. Проверка существования TXT записи производится запросом к NS серверам домена, в нашем случае dns1.yandex.net и dns2.yandex.net. Вот тут может возникнуть ошибка валидации домена, т.к. на одном из серверов запись уже существует, а на втором ещё нет. Тут нам на помощь и приходит Certbot с самописными скриптами.
- --manual-auth-hook путь к скрипту - для создания TXT записи для авторизации;
- --manual-cleanup-hook путь к скрипту - для удаления TXT записи после завершения проверки.
Все предварительные этапы завершены, приступим к созданию скриптов для работы с dns-записями. Первым создадим скрипт создания необходимых записей
mkdir -p /scripts/certbot-dns-pddyandex touch /scripts/certbot-dns-pddyandex/yandex-auth-hook.shс таким содержанием
#!/bin/bash
_dir="$(dirname "$0")"
source "$_dir/config.sh"
# Get API key for current domain
API_KEY=${API_KEYMAP["$CERTBOT_DOMAIN"]}
if [ -z "$API_KEY" ]; then
echo "No API key found for domain $CERTBOT_DOMAIN, exit"
exit
fi
# Create TXT record
CREATE_DOMAIN="_acme-challenge"
RECORD_ID=$(curl -s -X POST "https://pddimp.yandex.ru/api2/admin/dns/add" \
-H "PddToken: $API_KEY" \
-d "domain=$CERTBOT_DOMAIN&type=TXT&content=$CERTBOT_VALIDATION&ttl=3600&subdomain=$CREATE_DOMAIN" \
| python -c "import sys,json;print(json.load(sys.stdin)['record']['record_id'])")
# Save info for cleanup
if [ ! -d /tmp/CERTBOT_$CERTBOT_DOMAIN ];then
mkdir -m 0700 /tmp/CERTBOT_$CERTBOT_DOMAIN
echo $RECORD_ID > /tmp/CERTBOT_$CERTBOT_DOMAIN/RECORD_ID
else
echo $RECORD_ID >> /tmp/CERTBOT_$CERTBOT_DOMAIN/RECORD_ID
fi
# Sleep to make sure the change has time to propagate over to DNS (max: 20 min)
c_time=0
end_time=1200
while [ "$c_time" -le "$end_time" ]; do
if [ `dig $CREATE_DOMAIN.$CERTBOT_DOMAIN TXT +short @dns1.yandex.net | grep $CERTBOT_VALIDATION` ]; then
sleep 5
if [ `dig $CREATE_DOMAIN.$CERTBOT_DOMAIN TXT +short @dns2.yandex.net | grep $CERTBOT_VALIDATION` ]; then
sleep 5
if [ `dig $CREATE_DOMAIN.$CERTBOT_DOMAIN TXT +short @8.8.8.8 | grep $CERTBOT_VALIDATION` ]; then
sleep 5
break
else
sleep 50
c_time=$[c_time+50]
fi
else
sleep 55
c_time=$[c_time+55]
fi
else
sleep 60
c_time=$[c_time+60]
fi
done
Он берёт из файла API-токен для конкретного домена и при его помощи создаёт необходимые для проверки TXT записи. Идентификаторы записей для их последующего удаления сохраняются в файле RECORD_ID.Теперь создадим скрипт для удаления временных записей
touch /scripts/certbot-dns-pddyandex/yandex-cleanup-hook.shс таким содержанием
#!/bin/bash
_dir="$(dirname "$0")"
source "$_dir/config.sh"
# Get API key for current domain
API_KEY=${API_KEYMAP["$CERTBOT_DOMAIN"]}
if [ -z "$API_KEY" ]; then
echo "No API key found for domain $CERTBOT_DOMAIN, exit"
exit
fi
# Remove the challenge TXT record from the zone
remove_record() {
RECORD_ID="$1"
if [ -n "${RECORD_ID}" ]; then
RESULT=$(curl -s -X POST "https://pddimp.yandex.ru/api2/admin/dns/del" \
-H "PddToken: $API_KEY" \
-d "domain=$CERTBOT_DOMAIN&record_id=$RECORD_ID" \
| python -c "import sys,json;print(json.load(sys.stdin)['success'])")
echo $RESULT
fi
}
if [ -f /tmp/CERTBOT_$CERTBOT_DOMAIN/RECORD_ID ]; then
while read RECORD; do
remove_record $RECORD
done < /tmp/CERTBOT_$CERTBOT_DOMAIN/RECORD_ID
rm -f /tmp/CERTBOT_$CERTBOT_DOMAIN/RECORD_ID
fi
Он так же, как и скрипт для создания записей, берёт API-токен для конкретного домена и удаляет записи, идентификаторы которых записаны в файле RECORD_ID.Последний файл, который осталось создать - хранилище API-токенов
touch /scripts/certbot-dns-pddyandex/config.shс таким содержанием
declare -A API_KEYMAP
API_KEYMAP["domain1.tld"]='52 symbols of key ....'
API_KEYMAP["domain2.tld"]='52 symbols of key....'
Все файлы созданы, теперь сделаем файлы скриптов исполняемыми
chmod +x yandex-auth-hook.sh yandex-cleanup-hook.shи попробуем получить wildcard-сертификат, для того, чтобы сертификаты не выпускались на самом деле добавим к команде ключ --dry-run
certbot certonly --manual-public-ip-logging-ok --agree-tos --renew-by-default \
-d oldfag.ru -d *.oldfag.ru --manual \
--manual-auth-hook /scripts/certbot-dns-pddyandex/yandex-auth-hook.sh \
--manual-cleanup-hook /scripts/certbot-dns-pddyandex/yandex-cleanup-hook.sh \
--preferred-challenges dns-01 --server https://acme-v02.api.letsencrypt.org/directory \
--register-unsafely-without-email --dry-run
Если всё прошло удачно, то можно выпустить сертификаты уже на самом деле, убрав последний ключ из предыдущей команды.После того, как сертификат будет успешно выпущен, в каталоге /etc/letsencrypt/renewal будет создан файл с параметрами перевыпуска сертификата. Отслеживая срок действия сертификата в /etc/letsencrypt/live/имя домена/cert.pem можно автоматизировать перевыпуск сертификатов при помощи команды
certbot renew
Для автоматического перевыпуска сертификата, без участия пользователя, нужно в файле /etc/letsencrypt/renewal/домен.conf раскомментировать строку, указывающую оставшийся срок действия сертификата, при достижении которого будет предпринята поптка его обновления
renew_before_expiry = 45 daysВсе скрипты и краткая инструкция лежат на GitHub.
Ругается на ошибку в 17 строке yandex-auth-hook.sh — python: command not found
ОтветитьУдалитьИ потом (23) Failed writing body
Но завершается как бы успешно — The dry run was successful
Просветите, чего он хочет?
Похоже, скрипт не знает, где искать python. Возможно он отсутствует в системе, или сломана ссылка на него.
УдалитьНа новом ubuntu заменить python на python3
УдалитьСпасибо, помогло заменить на python3
Удалитьхотя и без этого работало, но теперь и на ошибку не ругается.
При попытке получить сертификат для поддомена, говорит что не нашел ключ...
ОтветитьУдалитьСкрипт рассчитан на выпуск wildcard сертификатов для доменов второго уровня. Для доменов третьего и выше уровней можно использовать скрипты из репозитория https://github.com/myallod/certbot-dns-pddyandex
УдалитьСтранно, при попытке получения токена для домена, пишет что Error: no_such_domain хотя домен делегирован на сервера яндекса. Может что-то еще нужно проденлать?
ОтветитьУдалитьНужно на страницу https://connect.yandex.ru/ войти под именем владельца домена, а после успешной авторизации, перейти на страницу получения токена.
УдалитьСпасибо добрый человек, сэномил мне 1 день возни с "Яндексом"
УдалитьКак-то инструкция слегка неполная без определения когда же заканчивается сертификат, если доменов не один, то надо по крону запускать какой-то скрипт который бы проверял все сертификаты, допустим раз в день и если осталось меньше 3 дней до конца выпускал новый для домена
ОтветитьУдалитьПочитал требования к продлению и решил что тупо поставлю команду в крон на обновление каждый месяц и норм
УдалитьНа самом деле не нужно создавать отдельное задание в крон. Certbot создаёт задание на обновление сертификатов и сохраняет параметры выпуска сертификатов в /etc/letsencrypt/renewal.
УдалитьСрок действия сертификата можно проверять с помощью openssl.
Срок, по наступлении которого нужно перевыпустить сертификат указан в параметре renew_before_expiry = 45 days, который указан в файле /etc/letsencrypt/renewal/домен.conf. По умолчанию он закомментирован, комментарий нужно убрать и указать количество дней до истечения срока действия сертификата, когда его нужно обновить.
УдалитьО как, спасибо, в статье в конце сбивает с толку что надо что-то отслеживать и автоматизировать, хотя вы говорите что уже всё автоматизировано и надо только в конфиге раскомментировать
Удалитьогромное спасибо, работает отлично!
ОтветитьУдалитьБольшое спасибо! Есть вопрос: при попытке создать сертификат для нескольких доменов, TXT запись "_acme-challenge" создаётся только у последнего указанного домена
ОтветитьУдалитьИзвиняюсь, запись создалась, но почему то спустя 15 минут
УдалитьПривет. Скрипт зависает на
ОтветитьУдалитьPerforming the following challenges:
dns-01 challenge for домен
dns-01 challenge for домен
при этом TXT-запись создаётся.
Скрипт не зависает, а ждёт, пока dns-запись появится на всех 3 dns-серверах, на которых проверяется её существование, 2 публичных dns самого Яндекса и один от Google. Это сделано из-за того, что когда Let's Encrypt пойдёт проверять её наличие на ns-серверах домена, то из-за каких-то настроек синхронизации у самого Яндекса может этой записи не оказаться. По сути дела, этот поиск сделан для того, чтобы удостовериться, что запись доступна из интернета.
Удалитьспасибо за скрипт, вчера всё получилось. не обратил сразу внимания, что там аж 20 минут ожидания
УдалитьСколько не пытался получить за 20 минут, что вручную, что со скриптом - всегда получаю "Запись TXT не найдена". Приходится ждать несколько часов, даже несмотря на то, что dig запись показывает...
УдалитьПоэтому мне пришлось отказаться от Яндекса и перенести домен на TimeWeb, только тогда прокатило, похоже у Яндекса что-то не то с настройками
УдалитьВ Ubuntu 20.04 всё оказалось намного проще, быстрее и с Яндексом сработало. Вот тут нашла решение: https://serverspace.ru/support/help/lets-encrypt-ubuntu-20-04/
УдалитьОт залетного бро огромное спасибо!!! Выручил
ОтветитьУдалитьДля тех, кому лень разбираться с версией пайтон, можно заменить
ОтветитьУдалитьpython -c "import sys,json;print(json.load(sys.stdin)['record']['record_id'])"
на
sed -r 's/.*"record_id": ?([0-9]*).*/\1/'
и
python -c "import sys,json;print(json.load(sys.stdin)['success'])"
на
sed -r 's/.*"success": ?"([a-z]*)".*/\1/'
Ооо, спасибо, минус одна зависимость у скрипта
УдалитьТут вдруг штука одна неприятная случилась. Wildcard не обновляется. Все по рецепту было, работало пару лет без претензий. Сегодня вот такое сообщение на выходе:
ОтветитьУдалитьRunning manual-cleanup-hook command: /scripts/certbot-dns-pddyandex/yandex-cleanup-hook.sh
Some challenges have failed.
IMPORTANT NOTES:
- The following errors were reported by the server:
Domain: site.ru
Type: unauthorized
Detail: During secondary validation: No TXT record found at
_acme-challenge.site.ru
Domain: site.ru
Type: unauthorized
Detail: No TXT record found at _acme-challenge.site.ru
To fix these errors, please make sure that your domain name was
entered correctly and the DNS A/AAAA record(s) for that domain
contain(s) the right IP address.
Естественно, токен проверен, ТХТ-записи создаются, А-запись не изменялась (все работает годами без изменений). Есть подозрение что проблема связана с какой-нибудь блокировкой и т.д.
Подскажешь что-нибудь, хоть копать куда? Спасибо!
Кстати, не-Wildcard'ы обновились за несколько секунд с командой:
Удалитьcertbot-auto certonly -d site2.ru -d www.site2.ru
У меня 23 мая успешно обновился wildcard, следующий в августе
УдалитьДобрый день!
ОтветитьУдалитьСтолкнулся с проблемой при попытке сгенерировать Let's Encrypt Wildcard SSL-сертификат при помощи Certbot. TXT-запись создается и резолвится на стороне dns1.yandex.net, dns2.yandex.net и 8.8.8.8, но в результате выдается ошибка о том, что запись не существует. Пробовали ожидать час, результат такой же. До 1 июня сертификаты генерировались успешно и все работало. Генерация происходит на ОС Ubuntu 22.04.1 LTS, версия Certbot: 1.29.0. Подскажите, у кого-то была такая же проблема? Если да, то удалось ли решить?
Этот комментарий был удален автором.
ОтветитьУдалитьчтобы не забыть, инструкция для нового api яндекса:
ОтветитьУдалить1) устанавливаем acme.sh
2) находим файл dns_yandex360.sh, записываем в него токен и orgid:
export Yandex360_Token="yxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
export Yandex360_OrgID="8xxxx"
и помещаем его в acme.sh/dnsapi
3)
/root/acme.sh/acme.sh --issue --server letsencrypt --dns dns_yandex360 -d domain.ru -d '*.domain.ru' --dnssleep 1800
voila
Здравствуйте. Пытаюсь адаптировать данный скрипт под провайдера beget, возник такой вопрос, при получении сертификата в TXT требуется внести две записи для проверки, у меня вносится одна, прошу подсказать в какую сторону копать.
ОтветитьУдалить