ACME Proxy Integration Guide
This guide is for hosts that can't (or shouldn't) reach the general internet, but still need automatically renewing SSL certificates — using standard certbot, not a custom script.
A note on acme.sh: this proxy is only validated against certbot right now. We hit an unresolved issue testing acme.sh against it (its DNS-manual-mode polling gives up well before this system's real, sometimes multi-minute issuance process finishes) and are still working through it — if certbot isn't an option for your host, reach out before committing to acme.sh.
If your host has normal outbound internet access and you'd rather call an API directly from your own automation, see the separate Certificate API - Integration Guide instead. That path doesn't yet support full ACME/EAB automated renewal; this one does, and is built specifically for hosts that can't run that kind of always-online script.
1. Prerequisites
a. Get an EAB credential
Open a ServiceNow ticket:
- Assignment Group: IT Authentication and Collaboration
- Request: ACME proxy access for certificate automation -- [give your team name]
We'll provision a credential for you and send back to values:
Keep the EAB HMAC key secret the same way you'd treat a password -- it's what proves that every future certificate request actually came from you.
| Value | What it's for |
|---|---|
| EAB Key ID | Identifies your credential to the proxy -- use as --eab-kid. This same value is also what you'll put in NetDB (see below). |
| EAB HMAC Key | The secret half of your credential -- used as --eab-hmac-key. |
Keep the EAB HMAC Key secret the same way you'd treat a password — it's what proves that every future certificate request actually came from you.
b. Set up a CERT_AUTH_ID custom field on each NetDB node you need certs for
For every hostname (and every SAN, if requesting a multi-domain certificate) you want to request a certificate for, someone with edit access on that NetDB node needs to:
- Log in to https://netdb.stanford.edu/.
- Search for the node or domain where you want certificate issuance to be automated (for example,
med4.stanford.edu). - Edit it.
- Add a Custom Field labeled
CERT_AUTH_IDwith the value set to your EAB Key ID from step 1a, exactly as given to you.
This is how the proxy authorizes your credential to request a certificate for that specific hostname — it checks your EAB Key ID against this custom field on the node before allowing the request through, on every single request, including every renewal — not just the first time. If it's missing or set to a different value, the request will be rejected with a message telling you exactly which node needs it and what value to set.
You do not need to provide a hostname list when requesting your credential — this NetDB step is the only place hostname authorization is configured, and it's fully self-service once your credential exists.
If a node already has a CERT_AUTH_ID value from another credential, don't overwrite it -- add yours to the same field, separated by a comma (e.g., existing-value,your-eab-key-id). Overwriting it would silently break the node of whoever's already using it.
2. Point your ACME client at the proxy
Unlike the REST API, there's no bearer token to fetch and no payload to build by hand -- certbot handles the entire protocol itself once pointed at the right server with your credential.
Using certbot:
certbot register \
--server https://acme-proxy-prod.iam.stanford.edu/directory \
--eab-kid <your-eab-key-id> \
--eab-hmac-key <your-eab-hmac-key> \
--agree-tos --email you@stanford.eduYou only do this once - certbot saves the registration locally and reuses it for every future request and renewal.
3. Request a certificate
Certbot needs one extra thing here that you won't see in typical ACME tutorials: the flags that tell it to use manual DNS-01 handling. That's not a limitation on your end — domain-control validation for this proxy happens on our side, against the real CERTInext CA, not via any DNS record you need to create. These flags just tell certbot not to look for (or wait on) one from you.
certbot certonly \
--server https://acme-proxy-prod.iam.stanford.edu/directory \
--eab-kid <your-eab-key-id> \
--eab-hmac-key <your-eab-hmac-key> \
--manual --preferred-challenges dns \
--manual-auth-hook "true" \
--manual-cleanup-hook "true" \
-d your-host.stanford.eduCertbot handles domain validation automatically as part of the protocol — you don't need to add any DNS records yourself.
A successful request writes the certificate straight to local disk — there's no separate download step or fulfillment email, unlike the REST API. Certbot saves it under /etc/letsencrypt/live/your-host.stanford.edu/.
4. Renewal
This is the actual point of using ACME instead of the REST API: renewal is genuinely automatic, with no script of your own to maintain.
Certbot installs its own periodic job (a cron entry, typically twice a day) the first time you use it. On each wake-up, it checks every certificate it's tracking and does nothing unless one is within its renewal window (roughly the last month of its validity) — most wake-ups are silent no-ops. You don't need to build or schedule anything yourself; just make sure whatever process manages cron/scheduled tasks on your host is actually running.
Every renewal re-runs the full authorization check described in step 1b — if your NetDB CERT_AUTH_ID field ever gets removed or changed, the next renewal attempt will fail even if past ones succeeded.
5. Common error messages
| Message contains | Meaning | Fix |
|---|---|---|
unknown EAB kid | The --eab-kid value isn't recognized | Double-check for typos, or confirm your credential was actually provisioned |
EAB signature mismatch | The --eab-hmac-key doesn't match | Double-check the secret value — this is case- and character-sensitive |
EAB kid ... is disabled | Your credential was revoked | Contact UIT Authentication and Collaboration |
no custom field includes | The NetDB node isn't linked to your credential yet | Add the CERT_AUTH_ID custom field per step 1b above |
order status is ... must be 'ready' | Your client tried to finalize before validation completed | Almost always transient — your ACME client will retry automatically; if it persists, contact UIT |
A note on what you'll see in that last error message: it lists the status of two NetDB fields, KEYCLOAK_ID and CERT_AUTH_ID — you can ignore any mention of KEYCLOAK_ID entirely. That field belongs to a separate, older system (the REST Certificate API) and has nothing to do with this ACME path. The only thing that matters for you is whether CERT_AUTH_ID shows your EAB Key ID.
Questions
Reach out via the UIT Authentication and Collaboration group or submit a Help ticket.
