% lacme(8)
% [Guilhem Moulin](mailto:guilhem@fripost.org)
% December 2015

Name
====

lacme - [ACME] client written with process isolation and minimal
privileges in mind

Synopsis
========

`lacme` [`--config=FILENAME`] [`--socket=PATH`] [*OPTION* …] *COMMAND* [*ARGUMENT* …]

Description
===========

`lacme` is a small [ACME] client written with process isolation and
minimal privileges in mind.  It is divided into four components, each
with its own executable:

 1. A [`lacme-accountd`(1)] process to manage the account key and issue
    SHA-256 signatures needed for each [ACME] command.  (This process
    binds to a UNIX-domain socket to reply to signature requests from
    the [ACME] client.)
    One can use the UNIX-domain socket forwarding facility of OpenSSH
    6.7 and later to run [`lacme-accountd`(1)] and `lacme` on different
    hosts.  Alternatively, the [`lacme-accountd`(1)] process can be
    spawned by the “master” `lacme` process below; in that case, the
    two processes communicate through a socket pair.

 2. A “master” `lacme` process, which runs as root and is the only
    component with access to the private key material of the server
    keys.  It is used to fork the [ACME] client (and optionally the
    [ACME] webserver) after dropping root privileges.
    For certificate issuances (`newOrder` command), it also generates
    Certificate Signing Requests, then verifies the validity of the
    issued certificate, and optionally reloads or restarts services when
    the *notify* setting is set.

 3. An actual [ACME] client (specified with the *command* setting of the
    [`[client]` section](#client-section) of the configuration file),
    which builds [ACME] commands and dialogues with the remote [ACME]
    server.
    Since [ACME] commands need to be signed with the account key, the
    “master” `lacme` process passes the [`lacme-accountd`(1)]
    UNIX-domain socket to the [ACME] client: data signatures are
    requested by writing the data to be signed to the socket.

 4. For certificate issuances (`newOrder` command), an optional
    webserver (specified with the *command* setting of the [`[webserver]`
    section](#webserver-section) of the configuration file), which is
    spawned by the “master” `lacme`.  (The only challenge type currently
    supported by `lacme` is `http-01`, which requires a webserver to
    answer challenges.)  That webserver only processes `GET` and `HEAD`
    requests under the `/.well-known/acme-challenge/` URI.
    Moreover temporary [`iptables`(8)] rules can be automatically
    installed to open the HTTP port.

Commands
========

`lacme account` [`--tos-agreed`] [`--register`] [*CONTACT* …]

:   Register (if `--registered` is set) a [`lacme-accountd`(1)]-managed
    account key.  A list of *CONTACT* information (such as `maito:`
    URIs) can be specified in order for the [ACME] server to contact the
    client for issues related to this registration (such as
    notifications about server-initiated revocations).  `--tos-agreed`
    indicates agreement with the [ACME] server's Terms of Service (and
    might be required for registration).

    If the account key is already registered, update the contact info
    with the given list of *CONTACT* information.

    Upon success, `lacme` prints the new or updated Account Object from
    the [ACME] server.

`lacme newOrder` [`--config-certs=`*FILE*] [`--min-days=`*INT*|`--force`] [*SECTION* …]

:   Read the certificate configuration *FILE* (see the **[certificate
    configuration file](#certificate-configuration-file)** section below
    for the configuration options), and request new Certificate Issuance
    for each of its sections (or the given list of *SECTION*s).
    Command alias: `new-order`.

    The flag `--force` is an alias for `--min-days=-1`, which forces
    renewal regardless of the expiration date of existing certificates.

`lacme` `revokeCert` *FILE* [*FILE* …]

:   Request that the given certificate(s) *FILE*(s) be revoked.  For
    this command, [`lacme-accountd`(1)] can be pointed to either the
    account key or the certificate key.
    Command alias: `revoke-cert`.

Generic settings
================

`--config=`*filename*

:   Use *filename* as configuration file instead of
    `%E/lacme/lacme.conf`.  The value is subject to [%-specifier
    expansion](#percent-specifiers).

    See the **[configuration file](#configuration-file)** section below
    for the configuration options.

`--socket=`*path*

:   Use *path* as the [`lacme-accountd`(1)] UNIX-domain socket to
    connect to for signature requests from the [ACME] client.  The value
    is subject to [%-specifier expansion](#percent-specifiers).
    `lacme` aborts if *path* exists or if its parent directory is
    writable by other users.
    Default: `%t/S.lacme`.

    This command-line option overrides the *socket* setting of the
    [`[client]` section](#client-section) of the configuration file; it
    also causes the [`[accountd]` section](#accountd-section) to be
    ignored.

`-h`, `--help`

:   Display a brief help and exit.

`-q`, `--quiet`

:   Be quiet.

`--debug`

:   Turn on debug mode.

Configuration file
==================

Valid settings are:

Default section
---------------

*config-certs*

:   For certificate issuances (`newOrder` command), specify the
    space-separated list of certificate configuration files or
    directories to use (see the **[certificate configuration
    file](#certificate-configuration-file)** section below for the
    configuration options).  Each item in that list is independently
    subject to [%-specifier expansion](#percent-specifiers).

    Paths not starting with `/` (after %-expansion) are relative to the
    parent directory of the **[configuration filename](#configuration-file)**.
    The list of files and directories is processed in the specified
    order, with the later items taking precedence.  Files in a directory
    are processed in lexicographic order, only considering the ones with
    suffix `.conf`.

    Default: `lacme-certs.conf lacme-certs.conf.d/`.

`[client]` section
------------------

This section is used for configuring the [ACME] client (which takes care
of [ACME] commands and dialogues with the remote [ACME] server).

*socket*

:   See `--socket=`.

*user*

:   The username to drop privileges to (setting both effective and real
    uid).  Skip privilege drop if the value is empty (not recommended).
    Default: `@@lacme_client_user@@`.

*group*

:   The groupname to drop privileges to (setting both effective and real
    gid, and also setting the list of supplementary gids to that single
    group).  Skip privilege drop if the value is empty (not
    recommended).
    Default: `@@lacme_client_group@@`.

*command*

:   The [ACME] client command.  It is split on whitespace, with the
    first item being the command to execute, the second its first
    argument etc.  (Note that `lacme` might append more arguments when
    executing the command internally.)
    Default: `@@libexecdir@@/lacme/client`.

*server*

:   Root URI of the [ACME] server.
    Default: `@@acmeapi_server@@`.

*timeout*

:   Timeout in seconds after which the client stops polling the [ACME]
    server and considers the request failed.
    Default: `30`.

*SSL_verify*

:   Whether to verify the server certificate chain.
    Default: `Yes`.

*SSL_version*

:   Specify the version of the SSL protocol used to transmit data.

*SSL_cipher_list*

:   Specify the cipher list for the connection, see [`ciphers`(1ssl)]
    for more information.

`[webserver]` section
---------------------

This section is used to configure how [ACME] challenge responses are
served during certificate issuance.

*listen*

:   Comma- or space-separated list of addresses to listen on.  Valid
    addresses are of the form `IPV4:PORT`, `[IPV6]:PORT` (where the
    `:PORT` suffix is optional and defaults to the HTTP port 80), or an
    absolute path of a UNIX-domain socket (created with mode `0666`).
    Default: `@@runstatedir@@/lacme-www.socket`.

    **Note**: The default value is only suitable when an external HTTP
    daemon is publicly reachable and passes all ACME challenge requests
    to the webserver component through the UNIX-domain socket
    `@@runstatedir@@/lacme-www.socket` (for instance using the provided
    `@@sysconfdir@@/lacme/apache2.conf` or `@@sysconfdir@@/lacme/nginx.conf` configuration
    snippets for each virtual host requiring authorization).  If there
    is no HTTP daemon bound to port 80 one needs to set *listen* to
    `[::]` (or `0.0.0.0 [::]` when dual IPv4/IPv6 stack is disabled or
    unavailable), and possibly also set *iptables* to `Yes`.

*challenge-directory*

:   Directory under which an external HTTP daemon is configured to serve `GET`
    requests for challenge files under `/.well-known/acme-challenge/` (for
    each virtual host requiring authorization) as static files.
    The directory _must_ exist beforehand, _must_ be empty, and the
    lacme client user (by default `@@lacme_client_user@@`) needs to be
    able to create files under it.

    This setting is required when *listen* is empty.  Moreover its value
    is subject to [%-specifier expansion](#percent-specifiers) _before_
    privilege drop.

*user*

:   The username to drop privileges to (setting both effective and real
    uid).  Skip privilege drop if the value is empty (not recommended).
    Default: `@@lacme_www_user@@`.

*group*

:   The groupname to drop privileges to (setting both effective and real
    gid, and also setting the list of supplementary gids to that single
    group).  Skip privilege drop if the value is empty (not
    recommended).
    Default: `@@lacme_www_group@@`.

*command*

:   The [ACME] webserver command.  It is split on whitespace, with the
    first item being the command to execute, the second its first
    argument etc.  (Note that `lacme` might append more arguments when
    executing the command internally.)
    A separate process is spawned for each address to *listen* on.  (In
    particular no webserver process is forked when the *listen* setting
    is empty.)
    Default: `@@libexecdir@@/lacme/webserver`.

*iptables*

:   Whether to automatically install temporary [`iptables`(8)] rules to
    open the `ADDRESS[:PORT]` specified with *listen*.  The rules are
    automatically removed once `lacme` exits.
    This setting is ignored when *challenge-directory* is set.
    Default: `No`.

`[accountd]` section
---------------------

This section is used for configuring the [`lacme-accountd`(1)] child
process.  If the section (including its header) is absent or commented
out, or if the CLI option `--socket` is specified, then `lacme` connects
to an existing [`lacme-accountd`(1)] process via the specified
UNIX-domain socket.

*user*

:   The username to drop privileges to (setting both effective and real
    uid).  Skip privilege drop if the value is empty (the default).

*group*

:   The groupname to drop privileges to (setting both effective and real
    gid, and also setting the list of supplementary gids to that single
    group).  Skip privilege drop if the value is empty (the default).

*command*

:   The [`lacme-accountd`(1)] command.  It is split on whitespace, with
    the first item being the command to execute, the second its first
    argument etc.  (Note that `lacme` appends more arguments when
    executing the command internally.)
    Each item in that list is independently subject to [%-specifier
    expansion](#percent-specifiers) _after_ privilege drop.
    Default: `@@bindir@@/lacme-accountd`.

    Use for instance `` `ssh -T lacme@account.example.net
    lacme-accountd` `` in order to spawn a remote [`lacme-accountd`(1)]
    server.

*config*

:   Path to the [`lacme-accountd`(1)] configuration file.  Note that the
    value might be subject to %-expansion by [`lacme-accountd`(1)].

*quiet*

:   Be quiet. Possible values: `Yes`/`No`.

Certificate configuration file
==============================

For certificate issuances (`newOrder` command), a separate file is used
to configure paths to the certificate and key, as well as the subject,
subjectAltName, etc. to generate Certificate Signing Requests.
Each section denotes a separate certificate issuance.
Valid settings are:

*certificate*

:   Where to store the issued certificate (in PEM format).
    At least one of *certificate* or *certificate-chain* is required.

*certificate-chain*

:   Where to store the issued certificate along with its chain of trust
    (in PEM format).
    At least one of *certificate* or *certificate-chain* is required.

*certificate-key*

:   Path to the service's private key.  This setting is required.  The
    [`genpkey`(1ssl)] command can be used to generate a new service RSA
    key:

        $ install -vm0600 /dev/null /path/to/service.rsa.key
        $ openssl genpkey -algorithm RSA -out /path/to/service.rsa.key

    Alternatively, for an ECDSA key using the NIST P-256 curve:

        $ install -vm0600 /dev/null /path/to/service.ecdsa.key
        $ openssl genpkey -algorithm EC -out /path/to/service.ecdsa.key \
			-pkeyopt ec_paramgen_curve:P-256 \
			-pkeyopt ec_param_enc:named_curve

    `lacme` supports any key algorithm than the underlying libssl
    (OpenSSL) version is able to manipulate, but the [ACME] server might
    reject CSRs associated with private keys of deprecated and/or
    “exotic” algorithms.

    For a dual cert setup (for instance RSA+ECDSA), duplicate the
    certificate section and use a distinct *certificate-key* resp.
    *certificate* (or *certificate-chain*) value for each key algorithm.

*min-days*

:   For an existing certificate, the minimum number of days before its
    expiration date the section is considered for re-issuance.
    A negative value forces reissuance, while the number `0` limits
    reissuance to expired certificates.
    Default: the value of the CLI option `--min-days`, or `21` if there
    is no such option.

*subject*

:   Subject field of the Certificate Signing Request, in the form
    `/type0=value0/type1=value1/type2=…`.  This setting is required.

*subjectAltName*

:   Comma-separated list of Subject Alternative Names, in the form
    `type0:value1,type1:value1,type2:…`
    The only `type` currently supported is `DNS`, to specify an
    alternative domain name.

*CAfile*

:   Path to the bundle of trusted issuer certificates.  This is used for
    validating each certificate after issuance or renewal.  Specifying
    an empty value skips certificate validation.
    Default: `@@datadir@@/lacme/ca-certificates.crt`.

*hash*

:   Message digest to sign the Certificate Signing Request with,
    overriding the [`req`(1ssl)] default.

*keyUsage*

:   Comma-separated list of Key Usages, for instance `digitalSignature,
    keyEncipherment`, to include in the Certificate Signing Request.
    See [`x509v3_config`(5ssl)] for a list of possible values.  Note
    that the ACME server might override the value provided here.

*tlsfeature*

:   Comma-separated list of [TLS extension][TLS Feature extension]
    identifiers, such as `status_request` for OCSP Must-Staple.
    See [`x509v3_config`(5ssl)] for a list of possible values.  Note
    that the ACME server might override the value provided here.

*owner*, *chown*

:   An optional `username[:groupname]` to chown the issued *certificate*
    and *certificate-chain* to.

*mode*, *chmod*

:   An optional octal mode to chmod the issued *certificate* and
    *certificate-chain* to.  By default the files are created with mode
    0644 minus umask restrictions.

*notify*

:   Command to pass the the system's command shell (`` `/bin/sh -c` ``)
    after successful installation of the *certificate* and/or
    *certificate-chain*.

%-specifiers  {#percent-specifiers}
============

Some CLI options and configuration settings are subject to %-expansion
for the following specifiers.  Check the documentation of each setting
to see which ones are affected.

----  ------------------------------------------------------------------
`%C`  `@@localstatedir@@/cache` for the root user, and `$XDG_CACHE_HOME`
      for other users (or `$HOME/.cache` if the `XDG_CACHE_HOME`
      environment variable is unset or empty).

`%E`  `@@sysconfdir@@` for the root user, and `$XDG_CONFIG_HOME` for
      other users (or `$HOME/.config` if the `XDG_CONFIG_HOME`
      environment variable is unset or empty).

`%g`  Current group name.

`%G`  Current group ID.

`%h`  Home directory of the current user.

`%t`  `@@runstatedir@@` for the root user, and `$XDG_RUNTIME_DIR` for
      other users.  Non-root users may only use `%t` when the
      `XDG_RUNTIME_DIR` environment variable is set to a non-empty
      value.

`%T`  `$TMPDIR`, or `/tmp` if the `TMPDIR` environment variable is unset
      or empty.

`%u`  Current user name.

`%U`  Current user ID.

`%%`  A literal `%`.
----  ------------------------------------------------------------------

Examples
========

    $ sudo lacme account --register --tos-agreed mailto:noreply@example.com
    $ sudo lacme newOrder
    $ sudo lacme revokeCert /path/to/service.crt

Automatic renewal can be scheduled via [`crontab`(5)] or
[`systemd.timer`(5)].  In order to avoid deploying a single account key
onto multiple nodes and/or dealing with multiple account keys, one can
install a single [`lacme-accountd`(1)] instance on a dedicated host,
generate a single account key there (and keep it well), and set the
following in the [`[accountd]` section](#accountd-section):

    command = ssh -T lacme@account.example.net lacme-accountd

If the user running `lacme` can connect to `lacme@account.example.net`
using (passwordless) key authentication, this setting will spawn a
remote [`lacme-accountd`(1)] and use it to sign [ACME] requests.
Further hardening can be achieved by means of [`authorized_keys`(5)]
restrictions:

    restrict,from="…",command="/usr/bin/lacme-accountd --quiet --stdio" ssh-rsa …

See also
========

[`lacme-accountd`(1)]

[ACME]: https://tools.ietf.org/html/rfc8555
[TLS Feature extension]: https://tools.ietf.org/html/rfc7633
[`lacme-accountd`(1)]: lacme-accountd.1.html
[`iptables`(8)]: https://linux.die.net/man/8/iptables
[`ciphers`(1ssl)]: https://www.openssl.org/docs/manmaster/man1/openssl-ciphers.html
[`x509v3_config`(5ssl)]: https://www.openssl.org/docs/manmaster/man5/x509v3_config.html
[`genpkey`(1ssl)]: https://www.openssl.org/docs/manmaster/man1/openssl-genpkey.html
[`req`(1ssl)]: https://www.openssl.org/docs/manmaster/man1/openssl-req.html
[`crontab`(5)]: https://linux.die.net/man/5/crontab
[`systemd.timer`(5)]: https://www.freedesktop.org/software/systemd/man/systemd.timer.html
[`authorized_keys`(5)]: https://man.openbsd.org/sshd.8#AUTHORIZED_KEYS_FILE_FORMAT
