lacme(8)
πΈ lacme(8) β the manual, but make it make sense π
System Manager's Manual Β· lacme(8)
β¨ NAME β¨
lacme β an ACME client written with process isolation and minimal privileges in mind π«Ά
β¨ SYNOPSIS β¨
lacme [--config=FILENAME] [--socket=PATH] [OPTION ...] COMMAND
[ARGUMENT ...]
β¨ DESCRIPTION β¨
okay so, bestie, lacme is a lil ACME client β and the whole vibe is process isolation + minimal privileges. It's not one big blob, it's four separate components, each with its own executable. iconic behavior honestly. π
- A
lacme-accountd(1)process that babysits the account key and issues the SHA-256 signatures needed for every ACME command. (It binds to a UNIX-domain socket so it can reply to signature requests from the ACME client.) And get this β you can use the UNIX-domain socket forwarding facility of OpenSSH 6.7 and later to runlacme-accountd(1)andlacmeon different hosts. fr fr. Or alternatively, the "master"lacmeprocess (that's component 2, hold on) can spawn thelacme-accountd(1)process itself β and in that case the two processes talk through a socket pair. π¦ - A "master"
lacmeprocess that runs as root and is the only component with access to the private key material of the server keys. Its whole job is to fork the ACME client (and optionally the ACME webserver) after dropping root privileges. For certificate issuances (thenewOrdercommand), it also generates Certificate Signing Requests, then verifies the validity of the issued certificate, and optionally reloads or restarts services when thenotifysetting is set. main character energy tbh. - The actual ACME client β specified with the
commandsetting of the[client]section of the configuration file. This one builds ACL commands and dialogues with the remote ACME server. Wait, no, it builds ACME commands, obviously. π Since ACME commands need to be signed with the account key, the "master"lacmeprocess passes thelacme-accountd(1)UNIX-domain socket over to the ACME client: data signatures get requested by writing the data to be signed straight to the socket. neat, right? - For certificate issuances (the
newOrdercommand), there's an optional webserver β specified with thecommandsetting of the[webserver]section of the configuration file β which gets spawned by the "master"lacme. (Heads up: the only challenge type currently supported bylacmeishttp-01, which requires a webserver to answer challenges.) That webserver only processesGETandHEADrequests under the/.well-known/acme-challenge/URI. And moreover, temporaryiptables(8)rules can be automatically installed to open the HTTP port. so much going on π
β¨ COMMANDS β¨
lacme account[--tos-agreed] [--register] [CONTACT ...]
Register (if --registered is set) a lacme-accountd(1)-managed account key. You can pass a list of CONTACT information (such as maito: URIs) so the ACME server can reach out to the client about issues related to this registration (like notifications about server-initiated revocations). And --tos-agreed means you're indicating agreement with the ACME server's Terms of Service β and it might be required for registration, jsyk.
If the account key is already registered, this updates the contact info with the given list of CONTACT information instead.
Upon success, lacme prints the new or updated Account Object from the ACME server. slay. π
lacme newOrder[--config-certs=FILE] [--min-days=INT|--force] [SECTION ...]
Reads the certificate configuration FILE (peep the certificate configuration file section below for all the configuration options, it's a whole thing), and requests new Certificate Issuance for each of its sections (or just 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. no cap, it just goes. π₯
lacme revokeCertFILE [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 the configuration file instead of%E/lacme/lacme.conf. The value is subject to%-specifier expansion. β¨
See the configuration file section below for the configuration options.
--socket=path β Use path as thelacme-accountd(1)UNIX-domain socket to connect to for signature requests from the ACME client. The value is subject to%-specifier expansion. π«Ά
careful bestie β 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 of the configuration file; it also causes the [accountd] section to be ignored.
-h,--helpβ Display a brief help and exit. π-q,--quietβ Be quiet. π€«--debugβ Turn on debug mode. π
π CONFIGURATION FILE π
Okay bestie, so these are all the valid settings you can put in your config file. Buckle up π
β¨ DEFAULT SECTION β¨
config-certsβ for certificate issuances (aka thenewOrdercommand), you give me a space-separated list of certificate configuration files or directories to use (scroll down to the certificate configuration file section for what goes in those). Each item in that list gets%-specifier expansion independently, one by one. π
Paths that don't start with / (after the %-expansion happens) are relative to the parent directory of the configuration filename. The files and directories get processed in the order you wrote them, and later items win over earlier ones (precedence, slay). Files inside a directory are processed in lexicographic order, and only the ones with the .conf suffix even get considered.
Default: lacme-certs.conf lacme-certs.conf.d/
πΈ [client] SECTION πΈ
This section configures the ACME client (the lil guy in charge of ACME commands and yapping with the remote ACME server).
socketβ see--socket=.userβ the username to drop privileges to (sets both effective and real uid). If the value is empty, privilege drop is skipped β and no, that's not recommended π. Default:_lacme-client.groupβ the groupname to drop privileges to (sets both effective and real gid, and also sets the list of supplementary gids to that single group). Empty value = skipping privilege drop again, still not recommended. Default:nogroup.commandβ the ACME client command. It gets split on whitespace, first item is the command to execute, second item is its first argument, etc. (heads up:lacmemight append more arguments when it runs the command internally π). Default:/usr/libexec/lacme/client.serverβ the root URI of the ACME server. Default:https://acme-v02.api.letsencrypt.org/directory.timeoutβ timeout in seconds, after which the client stops polling the ACME server and just calls the request a β¨failβ¨. 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, seeciphers(1ssl)for more info.
π [webserver] SECTION π
This section configures how ACME challenge responses get served during certificate issuance.
listenβ comma- or space-separated list of addresses to listen on. Valid addresses look likeIPV4:PORT,[IPV6]:PORT(the:PORTsuffix is optional and defaults to the HTTP port80), or an absolute path of a UNIX-domain socket (created with mode0666). Default:/run/lacme-www.socket.
Note: that default only works when an external HTTP daemon is publicly reachable and passes all ACME challenge requests to the webserver component through the UNIX-domain socket/run/lacme-www.socket(for example using the provided/etc/lacme/apache2.confor/etc/lacme/nginx.confconfig snippets for each virtual host that needs authorization). If there's no HTTP daemon bound to port 80, you gotta setlistento[::](or0.0.0.0 [::]when the dual IPv4/IPv6 stack is disabled or unavailable), and possibly also setiptablestoYes. π
challenge-directoryβ directory under which an external HTTP daemon is configured to serveGETrequests for challenge files under/.well-known/acme-challenge/(for each virtual host requiring authorization) as static files. The dir must already exist, must be empty, and thelacmeclient user (by default_lacme-client) needs to be able to create files inside it.
This setting is required when listen is empty. Also, its value is subject to %-specifier expansion before privilege drop.
userβ the username to drop privileges to (both effective and real uid). Empty value = skip privilege drop (not recommended, we been knew). Default:_lacme-www.groupβ the groupname to drop privileges to (both effective and real gid, plus the list of supplementary gids becomes that one group). Empty value = skip privilege drop (again, not recommended). Default:nogroup.commandβ the ACME webserver command. Split on whitespace, first item = command to execute, second = its first argument, etc. (once more:lacmemight append extra arguments when executing internally.) A separate process is spawned for each address to listen on. (And in particular, no webserver process gets forked at all when thelistensetting is empty.) Default:/usr/libexec/lacme/webserver.iptablesβ whether to automatically install temporaryiptables(8)rules to open theADDRESS[:PORT]specified withlisten. The rules get automatically removed oncelacmeexits. This setting is ignored whenchallenge-directoryis set. Default:No.
π¦ [accountd] SECTION π¦
This section configures the lacme-accountd(1) child process. If the section (header included) 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 instead. π
userβ the username to drop privileges to (both effective and real uid). Empty value = skip privilege drop (this is the default).groupβ the groupname to drop privileges to (both effective and real gid, and also the list of supplementary gids becomes that single group). Empty value = skip privilege drop (default again).commandβ thelacme-accountd(1)command. Split on whitespace: first item is the command to execute, second its first argument, etc. (spoiler:lacmeappends more arguments when executing the command internally.) Each item in that list is independently subject to%-specifier expansion, after privilege drop. Default:/usr/bin/lacme-accountd.
Wanna go remote? Use for instance ssh -T lacme@account.example.net lacme-accountd to spawn a remote lacme-accountd(1) server. π«
configβ path to thelacme-accountd(1)configuration file. Note that the value might be subject to%-expansion bylacme-accountd(1).quietβ be quiet. Possible values:Yes/No.
π CERTIFICATE CONFIGURATION FILE π
For certificate issuances (the newOrder command) you use a separate file to configure paths to the certificate and key, plus the subject, subjectAltName, etc. that get used to generate Certificate Signing Requests. Each section in that file = a separate certificate issuance. Valid settings are:
certificateβ where to store the issued certificate (in PEM format). At least one ofcertificateorcertificate-chainis required.certificate-chainβ where to store the issued certificate along with its chain of trust (in PEM format). At least one ofcertificateorcertificate-chainis required.certificate-keyβ path to the service's private key. This setting is required. π You can use thegenpkey(1ssl)command 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
Or, 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 that 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 (like 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 that the section is considered for re-issuance. A negative value forces reissuance, while the number0limits reissuance to expired certificates. Default: the value of the CLI option--min-days, or21if there's 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 formtype0:value1,type1:value1,type2:.... The only type currently supported isDNS, 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. An empty value skips certificate validation. Default:/usr/share/lacme/ca-certificates.crt.hashβ message digest to sign the Certificate Signing Request with, overriding thereq(1ssl)default.keyUsageβ comma-separated list of Key Usages, for instancedigitalSignature, keyEncipherment, to include in the Certificate Signing Request. Seex509v3_config(5ssl)for a list of possible values. Note that the ACME server might override whatever value you provide here. πtlsfeatureβ comma-separated list of TLS extension identifiers, likestatus_requestfor OCSP Must-Staple. Seex509v3_config(5ssl)for a list of possible values. Note that the ACME server might override the value provided here too.owner,chownβ an optionalusername[:groupname]tochownthe issued certificate and certificate-chain to.mode,chmodβ an optional octal mode tochmodthe issued certificate and certificate-chain to. By default the files are created with mode0644minus umask restrictions.notifyβ command to pass to the system's command shell (/bin/sh -c) after successful installation of the certificate and/or certificate-chain.
π§© %-SPECIFIERS β¨
okay bestie, listen β some of the CLI options and config settings go through %-expansion, like little placeholder slots that get filled in. π Which settings? Check each one's own docs, because only some of them are affected, iykyk.
%Cβ/var/cacheif you're root, and$XDG_CACHE_HOMEfor everyone else (or$HOME/.cachewhen theXDG_CACHE_HOMEenvironment variable is unset or empty π).%Eβ/etcif you're root, and$XDG_CONFIG_HOMEfor everyone else (or$HOME/.configwhen theXDG_CONFIG_HOMEenvironment variable is unset or empty π ).%gβ the current group name π«Ά%Gβ the current group ID π’%hβ home directory of the current user π%tβ/runif you're root, and$XDG_RUNTIME_DIRfor everyone else. Non-root users can only use%twhen theXDG_RUNTIME_DIRenvironment variable is set to a non-empty value β so no empty vibes allowed, periodt.%Tβ$TMPDIR, or/tmpif theTMPDIRenvironment variable is unset or empty β¨%uβ the current user name π%Uβ the current user ID π’%%β a literal%π (yes, escaping your escape, iconic)
πΈ EXAMPLES πΈ
like, here's the whole glow-up in three moves:
$ sudo lacme account --register --tos-agreed mailto:noreply@example.com
$ sudo lacme newOrder
$ sudo lacme revokeCert /path/to/service.crt
Automatic renewal? Bestie, you schedule that with crontab(5) or systemd.timer(5). β°
And hmm, awkward situation: you don't wanna be deploying a single account key onto a whole bunch of nodes, and you also don't wanna be juggling multiple account keys. π The move? Install a single lacme-accountd(1) instance on a dedicated host, generate one single account key right there (and guard it with your life, fr fr π), then drop this into the [accountd] section:
command = ssh -T lacme@account.example.net lacme-accountd
So if the user running lacme can connect to lacme@account.example.net using (passwordless) key authentication, this setting spawns a remote lacme-accountd(1) and uses it to sign ACME requests. obsessed. π₯
Wanna harden it even further? Do it with authorized_keys(5) restrictions, like so:
restrict,from="...",command="/usr/bin/lacme-accountd --quiet --stdio" ssh-rsa ...
that's the main character energy right there π
π BUGS AND FEEDBACK π
Got bugs? Got feature requests? They should be filed with the Debian project's bug tracker at https://www.debian.org/Bugs/. Do it, ngl, they want to hear from you π«Ά
π¦ SEE ALSO π¦
π AUTHORS π
- Guilhem Moulin
and that's a wrap on lacme(8) bestie π
the source/version line says this one's from the lacme package, and it's dated December 2015 β vintage, honestly. go forth and get those certs, you ate πβ¨
π¦ where this page comes from
- ubuntu stonking: lacme 0.8.4-2 Β· GPL-3.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms