Блогът на Петко
False Hopes

Затворена бета на Let's Encrypt

Петко Борджуков

Вчера от Let’s Encrypt ми изпратиха E-Mail, че домейните, за които съм поискал да бъдат подписани сертификати, са одобрени.

Let’s Encrypt

Let’s Encrypt е автоматизиран, отворен доставчик на (безплатни) удостоверителни услуги (на английски – Certificate Authority).

За повече информация, препоръчвам следните лекции:

Записване за бета програмата

Преди повече от месец, в Twitter акаунта на Let’s Encrypt беше обявено записване за бета програма, което ставаше, посредством попълване на Google формуляр. Въпреки че намерих за ироничен факта, че разчитат на Google, реших да изпратя заявка.

Формулярът беше изключително прост – поле, в което да изредиш за кои домейни искаш сертификати и поле за E-Mail адрес.

Начало на бета програмата

На 19-и октомври от Let’s Encrypt обявиха, че са получили cross-signatures за двата си intermediate сертификата, което означава, че подписаните от тях сертификати вече са доверени в браузърите.

Малко повече от седмица след това получих E-Mail, че домейните, за които съм поискал да бъдат подписани сертификати, са одобрени. Ето съдържанието на E-Mail-а:

From: Let’s Encrypt Beta <betaprogram@letsencrypt.org>

Date: Tue, Oct 27, 2015 at 5:14 PM

Subject: Let’s Encrypt Closed Beta Invite

To: [email here]

Greetings from Let’s Encrypt, [email here].

Thank you for your interest in our beta program! We’re excited to let you know that your domains (below) have been whitelisted, and you can now utilize an ACME client to obtain a certificate for them.

Quick Start

To use Let’s Encrypt’s official client to obtain your real certificates, you will need to provide the production API URL on the command line:

https://acme-v01.api.letsencrypt.org/directory

When running the Python client (installation directions [1]), be sure to specify the --server argument with the production URL:

git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt
./letsencrypt-auto --agree-dev-preview --server \
      https://acme-v01.api.letsencrypt.org/directory auth

If you are using a different ACME client, be sure to configure it to use the production URL in order to get valid certificates. Many clients will default to the staging URL.

Known Issues

There are some known issues with the official Python client posted here: https://github.com/letsencrypt/letsencrypt/wiki/Known-issues

Renewals and Lifetimes

Certificates from Let’s Encrypt are valid for 90 days. We recommend renewing them every 60 days to provide a nice margin of error. As a beta participant, you should be prepared to manually renew your certificates at that time. As we get closer to General Availability, we hope to have automatic renewal tested and working on more platforms, but for now, please play it safe and keep track.

Rate Limiting

During this beta test we have very tight rate-limiting in place. We plan to loosen these limits as the beta proceeds.

There are two rate limits in play: Registrations/IP address, and Certificates/Domain.

Registrations/IP address limits the number of registrations you can make in a given day; currently 10. This means you should avoid deleting the /etc/letsencrypt/accounts folder, or you may not be able to re-register.

Certificates/Domain you could run into through repeated re-issuance. This limit measures certificates issued for a given combination of Top Level Domain + Domain. This means if you issue certificates for the following domains, at the end you would have what we consider 4 certificates for the domain example.com.

www.example.com
example.com www.example.com
webmail.example.com ldap.example.com
example.com www.example.com

The limit on Certificates/Domain has a window of 60 days, to give 30 days for renewals. We know it’s restrictive at present; thank you for your patience in helping us ensure Let’s Encrypt is ready for the whole world.

Certificate Transparency

Part of our transparency mission includes publicly disclosing the certificates we issue via Certificate Transparency. Your email address is not publicly disclosed.

Helpful Information

Let’s Encrypt maintainence events are posted on https://letsencrypt.status.io/ and Twitter (@letsencrypt_ops). If you need help, both the Let’s Encrypt community at https://community.letsencrypt.org/ and #letsencrypt on irc.freenode.org are excellent sources of assistance.

If there are updates for Beta program participants, they will be posted at the community site at https://community.letsencrypt.org/t/beta-program-announcements/1631.

Your whitelisted domains are: …

