ACME
Every Mesh Node runs a built-in RFC 8555 ACME server. Your existing ACME clients request and renew certificates from the node; each request still passes local policy, the customer approval quorum, Sectigo Edge approval and the protected signer. Unlike a public ACME CA, the node's ACME service is workload-authenticated: every request must arrive over mutual TLS with a workload identity, and each ACME account is bound to that exact identity.
Requirements
- An enrolled, healthy Mesh Node (any platform).
- ACME clients that support External Account Binding (EAB) and can present a client certificate (your workload's X.509-SVID) on their HTTPS connection to the ACME server.
- Clients that trust the CA that issued the node's
local-api.crt. - For HTTP-01 validation, the node must be able to reach
http://<identifier>/.well-known/acme-challenge/<token>for each DNS name requested.
How it works
| Topic | Behavior |
|---|---|
| Directory URL | <local_api_url>/acme/directory, for example https://127.0.0.1:9443/acme/directory. In Kubernetes each pod has its own URL. |
| Authentication | Verified X.509-SVID on every request; the account stays bound to that SPIFFE ID. Rotating the SVID or the account key cannot rebind an account to a different identity. |
| Account creation | Requires EAB in production (externalAccountRequired: true), acceptance of the terms of service and one to five plain mailto: contacts. |
| EAB credential | Random 256-bit HS256 secret, valid 5 minutes to 23 hours, bound to one node ID and one exact workload SPIFFE ID, usable to create one account on that node. |
| Challenges | http-01, validated by the node. |
| Authorization | The requester must be inside allowed_spiffe_prefixes and each DNS name inside allowed_dns_suffixes; then normal policy (profile, algorithm, lifetime) applies. |
| Key rollover | Standard RFC 8555 keyChange with nested old/new-key signatures; the identity, contacts and EAB binding are unchanged. |
| Deactivation | Irreversible; cancels pending orders and authorizations, does not revoke issued certificates. |
| Renewal information | renewalInfo is advertised for clients that support it. |
Prepare the node
ACME is built in, so no adapter keys are needed. The production configuration must contain:
{
"acme_external_account_required": true,
"acme_external_account_credentials_file": "/etc/edgepki/acme-eab.json",
"allowed_spiffe_prefixes": ["spiffe://acme-corp.example/ns/prod/"],
"allowed_dns_suffixes": [".prod.acme-corp.example"]
}
The installers create acme-eab.json as an empty, private store ({"version":1,"credentials":[]}). An empty store is deliberate: the node can enroll and learn its node ID, but no ACME account can be created until you add credentials. The values above are examples.
Configure in the console
- Open ConsoleIntegrations and select Configure on the ACME card.
- Select Enable this integration and choose the Target Mesh Nodes that will serve ACME.
- Enter the Certificate / identity profile that ACME issuance should use. The Local adapter reference is fixed to
builtin/acme. - Select Save desired state. Each target node reports
healthyon its next poll.
ACME finalization requires an active assignment of the node and always uses the profile selected here. If you disable ACME or remove a node, that node stops finalizing orders immediately.
Create an External Account Binding credential
Create one credential per node/account pair, on a restricted administrator host, with the sectigo-edge CLI from the same release as the node. Run it as the user that owns the credential file; the command writes the store atomically with mode 0600 and prints the client secret once:
install -d -m 0700 ./edgepki-eab
sectigo-edge \
-acme-eab-file "$PWD/edgepki-eab/eab-credentials.json" \
-acme-eab-node-id node_7c1e4b2a-93d5-4f61-8a0e-2b6d9f3c5e17 \
-acme-eab-workload spiffe://acme-corp.example/ns/prod/sa/web \
-acme-eab-validity 15m \
acme-eab-create > ./edgepki-eab/client-credential.json
chmod 0600 ./edgepki-eab/client-credential.json
Then deliver the two files separately:
| File | Goes to | How |
|---|---|---|
client-credential.json (key_id and hmac_key_base64url) | The ACME client for that workload | Once, through your approved secret channel |
eab-credentials.json (the store) | The node's acme_external_account_credentials_file | Copy to /etc/edgepki/acme-eab.json (owner edgepki, mode 0600) on Linux, C:\ProgramData\Sectigo\Edge\acme-eab.json on Windows, or the edgepki-acme-eab Secret on Kubernetes |
On Kubernetes, replace the Secret from the file so the secret never appears in a command argument:
kubectl -n edgepki create secret generic edgepki-acme-eab \
--from-file=eab-credentials.json=./edgepki-eab/eab-credentials.json \
--dry-run=client -o yaml | kubectl apply -f -
secret/edgepki-acme-eab configured
The node re-reads the store for every new-account request, so no restart is needed. Existing accounts keep working after their credential expires; the next acme-eab-create run prunes expired entries. Never put HMAC values in Helm values, source control, tickets or command-line literals.
Redundant nodes and failover
ACME state is local to each node. Never put ACME clients behind a load balancer that spreads requests across nodes — nonces, orders and authorizations must return to the same node.
- Create a separate EAB credential and a separate ACME account for each node a client may use.
- Configure the client with a primary and a secondary directory, for example
https://mesh-edgepki-node-0.mesh-edgepki-node.edgepki.svc:9443/acme/directoryandhttps://mesh-edgepki-node-1.mesh-edgepki-node.edgepki.svc:9443/acme/directory. - Fail over to the secondary only when the primary is unreachable. A reachable ACME error (for example a policy denial) is final.
- Include each node's state in your backups; restoring it preserves accounts and EAB history. A rebuilt node needs new credentials.
A shared Kubernetes Secret can hold credentials for every replica — node-ID binding stops another pod from accepting them — but every pod can read every entry. For strict isolation, give each node its own release and Secret.
Rotation
ACME clients renew on their own schedule; the node does not deploy ACME certificates to services. To have Sectigo Edge itself stage, health-check and roll back certificates on a web server, use the NGINX or Apache adapters instead.
Verify
Check the directory with your workload identity:
curl --cacert local-api-ca.pem --cert workload-svid.pem --key workload-svid-key.pem \
https://127.0.0.1:9443/acme/directory
{"keyChange":"https://127.0.0.1:9443/acme/key-change","meta":{"externalAccountRequired":true,"termsOfService":"https://sharppki.com/legal","website":"https://sharppki.com"},"newAccount":"https://127.0.0.1:9443/acme/new-account","newNonce":"https://127.0.0.1:9443/acme/new-nonce","newOrder":"https://127.0.0.1:9443/acme/new-order","renewalInfo":"https://127.0.0.1:9443/acme/renewal-info","revokeCert":"https://127.0.0.1:9443/acme/revoke-cert"}
Then confirm the ACME card is Healthy and that the integration appears with "kind": "acme" and "health": "healthy" in sectigo-edge status. Issued certificates appear under ConsoleCertificates.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
ACME problem externalAccountRequired | The client sent no EAB | Configure the client's EAB key ID and HMAC |
| Generic authorization failure on new-account | EAB credential unknown, expired, already used, made for another node or another workload, malformed or signed incorrectly | Create a new credential for the exact node ID and workload SPIFFE ID |
userActionRequired | Terms of service not accepted | Enable terms agreement in the client |
TLS handshake fails / unauthorized | No client certificate, or it does not chain to the node's workload trust bundle | Present the workload SVID |
HTTP-01 validation failed | The node could not fetch the challenge from http://<name>/.well-known/acme-challenge/ | Make the name resolve and serve the token on port 80 from the node's point of view |
Card Degraded with adapter_reference_invalid | A reference other than builtin/acme was saved | Re-save the integration |
| Order finalization refused after a change | ACME disabled or the node unassigned | Re-enable and reassign |
Credential-store read or validation failures fail closed. See also Troubleshooting.