On Fri, Sep 10, 2021 at 04:19:41PM +0100, Joshua Van Leeuwen wrote:
> Hi all,
> 
> I am a developer for the cert-manager <https://cert-manager.io> project
> which is an operator for issuing
> certificates in Kubernetes.
> 
> I am reaching out as I have a question regarding perhaps some ambiguity in
> the
> ACME RFC.
> 
> cert-manager implements an ACME client for requesting certificates from ACME
> servers. As part of the ACME flow when requesting a certificate, the ACME
> Challenge controller worker is responsible for self-checking whether a
> Challenge
> is valid, accepting that Challenge to the server, and finally waiting for
> Authorization.
> 
> Due to the nature of the operator model in Kubernetes, before this flow
> takes
> place, the controller fetches the current state of the ACME Challenge from
> the
> server. This uses an empty body ("") POST-as-GET request to the Challenge
> endpoint in order to recover state which might have been lost.
> 
> cert-manager has been successfully used against ACME servers for the past 4
> years, including namely Let's Encrypt. Recent implementations of ACME
> servers
> have had issues with this call whereby they interpret it as an Accept, or
> otherwise reject the call and effectively invalidate the Order.
> 
> Though this behaviour can be mitigated by calling the authorization
> endpoint and
> pruning the Challenge that the controller is concerned with, my question is
> whether or not querying the Challenge endpoint for its status is valid
> according
> to the ACME RFC?

I have implemented an ACME client, and it never queries challenge
endpoints, only uses them to trigger validations (it even discards the
validation trigger responses; I do not know what LE sends back for
these).

- On valid authorizations, it never pays any attention to challenges.
  Valid is valid.
- On pending challenges it grabs all challenges it understands (since
  unknown challenges might be something else than type/nonce model
  seen in 3 challenge types in the main ACME RFC) and figures out what
  it can do later. When it acknowledges a challenge, it uses URL pulled
  in this step.
- On failed authorizations, it indiscriminatedly (it pays no attention
  if type matches or not) digs whatever error records exist, plus
  whatever extended data Let's Encrypt includes.


And from the spec, I get the feeling that querying challenge objects
is ... underspecified. As well as being a footgun.


> > To check on the status of an authorization, the client sends a POST-
> > as-GET request to the authorization URL, and the server responds with
> > the current authorization object. In responding to poll requests
> > while the validation is still in progress, the server MUST return a
> > 200 (OK) response and MAY include a Retry-After header field to
> > suggest a polling interval to the client.
> 
> However we are not necessarily concerned with the _authorization_, only a
> particular child Challenge. Is querying the Challenge endpoint to discover
> state ever intended as a supported call in the RFC?

The client I wrote pays as little attention to challenges as possible,
it pays attention to authorizations instead.

In pre-RFC ACME (LE "ACMEv1") days, clients matching challenge types on
accepted authorizations was a not uncommon footgun. Caused a number of
spurious failures.


-Ilari

_______________________________________________
Acme mailing list
[email protected]
https://www.ietf.org/mailman/listinfo/acme

Reply via email to