📜 ⬆️ ⬇️

Simple automation example letsencrypt

image

The certification center “Let's Encrypt” (hereinafter simply letsencrypt) came out of beta a couple of months ago, got used to it in real conditions, got rid of childhood diseases and was overgrown by various customers. And by this time issued 5 million certificates. It's time to introduce, i.e. receive certificates for your domains and update them automatically. But how to implement so as to get closer to your favorite admin "set and forget"? So that it was easy to get new certificates, and the old ones were updated automatically? So how to add a bit of security to this process?
The answer is under the cut.

TL; DR / Quick Start / cheat sheet
  • Download and configure the script
    sudo adduser --system --home /opt/letsencrypt le sudo -u le -s git clone https://github.com/lukas2511/letsencrypt.sh.git /opt/letsencrypt/ mkdir /opt/letsencrypt/.acme-challenges echo CONTACT_EMAIL="your@email" > /opt/letsencrypt/config echo "_" > /opt/letsencrypt/domains.txt 
  • add line to nginx virtual host config
     location /.well-known/acme-challenge/ { alias /opt/letsencrypt/.acme-challenges/; } 
  • run the script
     sudo -u le /opt/letsencrypt/letsencrypt.sh --cron 
  • add three more lines to the virtual host config
     listen 443 ssl; ssl_certificate /opt/letsencrypt/certs/_/fullchain.pem; ssl_certificate_key /opt/letsencrypt/certs/_/privkey.pem; 
  • add le to cron
     1 0 * * * /opt/letsencrypt/letsencrypt.sh --cron 


As I said, letsencrypt has been overgrown with various clients who allow to get a certificate. These same clients, by the way, already dozens for different systems and programming languages. The article will tell about the implementation of the client on bash from lukas2511, letsencrypt.sh . This is one bash script that lies in its folder and only needs openssl to work. It will run under a separate user. Of course, if you wish, you can always tighten the nuts even more tightly in terms of security - run in chroot, etc.

First you need to download and configure the script.
Suppose the OS is linux, the web server is nginx, the working folder of the script is / opt / letsencrypt, and the user is le.
Create a system user from which the script will work. When creating a system user in debian / ubuntu, it exposes the / bin / false shell and is assigned the nogroup group, which is fine for us.
 $ sudo adduser --system --home /opt/letsencrypt le 

Now you can become this user and do everything under it (except for the nginx configuration).
Download the script and see the contents.
 $ sudo -u le -s $ git clone https://github.com/lukas2511/letsencrypt.sh.git /opt/letsencrypt/ $ ls -la /opt/letsencrypt/ total 84 drwxr-xr-x 4 le le 4096 Jun 25 15:56 . drwxr-xr-x 3 root root 4096 Jun 25 15:53 .. -rw-r--r-- 1 le le 1406 Jun 25 15:56 CHANGELOG drwxr-xr-x 3 le le 4096 Jun 25 15:56 docs drwxr-xr-x 8 le le 4096 Jun 25 15:56 .git -rw-r--r-- 1 le le 108 Jun 25 15:56 .gitignore -rwxr-xr-x 1 le le 37634 Jun 25 15:56 letsencrypt.sh -rw-r--r-- 1 le le 1080 Jun 25 15:56 LICENSE -rw-r--r-- 1 le le 3040 Jun 25 15:56 README.md -rwxr-xr-x 1 le le 8048 Jun 25 15:56 test.sh -rw-r--r-- 1 le le 107 Jun 25 15:56 .travis.yml 

To work, the script needs a folder where it will add files for domain validation.
By default, the script is configured to use the /opt/letsencrypt/.acme-challenges folder and will fall with an error if there is no such folder.
It is also desirable to create a config with the necessary parameters. The script tries to take parameters for operation from the /opt/letsencrypt/config file. By default, there is no file and the script uses default values, but there is a well-documented config in the documentation folder that can be taken as a basis.
Create a folder and copy the config
 $ mkdir /opt/letsencrypt/.acme-challenges $ cp /opt/letsencrypt/docs/examples/config /opt/letsencrypt/config 

To see what values ​​the script works with, you can call it with the --env
 $ /opt/letsencrypt/letsencrypt.sh --env # letsencrypt.sh configuration # # !! WARNING !! No main config file found, using default config! # declare -- CA="https://acme-v01.api.letsencrypt.org/directory" declare -- LICENSE="https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf" declare -- CERTDIR="/opt/letsencrypt/certs" declare -- CHALLENGETYPE="http-01" declare -- DOMAINS_TXT="/opt/letsencrypt/domains.txt" declare -- HOOK="" declare -- HOOK_CHAIN="no" declare -- RENEW_DAYS="30" declare -- ACCOUNT_KEY="/opt/letsencrypt/accounts/aHR0cHM6Ly9hY21lLXYwMS5hcGkubGV0c2VuY3J5cHQub3JnL2RpcmVjdG9yeQo/account_key.pem" declare -- ACCOUNT_KEY_JSON="/opt/letsencrypt/accounts/aHR0cHM6Ly9hY21lLXYwMS5hcGkubGV0c2VuY3J5cHQub3JnL2RpcmVjdG9yeQo/registration_info.json" declare -- KEYSIZE="4096" declare -- WELLKNOWN="/opt/letsencrypt/.acme-challenges" declare -- PRIVATE_KEY_RENEW="yes" declare -- OPENSSL_CNF="/usr/lib/ssl/openssl.cnf" declare -- CONTACT_EMAIL="" declare -- LOCKFILE="/opt/letsencrypt/lock" 

Description of some parameters
CA - which certification authority to use. There are at least two of them - combat (by default) and test . The fact is that combat has different restrictions on the frequency of requests and the number of domains. It is easy to rest against these limitations when testing. Therefore, I recommend specifying a test center for test runs. It works in the same way as combat, it simply generates invalid certificates.
Here is the test CA:
CA="https://acme-staging.api.letsencrypt.org/directory"

CERTDIR - folder for certificates. Inside it there are hotel folders by the host name. And in these folders are certificates for each host. You will need to configure nginx to read certificates from these folders (see below).
')
DOMAINS_TXT - list of domains. One line - one certificate. In one line there can be several domains, then one certificate is created for them. The script takes the first domain as the name of the certificate, and the remaining domains indicate as optional. For example, for such a file, the script will create two certificates: some.domain.com and test.com.
some.domain.com another.domain.net example.domain.org
test.com www.test.org ftp.test.net

HOOK is a script that runs on various actions (during domain validation, certificate generation, etc.).
Different parameters are passed to the script: operation name, paths to new certificates, etc.
Specifying your script can help if you need to perform a little more action at each step.
For example, a certificate needs to be decomposed into several servers, or a domain should be validated through dns, and not through a file.
The script, which does nothing, but contains a lot of comments, is located at /opt/letsencrypt/docs/examples/hook.sh

RENEW_DAYS - after how many days to renew the certificate. Maximum 90, default 30.

CONTACT_EMAIL - working email administrator.

I recommend specifying your email CONTACT_EMAIL in CONTACT_EMAIL in the CONTACT_EMAIL and CONTACT_EMAIL up a test CA for the duration of the tests.
The installation and initial setup of the script is complete. Now you can get certificates.

To get started, we will get a certificate for one domain: letest.lexore.net
In nginx for the test we will make a simple config of a virtual host that will output the protocol, http or https.
 server { listen 80; server_name letest.lexore.net; location /.well-known/acme-challenge/ { alias /opt/letsencrypt/.acme-challenges/; } location / { default_type text/plain; return 200 "scheme: $scheme"; } } 

Key parameter: location /.well-known/acme-challenge/
/opt/letsencrypt/.acme-challenges/ are created in the /opt/letsencrypt/.acme-challenges/ folder to confirm that you are managing the site.
They must be available at _/.well-known/acme-challenge/ , otherwise the certificate will not be signed.
File names are randomly generated, so it's easier to open access to the entire folder.
At the end, the script deletes the created file, so the folder will not be cluttered.

Restart nginx and check the site:
 $ curl -i letest.lexore.net HTTP/1.1 200 OK Server: nginx Date: Sun, 26 Jun 2016 13:13:18 GMT Content-Type: text/plain Content-Length: 12 Connection: keep-alive scheme: http 

Now you need to register the host name in domains.txt and run the script itself.
 $ echo letest.lexore.net > /opt/letsencrypt/domains.txt $ /opt/letsencrypt/letsencrypt.sh --cron # INFO: Using main config file /opt/letsencrypt/config Processing letest.lexore.net + Signing domains... + Creating new directory /opt/letsencrypt/certs/letest.lexore.net ... + Generating private key... + Generating signing request... + Requesting challenge for letest.lexore.net... + Responding to challenge for letest.lexore.net... + Challenge is valid! + Requesting certificate... + Checking certificate... + Done! + Creating fullchain.pem... + Done! 

The certificate is ready, the certificate and key files are in the " /opt/letsencrypt/certs/letest.lexore.net " folder.
It remains to add the settings in nginx. You need to add the following lines to the virtual host config:
 listen 443 ssl; ssl_certificate /opt/letsencrypt/certs/letest.lexore.net/fullchain.pem; ssl_certificate_key /opt/letsencrypt/certs/letest.lexore.net/privkey.pem; 

After rebooting nginx, you can try the site in a browser.
If a test CA was specified in the script configuration, the browser will call for a certificate.
What does this certificate look like in firefox
image

But it still means that the script and nginx are configured correctly.
Now you just need to change the CA in the config to the combat value and run the script again, adding the parameter --force .
Without this parameter, the script will not re-generate the certificate, since The obsolescence period specified in the config has not yet come up.
 le@endor:~$ /opt/letsencrypt/letsencrypt.sh --cron --force # INFO: Using main config file /opt/letsencrypt/config Processing letest.lexore.net + Checking domain name(s) of existing cert... unchanged. + Checking expire date of existing cert... + Valid till Sep 24 12:13:00 2016 GMT (Longer than 80 days). Ignoring because renew was forced! + Signing domains... + Generating private key... + Generating signing request... + Requesting challenge for letest.lexore.net... + Responding to challenge for letest.lexore.net... + Challenge is valid! + Requesting certificate... + Checking certificate... + Done! + Creating fullchain.pem... + Done! 

After running the script and restarting nginx, the site will receive the correct certificate.
The certificate is ready, https works.
What does the right certificate look like


A few words about several domains.
One certificate can be used for several domains. For example, here’s what it would look like if you add subdomain.letest.lexore.net .
Running the script:
 $ /opt/letsencrypt/letsencrypt.sh --cron --force # INFO: Using main config file /opt/letsencrypt/config Processing letest.lexore.net with alternative names: subdomain.letest.lexore.net + Checking domain name(s) of existing cert... changed! + Domain name(s) are not matching! + Names in old certificate: letest.lexore.net + Configured names: letest.lexore.net subdomain.letest.lexore.net + Forcing renew. + Checking expire date of existing cert... + Valid till Sep 24 12:48:00 2016 GMT (Longer than 80 days). Ignoring because renew was forced! + Signing domains... + Generating private key... + Generating signing request... + Requesting challenge for letest.lexore.net... + Requesting challenge for subdomain.letest.lexore.net... + Responding to challenge for letest.lexore.net... + Challenge is valid! + Responding to challenge for subdomain.letest.lexore.net... + Challenge is valid! + Requesting certificate... + Checking certificate... + Done! + Creating fullchain.pem... + Done! 

Edit nginx config, restart, and now the new certificate is already working for two domains.
Screenshot of such a certificate in firefox


Domains do not have to be connected in any way; you can create one domain for domain.com and ftp.example.net.
Maximum you can specify 100 domains in one certificate.
For some, this may be enough to get by with one certificate for all sites on the server.
However, this certificate will have to be re-created for each new domain in the list, and you can rest against limits.

And now the best part is automation.
In order for the script itself to update all certificates from the domains.txt file and you forget about hand manipulations, you need to add one line to the cron of the user le:
 0 1 * * * /opt/letsencrypt/letsencrypt.sh --cron 

Thus, the algorithm for translating subsequent sites to https:


This is not the only way to automate, many letsencrypt clients can reduce all the work to the launch of a single script on the crown.
I liked this script for its simplicity; all the work is done by one bash script.
And also, for its additional features - besides simple automation, it supports out of the box “complex” automation, running its own scripts and redefining the parameters.
For example, I have already mentioned about the parameter HOOK in the config, which allows you to run your script.
Also out of the box there is a parameter CONFIG_D - a folder in which all .sh scripts will be run to redefine the parameters of the main config.
Plus, support for different "accounts" by specifying different ACCOUNTDIR - folders with private keys for signing requests.
I think this will allow the use of the script in large and complex infrastructures.

Source: https://habr.com/ru/post/304174/


All Articles