Commit b510d2a2 authored by Adrien Dorsaz's avatar Adrien Dorsaz

Update README.md for the acme-dns-tiny poject

parent 8fe116d3
# acme-tiny
# acme-dns-tiny
[![Build Status](https://travis-ci.org/diafygi/acme-tiny.svg)](https://travis-ci.org/diafygi/acme-tiny)
[![Coverage Status](https://coveralls.io/repos/diafygi/acme-tiny/badge.svg?branch=master&service=github)](https://coveralls.io/github/diafygi/acme-tiny?branch=master)
[![Build Status](#)](#)
[![Coverage Status](#)](#)
This is a tiny, auditable script that you can throw on your server to issue
and renew [Let's Encrypt](https://letsencrypt.org/) certificates. Since it has
to be run on your server and have access to your private Let's Encrypt account
key, I tried to make it as tiny as possible (currently less than 200 lines).
The only prerequisites are python and openssl.
and renew [Let's Encrypt](https://letsencrypt.org/) certificates with DNS
authentication.
**PLEASE READ THE SOURCE CODE! YOU MUST TRUST IT WITH YOUR PRIVATE KEYS!**
Since it has to have access to your private ACME account key and the
rights to update the DNS records of your DNS server, this code has been designed
to be as tiny as possible (currently less than 250 lines).
##Donate
The only prerequisites are python (especially the dnspython module) and openssl.
**PLEASE READ THE SOURCE CODE! YOU MUST TRUST IT WITH YOUR ACCOUNT PRIVATE KEYS!**
Note: this script is a fork of the [acme-tiny project](https://github.com/diafygi/acme-tiny)
which uses ACME HTTP verification to create signed certificates.
## Donate
If this script is useful to you, please donate to the EFF. I don't work there,
but they do fantastic work.
......@@ -44,11 +51,12 @@ Let's Encrypt client.
The private account key from the Let's Encrypt client is saved in the
[JWK](https://tools.ietf.org/html/rfc7517) format. `acme-tiny` is using the PEM
key format. To convert the key, you can use the tool
[conversion script](https://gist.github.com/JonLundy/f25c99ee0770e19dc595) by JonLundy:
[conversion script](https://gist.github.com/JonLundy/f25c99ee0770e19dc595)
by JonLundy:
```sh
# Download the script
wget -O - "https://gist.githubusercontent.com/JonLundy/f25c99ee0770e19dc595/raw/6035c1c8938fae85810de6aad1ecf6e2db663e26/conv.py" > conv.py
curl "https://gist.githubusercontent.com/JonLundy/f25c99ee0770e19dc595/raw/6035c1c8938fae85810de6aad1ecf6e2db663e26/conv.py" > conv.py
# Copy your private key to your working directory
cp /etc/letsencrypt/accounts/acme-v01.api.letsencrypt.org/directory/<id>/private_key.json private_key.json
......@@ -63,8 +71,9 @@ openssl rsa -in private_key.der -inform der > account.key
### Step 2: Create a certificate signing request (CSR) for your domains.
The ACME protocol (what Let's Encrypt uses) requires a CSR file to be submitted
to it, even for renewals. You can use the same CSR for multiple renewals. NOTE:
you can't use your account private key as your domain private key!
to it, even for renewals. You can use the same CSR for multiple renewals.
NOTE: you can't use your account private key as your domain private key!
```
#generate a domain private key (if you haven't already)
......@@ -73,139 +82,115 @@ openssl genrsa 4096 > domain.key
```
#for a single domain
openssl req -new -sha256 -key domain.key -subj "/CN=yoursite.com" > domain.csr
openssl req -new -sha256 -key domain.key -subj "/CN=example.org" > domain.csr
#for multiple domains (use this one if you want both www.yoursite.com and 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
#for multiple domains (use this one if you want both www.example.org and example.org)
openssl req -new -sha256 -key domain.key -subj "/" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=DNS:example.org,DNS:www.example.org")) > domain.csr
```
### Step 3: Make your website host challenge files
### Step 3: Make your DNS server allow dynamic updates
You must prove you own the domains you want a certificate for, so Let's Encrypt
requires you host some files on them. This script will generate and write those
files in the folder you specify, so all you need to do is make sure that this
folder is served under the ".well-known/acme-challenge/" url path. NOTE: Let's
Encrypt will perform a plain HTTP request to port 80 on your server, so you
must serve the challenge files via HTTP (a redirect to HTTPS is fine too).
requires you host some DNS resource records.
```
#make some challenge folder (modify to suit your needs)
mkdir -p /var/www/challenges/
```
This script will generate and write those DNS records to your DNS server by
use of DNS dynamic message updates.
```nginx
#example for nginx
server {
listen 80;
server_name yoursite.com www.yoursite.com;
So you have to configure your DNS server to allow dynamic DNS
updates and create a TSIG key which will give rights to perform updates.
location /.well-known/acme-challenge/ {
alias /var/www/challenges/;
try_files $uri =404;
}
The configuration of the script will need:
* the TSIG key name and value
* the algorithm used for TSIG key (MD5, SHA1, SHA224, SHA256, SHA384 or SHA512)
* the DNS zone to update
* the address and the port of the DNS server
...the rest of your config
}
```
The simplest way to configure the script is to copy the `example.ini` file
from this repository and update the values as needed.
**Be careful! Set permissions correctly on your configuration file, because
it will contain the key authorized to modify your DNS configuration !**
### Step 4: Get a signed certificate!
Now that you have setup your server and generated all the needed files, run this
script on your server with the permissions needed to write to the above folder
and read your private account key and CSR.
script on a computer containing your private account key, the CSR and the configuration.
```
#run the script on your server
python acme_tiny.py --account-key ./account.key --csr ./domain.csr --acme-dir /var/www/challenges/ > ./signed.crt
python acme_dns_tiny.py example.ini > ./chain.pem
```
### Step 5: Install the certificate
The signed https certificate that is output by this script can be used along
with your private key to run an https server. You need to include them in the
https settings in your web server's configuration. Here's an example on how to
configure an nginx server:
If every thing was ok, chain.crt contains your signed certificate followed by the
CA's certificate which signed yours.
```
#NOTE: For nginx, you need to append the Let's Encrypt intermediate cert to your cert
wget -O - https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem > intermediate.pem
cat signed.crt intermediate.pem > chained.pem
```
### Step 5: Install the certificate
```nginx
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
}
```
The certificate chain that is output by this script can be used along
with your private key to run any service on your server which need TSL encryption.
You need to include both in the TLS settings of your services.
### Step 6: Setup an auto-renew cronjob
Congrats! Your website is now using https! Unfortunately, Let's Encrypt
Congrats! Your server is now using TLS! Unfortunately, Let's Encrypt
certificates only last for 90 days, so you need to renew them often. No worries!
It's automated! Just make a bash script and add it to your crontab (see below
for example script).
Example of a `renew_cert.sh`:
Example of a skeleton for `renew_cert.sh` script:
```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
```
#!/bin/bash
# Configuration
# You should use another directory as /tmp could be destroyed regularly
WORKINGDIR="/tmp/acme-dns-tiny"
# Pre run script: configure a secure workspace using ACL POSIX
mkdir -p ${WORKINGDIR}
setfacl -m "default:other:--- , other:---" ${WORKINGDIR}
# You should also add code to create backup of older certificates
# You may need code to handle HPKP (key pining in HTTP) updates
# You may need to update DANE (key pining in DNS) too
# With HPKP and DANE, you should also consider your automatic key rollover
# which will need to update the CSR file and/or your DNS DANE records.
# Run the script
python /path/to/acme_dns_tiny.py example.ini > ${WORKINGDIR}/chain.pem || exit
# Post run script
# You should reload each service using TLS
```
#example line in your crontab (runs once per month)
0 0 1 * * /path/to/renew_cert.sh 2>> /var/log/acme_tiny.log
```
Then you'll need to configure a cron job to execute this script regularly (think
to set random minutes to avoid to DDOS the CA servers).
## Permissions
The biggest problem you'll likely come across while setting up and running this
script is permissions. You want to limit access to your account private key and
challenge web folder as much as possible. I'd recommend creating a user
specifically for handling this script, the account private key, and the
challenge folder. Then add the ability for that user to write to your installed
certificate file (e.g. `/path/to/chained.pem`) and reload your webserver. That
way, the cron script will do its thing, overwrite your old certificate, and
script is permissions. You want to limit access to your account private key, your
CSR and your configuration file. I'd recommend creating a user
specifically for handling this script, the account private key, the CSR and
the DNS key. Then add the ability for that user to write to your installed
certificate file (e.g. `/path/to/chain.pem`) and reload your services. That
way, the cron job will do its thing, overwrite your old certificate, and
reload your webserver without having permission to do anything else.
**BE SURE TO:**
* Backup your account private key (e.g. `account.key`)
* Don't allow this script to be able to read your domain private key!
* Don't allow this script to be run as root!
* Don't allow this script to be able to read your *domain* private key!
* Don't allow this script to be run as *root*!
* Understand and configure correctly your cron job to do all your needs !
(if you don't know bash, write it in your preferred language to manage your
server)
## Feedback/Contributing
This project has a very, very limited scope and codebase. I'm happy to receive
bug reports and pull requests, but please don't add any new features. This
script must stay under 200 lines of code to ensure it can be easily audited by
anyone who wants to run it.
This project has a very, very limited scope and codebase. The project is happy
to receive bug reports and pull requests, but please don't add any new features.
This script must stay under 250 lines of code to ensure it can be easily audited
by anyone who wants to run it.
If you want to add features for your own setup to make things easier for you,
please do! It's open source, so feel free to fork it and modify as necessary.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment