Simple ACME client for distributed certificate ordering
UNLICENSE License
acme-distributed is a (still somewhat incomplete) command line ACME client for distributed certificate ordering.
acme-distributed is work in progress. I use it as my primary ACME client for ordering and renewing all of my Let's Encrypt certificates so far. You are welcome to start using it as well. Please use the issue tracker to file bug reports.
The current version is v0.4.0
First things first:
The master branch in this repository most likely is unstable from time to time. Please download the latest release.
USAGE: ./acme-distributed.rb [options] <configuration>
-V, --version Display version number and exit
-e, --endpoint <name> The endpoint to use for the request
-c <cert1[, cert2[, ...]]>, Certificates to request
--certificates
-L, --log-level <level> Log level to use [DEBUG, INFO, WARN, ERROR]. Default is INFO.
-r, --remaining-lifetime <days> Only renew certificates which have a remaining validity less than <days> days
-n, --dry-run Dry-run mode, does not perform any actual change.
If you run acme-distributed behind a HTTP proxy server, be sure to set https_proxy
environment accordingly.
acme-distributed is a simple ACME client for special use cases. It does not implement all functionality that other ACME clients offer. If you are just looking for an ordinary ACME client, please look elsewhere.
The corner case implemented by this client is the separation of certificate ordering from fullfilling http-01 authorization requests. This can be useful in the following scenarios:
Please note that acme-distributed will not (nor will ever) deploy any certificates to your servers. This task is left to whatever configuration management or provisioning tools you might have in place.
bundler install
to install dependenciesBasically, what acme-distributed does is similar to other ACME clients when requesting certificates, except that it places the http-01 authorization challenges not on the local machine, but on each of the configured remote servers:
acme-distributed uses the Ruby ACME implementation acme-client by Charles Barbier and requires
Depending on the connector type(s) you use, there might be more dependencies and/or requirements (e.g. password-less SSH access to your remote web servers, etc).
Furthermore, you will need a Let's Encrypt account already setup, i.e. you need a valid, registered account key. acme-distributed does not offer registration functionality right now. This functionality is planned for the v1.0 release of this client.
acme-distributed uses configuration files in simple YAML format. The following configurables are available:
Define the available ACME endpoints for this configuration.
The url and private_key options are mandatory.
You can name the endpoints as you wish, the names production and staging below are just examples.
endpoints:
production:
url: https://acme-v02.api.letsencrypt.org/directory
private_key: /etc/acme-deploy/accounts/production/private-key.pem
email_addr: [email protected]
staging:
url: https://acme-staging-v02.api.letsencrypt.org/directory
private_key: /etc/acme-deploy/accounts/staging/private-key.pem
email_addr: [email protected]
You can define any number of certificates acme-distributed should handle. Each certificate needs a unique name name, which is given as the entry key.
The options subject, key and path are mandatory.
You can use the special variable {{endpoint}}
for the name of the endpoint in key and path values. If found, it will be replaced with the endpoint configuration name (e.g. staging or production if defined as in the example above).
certificates:
ssl.example.com:
subject: ssl.example.com
san:
- ssl2.example.com
- ssl3.example.com
key: /etc/acme-deploy/{{endpoint}}/keys/ssl.example.com.key
path: /etc/acme-deploy/{{endpoint}}/certs/ssl.example.com.pem
connector_group: frontend_web_servers
secure.example.com:
subject: secure.example.com
key: /etc/acme-deploy/{{endpoint}}/keys/secure.example.com.key
path: /etc/acme-deploy/{{endpoint}}/certs/secure.example.com.pem
connector_group: backend_web_servers
Connectors are used to connect to the remote systems that handle the authorization requests (e.g. your web servers). Connectors are grouped into connector groups which share a similar connector type. Each connector group must have at least one connector defined, but can (theoretically) contain infinite connectors. As a rule of thumb, if your web servers are behind a load balancer, each server should be configured as a connector in the same group.
Connectors are required to be unique within each group, but not across groups. You can use a connector with the same properties as an existing one in different groups.
Certificates can be configured to be handled by a specific connector group or by a configurable default connector group.
Connector groups know two properties:
type
: The type of the connector. See Connector types for more details.connectors
: An array that contains connector configuration as a hash, one element for each connector.Currently, the following connector types are supported.
Uses SSH to put an authorization challenge on the file system on a remote server, to be authorized via HTTP.
The following configuration options are mandatory and must be set:
hostname
specifies the DNS hostname (or IP address) of the server to connect to via SSHusername
specifies the remote username to use for authenticationssh_port
specifies the TCP port the SSH daemon on the server listens toacme_path
specifies the path on the remote server where authorization challenges are putPlease note that only the base name of the path sent by the ACME challenge will be used when creating the challenge files on the remote servers -- the /.well-known/acme
part will be cut off. So you either have an alias configured on your web servers pointing to acme_path or you include /.well-known/acme-challenge
in acme_path setting. In the example below, the web server is configured with an alias /.well-known/acme-challenge -> /var/www/acme
for simplicity.
Uses SSH to connect to a DNS server running unbound
(or a server with control access to your DNS server) and executes unbound-control
to add an authorization record to your DNS zone (i.e. unbound-control local_data _acme_challenge.fqdn.example.com 5 IN TXT <challenge>
).
The following configuration options are mandatory and must be set:
hostname
specifies the DNS hostname (or IP address) of the server to connect to via SSHusername
specifies the remote username to use for authenticationssh_port
specifies the TCP port the SSH daemon on the server listens tounbound_ctrl
specifies the path on the remote server to the unbound-control
binaryconnector_groups:
frontend_web_servers:
type: ssh_http_file
connectors:
- name: frontend_web_1
hostname: www1.example.com
username: acme
ssh_port: 22
acme_path: /var/www/acme
- name: frontend_web_2:
hostname: www2.example.com
username: acme
ssh_port: 22
acme_path: /var/www/acme
backend_web_servers:
type: ssh_dns_unbound
connectors:
- name: backend_web_1
hostname: www3.example.com
username: acme
ssh_port: 22
unbound_ctrl: /usr/sbin/unbound-control
acme-distributed is put in the Public Domain under the Unlicense terms.
Pull requests and patches are accepted as long as they are put in the public domain as well. For this purpose, please accompany your patches with the following statement:
I dedicate any and all copyright interest in this software to the
public domain. I make this dedication for the benefit of the public at
large and to the detriment of my heirs and successors. I intend this
dedication to be an overt act of relinquishment in perpetuity of all
present and future rights to this software under copyright law.