ACME EAB Credentials Are Secrets, But They're Not Treated That Way
Corey Bonnell
The ACME protocol provides the ability to bind an ACME account with a pre-existing account registered with the CA using a secret HMAC key. However, the common way to feed that secret to popular ACME clients is to paste it straight onto the command line, where any user on the same machine can read it. Worse, several major CAs let you reuse the same EAB credential, so a single capture is enough to keep abusing it.
This article walks through why the EAB HMAC key is a secret, how the popular ACME clients (mis)handle it, why the command line is the wrong place for it, how CAs make the problem worse by allowing reuse, and what to do about it today.
What EAB is, and why the HMAC key is a secret
External Account Binding is defined in RFC 8555 in section 7.3.4.
A CA that wants to tie ACME accounts to existing accounts sets
externalAccountRequired in its ACME directory and refuses newAccount requests
that don’t carry an externalAccountBinding field.
To produce that field, the client needs two values that the CA provides through some channel outside of ACME:
- key identifier: an ASCII string that merely identifies the key (it’s not a secret on its own), and
- MAC key: the secret HMAC key.
The ACME client uses the MAC key to sign the ACME account key that it generated and supplies the result in the newAccount request. Anyone who holds the identifier and the MAC key can
register an ACME account against the existing CA account whose those credentials belong to.
That makes the HMAC key a bearer secret, no different than an API token or password.
How the major clients take it: on the command line
certbot exposes --eab-kid and --eab-hmac-key as command-line options. Google’s
Public CA quickstart
tells you to run:
certbot register \
--email "EMAIL_ADDRESS" \
--no-eff-email \
--server "SERVER" \
--eab-kid "EAB_KID" \
--eab-hmac-key "EAB_HMAC_KEY"Similarly, lego specifies the --eab flag together with --eab.kid and --eab.hmac.
A real invocation would look like:
lego --eab --eab.kid="..." --eab.hmac="..." ...acme.sh uses --eab-kid and --eab-hmac-key, as shown in its
Wiki documentation:
acme.sh --register-account --server zerossl \
--eab-kid xxxxxxxxxxxx \
--eab-hmac-key xxxxxxxxxA few of these tools do provide alternate means to supply EAB information, such as
certbot’s cli.ini configuration file or lego’s environment variables.
However, this functionality is buried at the bottom of documentation and mentioned in passing. Official client documentation,
how-tos, and CA quickstarts generally tell users to place the HMAC key on the command line.
Why the command line is the wrong place for a secret
On Linux, a process’s arguments are not private. By default, any user on the machine can run
ps aux and see the arguments for any process, even those running as root. If you have a
machine running Linux nearby, you can see this for yourself.
This behavior is well known and documented in the Linux kernel’s procfs documentation.
Section 4.1 of the linked documentation describes the hidepid option (which will be mentioned again below). It states that
if this option is enabled (it’s disabled by default), then “poorly written programs passing sensitive information via program
arguments are now protected against local eavesdroppers.” Yet, this bad practice is the most common way
to supply EAB secrets today.
On any shared host, running an ACME client with the EAB HMAC key on the command line briefly exposes that
secret to every other user on the box. A snooping user can capture it as easily as running a
while true; do ps aux; done loop. Additionally, the secret may be recorded in process audit logs or shell history
files.
Despite this potential for exposure, none of the ACME clients that allow EAB secrets to be specified on the command line mention the risks of doing so.
The multiplier: several CAs allow EAB reuse
If EAB credentials were used only one time and invalidated after use, then a leaked HMAC key wouldn’t be as big of a deal. However, it appears that several CAs allow subscribers to reuse EAB secrets.
For example, ZeroSSL explicitly allows and actually encourages reuse. Its EAB documentation states at the top in a warning box: “Since March 2022 all EAB credentials are reusable. One set of EAB credentials should be enough for most use cases.” Several other CAs also encourage or require EAB reuse, tying EAB keys to specific accounts, certificate profiles, or other configuration options.
Google Trust Services appears to take the more secure approach. Per Google’s Public CA quickstart, “after you have registered an ACME account by using an EAB secret, the EAB secret becomes invalid and you can’t reuse it. If you want to register multiple ACME accounts, you must request a unique EAB secret for each.” That is the correct model. The credential is single-use, so an eavesdropper who captures it after account registration gets nothing of value.
What should change
ACME clients should stop accepting EAB on the command line.
Registration is a one-time operation. There is no reason to allow for the HMAC key to be provided on the command line for convenience. Clients should make a file-based or environment variable-based path the default and the documented one, and deprecate the command-line options. At the very least, ACME client developers should document the dangers of supplying secret EAB information through command-line arguments.
CAs should stop reuse of EAB credentials.
This is already the practice employed by Google Trust Services. CAs that currently issue long-lived, reusable EAB secrets should consider following Google’s lead. Doing so minimizes or eliminates the impact of EAB secrets that are disclosed.
A workaround you can apply today
Until clients and CAs change, you can stop other local users from reading process
arguments by mounting /proc with hidepid.
Remount /proc immediately (takes effect at once):
sudo mount -o remount,rw,nosuid,nodev,noexec,relatime,hidepid=2 /procMake it persistent by editing /etc/fstab so it survives reboots:
proc /proc proc defaults,nosuid,nodev,noexec,relatime,hidepid=2 0 0The takeaway
Improving the handling of EAB secrets doesn’t need new protocol work. In fact, proper processing of EAB secrets is already there in some clients, but it’s hidden. Client developers should remove the command line flags to supply EAB information, or at the very least have documentation about the risks and encourage alternate methods. CAs should also create single-use credentials like Google Trust Services already does to minimize the impact of disclosure.
The EAB HMAC is a secret. It needs to be treated like one.