Skip to content

ACME

Issue certificates from a private CA with cert-manager, certbot or any ACME client, using External Account Binding.

Updated View as Markdown

Every active subordinate CA has a private ACME (RFC 8555) directory:

https://pki.ezghcloud.com/acme/<CA ID>/directory

ACME clients register with an ACME binding: an External Account Binding key ID (the binding’s eab_… slug) and HMAC key. A binding orders certificates with its owner’s access, so its owner needs certificates.certificateAuthorities.issue on the CA for as long as it’s used. Each order and finalization checks that again: if the owner loses the permission, leaves the organization, or the binding is deleted, its clients stop getting certificates.

There are no challenges. EZGH can’t reach your private names to validate them, so authorizations are valid from the start: control comes from the binding’s key, its allowed names, and the CA’s name constraints. Keep the HMAC key as secret as a private key.

Create a binding

You need certificates.acmeBindings.create and certificates.certificateAuthorities.issue on the CA. A binding has a profile (tlsServer, tlsClient or tlsServerClient), a longest validity (at most the CA’s longest certificate), and optionally the names it may order: exact DNS names or a leading *. label, within the CA’s name constraints.

ezgh private-ca acme-binding create corp-issuing --name cert-manager \
  --allowed-name '*.svc.corp.example' --max-validity-days 30

The directory URL, key ID and HMAC key are shown once. In the console, use Create ACME binding on the CA’s ACME tab; its last screen also has the cert-manager and certbot setups below.

Deleting a binding stops every ACME account registered with it.

cert-manager

apiVersion: v1
kind: Secret
metadata:
  name: corp-issuing-eab
  namespace: cert-manager
stringData:
  secret: <HMAC key>
---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: corp-issuing
spec:
  acme:
    server: https://pki.ezghcloud.com/acme/<CA ID>/directory
    privateKeySecretRef:
      name: corp-issuing-account
    externalAccountBinding:
      keyID: <key ID>
      keySecretRef:
        name: corp-issuing-eab
        key: secret

Certificates then name the issuer as usual (issuerRef: {kind: ClusterIssuer, name: corp-issuing}). Pods that verify them need the root certificate in their trust bundle.

certbot

certbot certonly --server https://pki.ezghcloud.com/acme/<CA ID>/directory \
  --eab-kid <key ID> --eab-hmac-key <HMAC key> \
  --manual --preferred-challenges dns --manual-auth-hook true \
  -d app.corp.example --agree-tos -m you@corp.example

The no-op --manual-auth-hook is never called, since there are no challenges; certbot renew works the same way.

Limits

Each binding may send 20 ACME requests per second, with bursts of 100. Account key rollover (keyChange) is supported; ACME Renewal Information isn’t.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close