След като набързо хвърлих едно око на изходния код на https://github.com/letsencrypt/letsencrypt, го клонирах на FreeBSD машината си и го изпробвах. Не ми допада, че letsencrypt-auto трябва да се изпълни с root привилегии, но изглежда работи доста чисто. Промените върху файловата система, които забелязах, са създаване на директории /etc/letsencrypt, в която се помещават ключовете и сертификатите и ~/.local/share/letsencrypt, в която е „виртуалната python среда“ на инструмента.

По подразбиране letsencrypt-auto прави няколко неща:

Както споменах, не ми хареса нуждата да изпълня скрипта с административни права. Освен това, не ми хареса от колко неща зависи под FreeBSD:

bootstrap/freebsd.sh:

#!/bin/sh -xe

pkg install -Ay \
  git \
  python \
  py27-virtualenv \
  augeas \
  libffi \

Изпълнението на този скрипт ми инсталира perl-5.20 и ми преинсталира(!) perl-5.18, без очевидна нужда за това.

Валидацията на домейните ми също беше доста неприятна – като начало, скриптовете не откриват наличието на nginx и те изправят пред избор (в грозно форматиран текст, който прилича на stack trace на python) – да създадеш файл в /.well-known/ на уеб сървъра, който отговаря за дадения домейн, или да спреш уеб сървъра и да изпълниш Bash-python black voodoo magic заклинание, което пуска уеб сървър, който сервира нужните данни. Ето как изглежда съобщението, което се показва след приятния curses-базиран диалог за избор на домейни:

Bash-Python Black Voodoo Magic:

Make sure your web server displays the following content at
http://petko.me/.well-known/acme-challenge/al8Z37ePxkms5jo0WtqguLq2aT7sQEd_S1IubcFzpwU before continuing:

{"header": {"alg": "RS256", "jwk": {"e": "AQAB", "kty": "RSA", "n": "vhDQ-ssP5mgMd27zpovkmSD7oV3sjhTKdO2AU5N9GMkUMNsQ612dIa1sxXGErrW9WGlOa8EkPeK2T4JA5IBUNnuxJBJfT-EmT3suH2uW8klbFlJqHDIAHbnVZjVcrqKFS4Iuub5oaG0wPT4hPe4IKR3vob7DL7Yv0sgHwFFD0N8VWDCb6kG5HUqyvvMr6x0sPOyPQEzzJO-YWUwZM-FQ-sXLfxkBsI9hz9EqfaxvGV3wUVY_OOKMbKcyCM0e_sa7Vrd0jg_FEgHLW2dFVe1wdLLW4YEiimNHwINVloZxQ4QrSAaGI-aXJx1FojPGpkLwviSTmMGGC2MD7BSVqIzjiQ"}}, "payload": "eyJ0bHMiOiBmYWxzZSwgInRva2VuIjogImFsOFozN2VQeGttczVqbzBXdHFndUxxMmFUN3NRRWRfUzFJdWJjRnpwd1UiLCAidHlwZSI6ICJzaW1wbGVIdHRwIn0", "signature": "LCNiHNdZheeLCEcNG3JStH6J3pTZHqWL3Zne5AkzuFJ5NM8UQrhpAE-ie8E5VeXEGvXZFlJOpKU72rDmlaBQIyrWF1NLHh1A9vbTdPf_xa1lwVvASAFnvgcUU0c7o--5BegP4GEeWHkeOpqi5s45f-ktNUxtPuY9KrK_ByEQdcwfTcaUGwgOy86Oy-zVfyU45K6e-7fGahXLmrmcG9ADf4EQFVAx6Kax42kTkGl9oS-IiitQcCkc7pZA8nDWG_D6f5u01bBvBOn4PewBauajBr5fOX1StIi4ealnDKq0mcY4JlD8Efp6wAopqQAIoecHxCbiRUWULBevvW6wCzpUKA"}

Content-Type header MUST be set to application/jose+json.

If you don't have HTTP server configured, you can run the following
command on the target server (as root):

