Feature #3006
Updated by Viacheslav Anzhiganov 27 days ago
Реализовать получение SSL-сертификатов по протоколу ACME для получения SSL-сертификатов Let'a Encrypt - [[ACME Protocol Support]] Based on perplexity promt: https://www.perplexity.ai/search/napishi-programmu-na-python-ko-Ak_4QyRdS0OpFM1reQ6dRg Сделано - [ ] Реализовал конечные точки acme-challenge - [ ] Реализова # Условия - На сервере ACME LetsEncrypt есть лимиты по запросам с одного IP - Необходимо стремиться к минимальному количеству неуспешных запросов к Acme серверу - перед отправкой запорса к ACME-серверу Необходимо убедиться в том, что хост, для которого запрашивается SSL-сертификат был прописан на сервера ProCDN Схема работы службы Cert для получения Lets encrytp SSL  ## Программа на Python для получения SSL-сертификата Let's Encrypt по ACME и сохранения в БД Ниже приведён пример программы, которая: - Использует библиотеку `acme` для взаимодействия с Let's Encrypt по протоколу ACME. - Проходит HTTP-01 challenge для валидации домена. - Получает SSL-сертификат. - Сохраняет сертификат и приватный ключ в базу данных PostgreSQL в формате PEM. ## Основные зависимости - `acme` (часть certbot): для работы с ACME-протоколом. - `cryptography`: для генерации ключей и создания CSR. - `psycopg2` или `asyncpg`: для работы с PostgreSQL. ## Пример кода python ```python import time import psycopg2 from acme import client, messages, challenges from acme import crypto_util from josepy import JWKRSA from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.backends import default_backend # Константы DIRECTORY_URL = 'https://acme-v02.api.letsencrypt.org/directory' DOMAIN = 'example.com' EMAIL = 'admin@example.com' # 1. Генерируем ключ пользователя user_key = rsa.generate_private_key( public_exponent=65537, key_size=2048, backend=default_backend() ) jwk = JWKRSA(key=user_key) # 2. Создаём клиента ACME net = client.ClientNetwork(jwk) directory = client.ClientV2.get_directory(DIRECTORY_URL, net) acme_client = client.ClientV2(directory, net=net) # 3. Регистрируем аккаунт account = acme_client.new_account( messages.NewRegistration.from_data( email=EMAIL, terms_of_service_agreed=True ) ) # 4. Запрашиваем авторизацию для домена order = acme_client.new_order( csr_pem=None, identifiers=[ messages.Identifier( typ=messages.IDENTIFIER_FQDN, value=DOMAIN ) ] ) authz = order.authorizations[0] challenge = next(c for c in authz.body.challenges if isinstance(c.chall, challenges.HTTP01)) # 5. Вам нужно разместить challenge token на вашем сервере по адресу /.well-known/acme-challenge/{token} # challenge.chall.path, challenge.chall.validation(jwk) # Этот шаг требует настройки веб-сервера! # 6. Отвечаем на challenge acme_client.answer_challenge(challenge, challenge.chall.response(jwk)) # 7. Ожидаем подтверждения авторизации while True: authz = acme_client.poll(authz)[0] if authz.body.status == 'valid': break time.sleep(2) # 8. Генерируем ключ для сертификата и CSR cert_key = crypto_util.make_key(bits=2048) csr_pem = crypto_util.make_csr(cert_key, [DOMAIN]) # 9. Запрашиваем выпуск сертификата final_order = acme_client.finalize_order(order, csr_pem) certificate_pem = acme_client.fetch_chain(final_order)[0].public_bytes().decode() # 10. Сохраняем сертификат и ключ в PostgreSQL conn = psycopg2.connect("dbname=yourdb user=youruser password=yourpass") cur = conn.cursor() cur.execute(""" INSERT INTO certificates (domain, cert_pem, key_pem) VALUES (%s, %s, %s) """, (DOMAIN, certificate_pem, cert_key.decode())) conn.commit() cur.close() conn.close() ``` ## ссылки по теме * [ ] https://github.com/torhve/lua-resty-letsencrypt * [ ] https://github.com/auto-ssl/lua-resty-auto-ssl