ZaLinux.ru

Бесплатное получение и настройка автоматического продления действительных сертификатов SSL

Зачем нужен SSL-сертификат?

Многие веб-мастера уже в курсе, что действительный (валидный) SSL-сертификат предотвращает кражу логинов, паролей, сессий сайтов. Не всем это очевидно, но SSL-сертификат предотвращает изменение содержимого веб-сайта, которое показывается пользователю. Варианты модификации содержимого ограничены только фантазией злоумышленника: вставка сторонней рекламы, предложений обновить плагины или браузер, вставка стороннего содержимого, перехват нажатий клавиш с помощью JavaScript, любая модификация данных на лету (в том числе и изображений) и многое-многое другое…

Сейчас в браузере Google Chrome появился флаг (настройка), при включении которой все сайты без шифрования передачи будут помечаться как небезопасные. Пока настройка отключена…

В общем, сертификат лучше иметь, чем не иметь. Тем более задаром. ))

Т.е. никто не запрещает нам купить сертификат, причём можно получить дополнительную функциональность, которая в бесплатных отсутствует. Плюс к этому, купленный сертификат не нужно каждые три месяца продлевать.

Тем не менее, если тратиться вы не собираетесь, то уже во многих местах можно получить действительный на 3 месяца сертификат. При этом его можно продлевать неограниченное количество раз.

Например, появились хостинги, на которых в один клик можно подключить SSL-сертификат, и он автоматически будет каждые три месяца продлеваться.

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

В этой статье я хочу рассказать об ещё одной возможности: настройку сервера Linux так, что он сам получит действительный SSL-сертификат и будет автоматически его продлевать любое количество раз через заданные промежутки времени. Участие пользователя больше не требуется. Ещё одним плюсом данного метода является то, что для получения сертификата не нужен настроенный для домена почтовый ящик.

В этом нам поможет утилита acme-tiny.

acme-tiny – это крошечный, поддающийся проверке скрипт, который вы можете забросить на свой сервер для получения и обновления сертификатов Let's Encrypt. Поскольку скрипт должен быть запущен на вашем сервере и иметь доступ к вашему приватному ключу аккаунта Let's Encrypt, автор сделал его настолько крошечным, насколько это возможно (в настоящее время менее 200 строк). Единственными зависимостями для скрипта являются python и openssl.

Ещё обязательное требование – скрипт должен быть запущен на том самом сервере, где хостится домен, для которого мы получаем сертификат (зато не нужно возиться с email).

Адрес программы: https://github.com/diafygi/acme-tiny

Инструкция по использованию acme-tiny

Если у вас уже есть выданный в Let's Encrypt сертификат, и вы хотите его просто обновить, вы должны только выполнить Шаги 3 и 6.

Шаг 0. Копируем программу себе на локальный диск

git clone https://github.com/diafygi/acme-tiny.git
cd acme-tiny/

Шаг 1: Создание приватного ключа аккаунта Let's Encrypt (если у вас ещё его нет)

У вас должен быть публичный ключ, зарегистрированный с Let's Encrypt и вы должны подписывать ваши запросы соответствующим приватным ключом. Если вы не понимаете, что я только что сказал, то весьма вероятно, что этот скрипт не для вас! Пожалуйста, используйте официальный клиент Let's Encrypt. Для выполнения этой инструкции вам нужно начать с создания ключа, который будет использовать acme-tiny для регистрации для вас аккаунта и подписывания всех последующих запросов.

openssl genrsa 4096 > account.key

Использование существующего ключа Let's Encrypt

В качестве альтернативы, вы можете конвертировать ваш ключ, ранее сгенерированный оригинальным клиентом Let's Encrypt.

Приватный ключ аккаунта из клиента Let's Encrypt сохраняется в формате JWK. acme-tiny использует формат ключа PEM. Для конвертирования этого ключа, вы можете использовать инструмент скрипт преобразований от JonLundy:

# Загрузите скрипт
wget -O - "https://gist.githubusercontent.com/JonLundy/f25c99ee0770e19dc595/raw/6035c1c8938fae85810de6aad1ecf6e2db663e26/conv.py" > conv.py

# Скопируйте ваш приватный ключ в рабочую директорию
cp /etc/letsencrypt/accounts/acme-v01.api.letsencrypt.org/directory/<id>/private_key.json private_key.json

# Создайте закодированный в DER приватный ключ
openssl asn1parse -noout -out private_key.der -genconf <(python conv.py private_key.json)

