Note: This is yet work in progress. While signing a CSR will basically work, using the client is not yet very convenient, as it still lacks documentation and all input can only be provided by the config.py file for now.
The aim of this project is to provide a client that does not need root permissions like the original let's encrypt client, does not need a whole bunch of external dependencies, and is well structured in an object oriented matter, so it can be understood and modified easily.
The client itself is coded in python, so if you do not want a client depending on python, just use it as a reference to build your own.
For now, the client depends on tree packages:
- python-jws
- pycurl
- pycrypto
There is one further (optional) dependency, if you like to use internal creation of certificates instead of command output:
- pyopenssl
If pyopenssl is installed, the --cmd switch is optional for userkey and serverkey modules.
pycurl and pycrypto need to be installed on the executing system via: pip install pycurl pip install pycropto
There is no need to install python-jws as yalec uses a modified version of it provided as a part of this repository.
The pycrypto module is needed to load and parse RSA keys. The ACME protocol requires the client to perform fancy stuff with the RSA keys used like signing JSON and splitting keys of into their modulo and exponent. This tasks are performed using the pycrypto module. It is also a dependency for the python-jws module.
pycurl is used to carry out the requests via HTTP. While all things might also be done using urllib2, I tend to use pycurl as it has a lot more options to perform more complicated tasks. If you do not like the idea to use pycurl, feel free to provide a pull request providing an additional HttpProvider using something else.
The ACME protocol defines some basic processes that need to be done in order to receive a new certificate. Some of the steps only need to be done before you are able to receive your first certificate. Other need to be done before you can renew an already issued certificate.
Let's Encrypt restricts the number of certificates that can be requested for a specific domain by a specific user per month. So before starting your production setup, use the staging-environment provided by Let's Encrypt to test it. For this, you should use https://acme-staging.api.letsencrypt.org/directory as base address. This is also the default, if you leave out the --base definition in the commands below.
First of all: this tool should not be run as root. Please execute it as a user with the least possible privileges.
To be able to perform the authorization procedure (authz), yalec needs write-permissions on a directory that can be reached for all domains that should be contained within the certificate on the directory http:///.well-known/acme-challenge. It is sufficient to set explicit permissions that allow the creation and deletion of files on that directory for the user executing yalec.
Before you can receive a certificate, you need to register a user. A registration basically consists of a user-key and some contact-information. During the registration you also accept the terms of service. This is only needed once before requesting your first certificate.
If you have pyopenssl installed, you can create a new user-key using the following command:
python2 yalec.py userkey --keyout=certs/user.key
Note: You need to keep the key-file written private, as this is your private key.
After creating the key, you can register it by calling the following command with appropriate parameters:
python2 yalec.py register --userkey=certs/user.key --mail="me@example.com" --base="https://acme-v01.api.letsencrypt.org"
So, we need to create a new user-key and then register it via yalec. If you do not want to use pyopenssl module, yalec allows you to create some command output that can be used to create a new user-key via commandline:
python2 yalec.py userkey --keyout=certs/user.key --cmd
This will output you something like this:
# create key with the following commands:
openssl genrsa -out certs/user.key 4096 ; chmod 600 certs/user.key
If you execute the openssl-command, it will create a new key file within the certs directory that contains your user-key.
Note: You need to keep the key-file written private, as this is your private key.
Now you can register that user by calling:
python2 yalec.py register --userkey=certs/user.key --mail="me@example.com" --base="https://acme-v01.api.letsencrypt.org"
Note: If you have the guts, you can pipe this directly into bash. If you try this, please check first, if command outputs sane commands.
Like creating user-keys you can use yalec to provide a basic command that allows creating a CSR for your domain or domains. This implies to create a new private key for the server as well.
If you have pyopenssl installed, just call something like
python2 yalec.py serverkey --keyout=certs/server.key --csrout=certs/server.csr --domain=example.com --domain=www.example.com --domain=mail.example.com
This will create a new server-key and a new signing-request that allows you to receive a new certificate.
Note: You need to keep the key-file written private, as this is your private key. If you key gets compromised, create a new one instantly as your encryption is insecure from that point of time. If you already have requested a certificate for the key, revoke it.
Likewise the user creation command, yalec allows you to output a command that can be executed in order to create a new CSR using openssl via commandline:
python2 yalec.py serverkey --keyout=certs/server.key --csrout=certs/server.csr --domain=example.com --domain=www.example.com --domain=mail.example.com --cmd
This will output something like this:
# create key with the following commands:
openssl genrsa -out certs/server.key 4096 ; chmod 600 certs/server.key
# create csr with the following commands:
TMPFILE=$(mktemp); tee $TMPFILE <<EOF
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
[req_distinguished_name]
[v3_req]
subjectAltName = @alt_names
[alt_names]
DNS.1=example.com
DNS.2=www.example.com
DNS.3=mail.example.com
EOF
openssl req -new -key "certs/server.key" -out "certs/server.csr" -subj "/CN=example.com/" -config $TMPFILE
rm $TMPFILE
Note: You need to keep the key-file written private, as this is your private key. If you key gets compromised, create a new one instantly as your encryption is insecure from that point of time. If you already have requested a certificate for the key, revoke it.
If you execute the bunch of commands outputed by yalec, you should have a new server.key file and a server.csr file that allows creating a proper csr.
You can always reuse the CSR created for certificate renewal but it might be wise to create a new private key and a new CSR from time to time.
Note: If you have the guts, you can pipe this directly into bash. If you try this, please check first, if command outputs sane commands.
As you have registered your user and created a CSR you should be able to request your certificate now.
python2 yalec.py sign --userkey=certs/user.key --certout=certs/server.crt --csr=certs/server.csr --domain=example.com --domain=www.example.com --domain=mail.example.com webdir=/tmp/acme --base="https://acme-v01.api.letsencrypt.org"
You can just reuse this command everytime you want to renew your certificate. This will be like every 2 Month (or 30 days before the certificate validity ends).
During this request, you have to name all domains of the CSR again and tell the script, where it finds your webroot by the webdir option.
The user acutally executing the command needs access to the webdir (or at least to the subfolder .well-known/acme-challenge and needs proper permissions to add files there.
For each domain named, this folder must be accessible via http:///.well-known/acme-challenge.
So what the command does is: For each domain in the list of domains, it requests a challenge from the ACME server. The ACME server tells yalec a name of a file to be placed at http://domain/.well-known/acme-challenge/. After the file has been placed there, yalec tells the server to retrieve the file which then allows the creation of certificates of the domain for the given user.
To configure your webserver use the server-key created as private key and the server-certiticate as certificate file (server.key and server.crt in the example above).
You also need to provide a full certificate chain. For some servers, the chain must be placed into the server-certificate file. If this is the case, you can just do it by downloading the issuing certificate from Let's Encrypt and attach it to your certificate file:
(cat server.crt ; curl "https://letsencrypt.org/certs/letsencryptauthorityx1.pem") > server.chain.crt
To revoke a certificate, you need the user-key and the certificate to be revoked. Just use the revoke module. For example:
python2 yalec.py revoke --userkey=certs/user.key --cert=certs/server.crt
yalec is licensed under LGPL v2.1. See LICENSE file for more information.