mkdir -p /tmp/letsencrypt/public_html/.well-known/acme-challenge
cd /tmp/letsencrypt/public_html
echo -n '{"header": {"alg": "RS256", "jwk": {"e": "AQAB", "kty": "RSA", "n": "vhDQ-ssP5mgMd27zpovkmSD7oV3sjhTKdO2AU5N9GMkUMNsQ612dIa1sxXGErrW9WGlOa8EkPeK2T4JA5IBUNnuxJBJfT-EmT3suH2uW8klbFlJqHDIAHbnVZjVcrqKFS4Iuub5oaG0wPT4hPe4IKR3vob7DL7Yv0sgHwFFD0N8VWDCb6kG5HUqyvvMr6x0sPOyPQEzzJO-YWUwZM-FQ-sXLfxkBsI9hz9EqfaxvGV3wUVY_OOKMbKcyCM0e_sa7Vrd0jg_FEgHLW2dFVe1wdLLW4YEiimNHwINVloZxQ4QrSAaGI-aXJx1FojPGpkLwviSTmMGGC2MD7BSVqIzjiQ"}}, "payload": "eyJ0bHMiOiBmYWxzZSwgInRva2VuIjogImFsOFozN2VQeGttczVqbzBXdHFndUxxMmFUN3NRRWRfUzFJdWJjRnpwd1UiLCAidHlwZSI6ICJzaW1wbGVIdHRwIn0", "signature": "LCNiHNdZheeLCEcNG3JStH6J3pTZHqWL3Zne5AkzuFJ5NM8UQrhpAE-ie8E5VeXEGvXZFlJOpKU72rDmlaBQIyrWF1NLHh1A9vbTdPf_xa1lwVvASAFnvgcUU0c7o--5BegP4GEeWHkeOpqi5s45f-ktNUxtPuY9KrK_ByEQdcwfTcaUGwgOy86Oy-zVfyU45K6e-7fGahXLmrmcG9ADf4EQFVAx6Kax42kTkGl9oS-IiitQcCkc7pZA8nDWG_D6f5u01bBvBOn4PewBauajBr5fOX1StIi4ealnDKq0mcY4JlD8Efp6wAopqQAIoecHxCbiRUWULBevvW6wCzpUKA"}' > .well-known/acme-challenge/al8Z37ePxkms5jo0WtqguLq2aT7sQEd_S1IubcFzpwU
# run only once per server:
$(command -v python2 || command -v python2.7 || command -v python2.6) -c \
"import BaseHTTPServer, SimpleHTTPServer; \
SimpleHTTPServer.SimpleHTTPRequestHandler.extensions_map = {'': 'application/jose+json'}; \
s = BaseHTTPServer.HTTPServer(('', 80), SimpleHTTPServer.SimpleHTTPRequestHandler); \
s.serve_forever()"
Press ENTER to continue

Първият вариант ми се стори по-приятен, въпреки великата глупост, че трябва на ръка да се зададе в конфигурацията на web сървъра какъв content type трябва да има дадения файл. За нещастие, по някаква причина не сработи при мен и се наложи да прибягна до втория вариант.

Втория вариант проработи за един домейн, но не и ако бях задал два – petko.me www.petko.me.

За всяко ново изпълнение на letsencrypt-auto се генерира нов (2048-битов!) частен ключ. Няма очевиден начин за увеличаване на големината на ключа или да указване на вече съществуващ такъв. След ровене открих, че има --csr параметър, който обаче при мен не проработи.

В крайна сметка според мен letsencrypt-auto не трябва да бъде използван.

Алтернативен инструмент

В крайна сметка изискванията ми са следните:

Предосатвеният от Let’s Encrypt инструмент не успя да отговори на изискванията ми. За щастие попаднах на https://github.com/diafygi/letsencrypt-nosudo. Със скрипта от това репо и с долния модифициран шелскрипт (разчита key.pem и openssl.cnf да са в работната директория), успях да се сдобия с подписан сертификат за petko.me и www.petko.me.

letsencrypt/examples/generate-csr-existing-key.sh:

#!/bin/sh
# This script generates a simple SAN CSR to be used with Let's Encrypt
# CA. Mostly intended for "auth --csr" testing, but, since it's easily
# auditable, feel free to adjust it and use it on your production web
# server.

if [ "$#" -lt 1 ]
then
  echo "Usage: $0 domain [domain...]" >&2
  exit 1
fi

domains="DNS:$1"
shift
for x in "$@"
do
  domains="$domains,DNS:$x"
done

SAN="$domains" openssl req -config "${OPENSSL_CNF:-openssl.cnf}" \
  -new -nodes -subj '/' -reqexts san \
  -key key.pem \
  -out "${CSR_PATH:-csr.der}" \
  -outform DER

echo "You can now run: letsencrypt auth --csr ${CSR_PATH:-csr.der}"

Заключение

Мъка. Но има светлина в тунела.