# Конвертируйте в PEM
openssl rsa -in private_key.der -inform der > account.key

Шаг 2: Создание запроса подписания сертификата (certificate signing request (CSR)) для ваших доменов.

Протокол ACME (который использует Let's Encrypt) требует, чтобы им был предоставлен файл CSR (запроса подписания сертификата) даже для продлений. Вы можете использовать один и тот же CSR для множества продлений. ПРИМЕЧАНИЕ: вы не можете использовать приватный ключ аккаунта в качестве приватного ключа домена!

#генерируем приватный ключ домена (если ещё нет)
openssl genrsa 4096 > domain.key
#для одного домена
openssl req -new -sha256 -key domain.key -subj "/CN=yoursite.com" > domain.csr

#для множества доменов (используйте это, если вы хотите и для www.yoursite.com, и для yoursite.com)
openssl req -new -sha256 -key domain.key -subj "/" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=DNS:yoursite.com,DNS:www.yoursite.com")) > domain.csr

Шаг 3: Создание файлов вызова для веб-сайта вашего хоста

Вы должны доказать, что вы владелец домена, для которого вы хотите сертификат, поэтому Let's Encrypt требует, чтобы на вашем хосте лежало несколько файлов. Этот скрипт сгенерирует и запишет эти файлы в директорию, которую вы укажете; всё, что вам нужно, это убедиться, что эта директория доступна в url по адресу ".well-known/acme-challenge/". ПРИМЕЧАНИЕ: Let's Encrypt выполнит запрос в виде обычного текста HTTP на порт 80 вашего сервера, поэтому вы должны предоставить доступ к файлам вызова через HTTP (HTTPS тоже пойдёт).

#создаём директорию для файлов вызова (отредактируйте под свои нужды)
mkdir -p /var/www/challenges/

Можно прописать псевдоним в конфигурационном файле сервера:

#пример для nginx
server {
    listen 80;
    server_name yoursite.com www.yoursite.com;

    location /.well-known/acme-challenge/ {
        alias /var/www/challenges/;
        try_files $uri =404;
    }

    ...the rest of your config
}

Мне нравится способ попроще, просто создать нужные директории в каталоге веб-сервера (на примере Arch Linux):

sudo mkdir -p /srv/http/.well-known/acme-challenge/

Step 4: Получите подписанный сертификат!

Теперь, когда вы настроили ваш сервер для генерации всех необходимых файлов, запустите этот скрипт на вашем сервере с разрешениями, которые ему нужны для записи в вышеприведённую папку и чтения вашего приватного ключа аккаунта и CSR.

#запустите скрипт на вашем сервере
python acme_tiny.py --account-key ./account.key --csr ./domain.csr --acme-dir /var/www/challenges/ > ./signed.crt

Например, мой реальный пример (для файлов вызова я использую директорию /srv/http/.well-known/acme-challenge/) выглядит так:

python acme_tiny.py --account-key account.key --csr ./domain.csr --acme-dir /srv/http/.well-known/acme-challenge/ > signed.crt

Step 5: Установите сертификаты

Подписанный https сертификат, который вывел этот скрипт, может использоваться вместе с приватным ключом, для запуска https сервера (кстати, эта же пара сертификат-ключ прекрасно будут работать в программах postfix и dovecot и шифровать и подписывать передаваемые почтовые сообщения. Некоторые подробности здесь). Вам нужно включить их в https настройки в вашей конфигурации сервера. Здесь пример, как настроить nginx сервер:

#ПРИМЕЧАНИЕ: Для nginx, вам нужно добавить промежуточный сертификат Let's Encrypt к вашему сертификату
wget -O - https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem > intermediate.pem
cat signed.crt intermediate.pem > chained.pem
server {
    listen 443;
    server_name yoursite.com, www.yoursite.com;

    ssl on;
    ssl_certificate /path/to/chained.pem;
    ssl_certificate_key /path/to/domain.key;
    ssl_session_timeout 5m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA;
    ssl_session_cache shared:SSL:50m;
    ssl_dhparam /path/to/server.dhparam;
    ssl_prefer_server_ciphers on;

    ...the rest of your config
}

server {
    listen 80;
    server_name yoursite.com, www.yoursite.com;

    location /.well-known/acme-challenge/ {
        alias /var/www/challenges/;
        try_files $uri =404;
    }

    ...the rest of your config
}

Пример настройки Apache для SSL можно найти здесь.

Шаг 5.1. Перемещение полученных файлов в постоянную директорию расположения

Помните, что вам нужно переместить полученный файлы в надлежащие директории. К примеру, я храню файлы в следующих расопложениях:

  • Цепочка корневых сертификатов: /etc/ssl/certs/ca-bundle.crt
  • Сертификат на домен: /etc/ssl/certs/server.crt
  • Приватный (секретный) ключ: /etc/ssl/private/server.key

Для того, чтобы присвоить файлам соответствующие имена и переместить в нужные директории выполняем:

sudo mv intermediate.pem /etc/ssl/certs/ca-bundle.crt
sudo mv signed.crt /etc/ssl/certs/server.crt
sudo mv domain.key /etc/ssl/private/server.key

Если на одном сервере вы имеете несколько доменов с HTTPS, то удобнее в названиях файлов использовать имена доменов.

Шаг 6: Настройка автоматического продления с cronjob

Поздравляю! Теперь ваш сайт использует https! К сожалению, сертификаты Let's Encrypt действительны только на протяжении 90 дней, поэтому вам нужно часто их продлевать. Не волнуйтесь! Это будет делаться автоматически! Просто создайте баш скрипт и добавьте его в ваш crontab (смотрите пример такого скрипта ниже).

Пример renew_cert.sh:

#!/usr/bin/sh
python /path/to/acme_tiny.py --account-key /path/to/account.key --csr /path/to/domain.csr --acme-dir /var/www/challenges/ > /tmp/signed.crt || exit
wget -O - https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem > intermediate.pem
cat /tmp/signed.crt intermediate.pem > /path/to/chained.pem
service nginx reload
#пример строки в ваш crontab (запускать один раз в месяц)
0 0 1 * * /path/to/renew_cert.sh 2>> /var/log/acme_tiny.log

Разрешение

Самой большой проблемой, с которой вы вероятно столкнётесь при настройке и запуске скрипта – это разрешения. Вы хотите ограничить доступ к вашему приватному ключу аккаута и каталогу файлов вызова настолько, насколько это возможно. Я рекомендую создать специального пользователя для работы с этим скриптом, приватном ключом аккаунта и папкой вызова. Затем добавьте возможность этому пользователю писать в ваш установленный файл сертификата (например, /path/to/chained.pem) и перезагружать ваш веб-сервер. Таким образом, скрипт cron будет делать следующее: переписывать ваш старый сертификат и перезагружать ваш веб-сервер и при этом у него не будет разрешения на что-либо ещё.

УБЕДИТЕСЬ, ЧТО:

  • Сделали резервную копию секретного ключа вашего аккаунта (e.g. account.key)
  • Не позволяйте скрипту быть способным читать ваш приватный ключ домена!
  • Не позволяйте скрипту быть запущенным от рута!

Ошибки при выполнении acme-tiny

Если у вас возникает ошибка

Signing certificate...
Traceback (most recent call last):
  File "acme_tiny.py", line 198, in <module>
    main(sys.argv[1:])
  File "acme_tiny.py", line 194, in main
    signed_crt = get_crt(args.account_key, args.csr, args.acme_dir, log=LOGGER, CA=args.ca)
  File "acme_tiny.py", line 161, in get_crt
    raise ValueError("Error signing certificate: {0} {1}".format(code, result))
ValueError: Error signing certificate: 400 b'{"type":"urn:acme:error:malformed","detail":"Error creating new cert :: Certificate public key must be different than account key","status":400}'

Это означает, что вы пытаетесь использовать один и тот же ключ в качестве приватного ключа аккаунта и приватного ключа домена – это должны быть разные ключи, посмотрите внимательно на шаги 1 и 2.

Рекомендуемые статьи:

1 Комментарий

  1. AlekseyShi

    Пробовал сделать для 192.168.0.62 (веб-сервер внутри локалки)
    Получаю : Issuance for IP addresses not supported
    Жаль.

    Поскольку ключи сгенерены в рабочем (домашнем) каталоге, то потом при перeходе в acme-tiny
    команду следует вызывать так:
    python acme-tiny/acme_tiny.py --account-key account.key --csr ./domain.csr --acme-dir /srv/http/.well-known/acme-challenge/ > signed.crt

    Иначе она не видит файлы ключей (мы в каталоге acme-tiny, а ключи вне ее)

Оставить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *