open-mpic / draft-mpic

Other
2 stars 0 forks source link

Endpoint naming #8

Open sciros opened 3 weeks ago

sciros commented 3 weeks ago

This question has come up as part of open-mpic as well but we may as well discuss it all here to keep things synced up.

What should the endpoints be for the various validations/checks that we'll want performed? Due to the nature of the industry terms, there's no obviously elegant approach.

I figured an easy way to start the conversation would be to throw some ideas out there to beat up on. Gemini and ChatGPT were happy to oblige, though each gave me quite different results for my question about this. Here was my prompt:

Let's talk about PKI and certificate issuance. I want to brainstorm endpoint naming for an API that would do multi-perspective issuance corroboration for various validation checks. There are several kinds of "verifications" or "validations" that get run as part of issuing a signed certificate. Correct me where I'm wrong, because I want to be very technically pedantic about this, but I think of the checks as being, roughly, DCV (domain control validation) and then CAA (certificate authority authorization) checking. With DCV the word "validation" is already in the name, and with CAA it's not, so I think many people in the PKI space do refer to CAA record validation as a "CAA check," and I've seen the occasional article where, perhaps for the sake of parallel terminology, people will talk of a "DCV check." But if I wanted to have an API with endpoints that carry out these various verifications, what is a good way to organize and name them? Perhaps DCV should be broken out into the various validation methods? And then CAA is just alongside those as "yet another record type" to check the presence of? Or maybe it's "/dcv-check" and "/caa-check" and then specifying in the request body what kind of DCV validation type to carry out (HTTP, etc.)? Please ruminate on this for me.

Gemini gave me the following options:

Option 1: Hierarchical Structure; clear separation of concerns, detailed endpoint names. /validations/dcv /validations/dcv/http /validations/dcv/dns /validations/dcv/email ... /validations/caa /validations/ocsp (or other validation types)

Option 2: Flat Structure with Query Parameters; simplicity, flexibility. /validate (or /verify) Query parameters: type: dcv, caa, ocsp, etc. method: http, dns, email, etc. (for DCV)

Option 3: Combined Approach; balance between hierarchy and simplicity. /dcv /dcv/http /dcv/dns /dcv/email /caa /ocsp (or other validation types) /validate for generic validation requests with query parameters

Personally I wasn't fond of any of these, although if I had to choose between the above I'd go with some version of option 1 or option 3.

ChatGPT 4o gave me a very different answer, seemingly being led by my prompt a bit more, so I found myself biased towards it.

  1. Endpoint Structure Overview DCV (Domain Control Validation): Since DCV involves different methods (HTTP, DNS, email, etc.), it makes sense to either have separate endpoints for each method or a single endpoint with the method specified in the request. CAA (Certificate Authority Authorization): CAA is more straightforward, typically involving a single check to see if the domain has specific CAA records that allow the issuance of a certificate by a CA.
  2. Naming Conventions Consistency is key. If you choose to use the term "check" for CAA, it might be beneficial to apply it uniformly, even to DCV, despite "validation" already being in the name.
  3. Potential Endpoint Structures

    1. Option A: Separate Endpoints for Each DCV Method /dcv/http-check: Validates domain control via HTTP. /dcv/dns-check: Validates domain control via DNS. /dcv/email-check: Validates domain control via email. /caa-check: Checks the CAA records for the domain. Pros: Clear separation of concerns, Easy to manage and extend if new DCV methods are added. Cons: Potentially more endpoints to maintain.

    2. Option B: Unified DCV Endpoint with Method in Request /dcv-check: Single endpoint for DCV validation. The method (HTTP, DNS, email) is specified in the request body or as a query parameter. /caa-check: Same as in Option A. Pros: Fewer endpoints, which might simplify API documentation, Easier to handle common validation logic. Cons: Slightly more complex request handling. Less explicit endpoint naming.

I'm personally partial to ChatGPT's Option B (and using a request body parameter for the method), as that's the direction I've proposed taking the open-mpic reference implementation for now and it's very close to its current state (v1.0.1 has /validation and /caa-check paths). But I don't know if it's the best direction to take and figure this is one of the first things we should sort out anyway for a standard API.

bwesterb commented 3 weeks ago

Let me add another dimension to this discussion.

Inspired by certificate transparency, I proposed using /mpic/v1 (or for the draft version now /mpic/draft00.)

In certificate transparency, all actions have a separate endpoint (add-chain, add-pre-chain, get-entries, get-sth, etc). This makes it easier to cache or rate-limit certain endpoints.

I don't see a similar advantage of putting the method in the URL in case of MPIC.

sciros commented 3 weeks ago

Thanks Bas, that's a good point. I think specifying /mpic/{version} (or draft) as the base URL is good. I also agree that putting the version in the URL is sensible if you want to enable/encourage running multiple versions of the API. Especially if you are envisioning a CT log kind of situation -- many CAs posting to a few MPIC enablers -- this makes a lot of sense. If the open source, roll-your-own-mpic implementation manages to find adoption, it may be a different dynamic, but that's far from a sure thing and this kind of flexibility in the API is valuable.

That still leaves the question of the method endpoints. I agree that dcv-html, dcv-dns, etc. being separate endpoints is not particularly useful the way it can be for CT. So it's more about what makes for a more elegant and usable spec. I personally do think that there should be some request path organization of what to corroborate, so it's not just "do mpic" and then the requested corroboration(s) is buried in the request body. To me that would feel clunky and unconventional.

How do we feel about, for example: /mpic/v1/caa-check (and specifying CAA specific parameters in the body) /mpic/v1/dcv-check (and specifying the DCV method and other relevant parameters in the body) /mpic/v1/dcv-with-caa-check

Or is there a preference instead for paths like like /mpic/v1/caa and /mpic/v1/dcv/{method}?

bwesterb commented 3 weeks ago

I don't have any preference between dcv-with-caa-check and dcv/caa or caa.

One could move more (mandatory) arguments into the path. For instance: /mpic/v1/caa/{domain}/{prefix}. As every endpoint could also do CAA, we'll end up with a common endpoint internally anyway. To me it feels cleanest to also have just one endpoint in the API. It's only a slight preference.

birgelee commented 2 weeks ago

The main advantage of moving all mandatory parameters to the path I can think of is that the endpoint could potentially accept an empty POST body. However, I do not particularly feel this is needed and I actually think it might be detrimental. Often I feel this type of rich path is useful for resource that have GET requests associated with them since GET requests cannot have bodies, so clean encoding in the path is essential (e.g., /blog/post/{id} can accept PUT to update the post or GET to view the post). I do not think the API should use GET, so there can be a body.

The downside with mandatory parameters in the path is that it makes the API rely on two separate encoding schemes: URL and JSON. URLs have limitations on acceptable characters and non-standard characters need to be escaped. JSON also has non-acceptable characters in strings which are escaped. I would argue 1. API client implementations are more likely to get the JSON escaping correct than the URL escaping. Most languages have a JSON library which takes in native objects and just makes them compliant JSON. URL escaping is also supported in most languages, but there is a risk that implementers will just use standard string replacement to build the URLs which could cause escapement errors. 2. For most methods there is some potentially rather large mandatory data which I think is sloppy to have in a URL. Almost every method needs an expected challenge. Some Sectigo challenges I have completed use a 3-line long file. Thus, a URL with all required parts is going to read something like: /mpic/v1/dcv/http/{domain}/{path}/{challenge} where path and challenge will both have tons of escape characters as path needs to escape all the "/" and challenge needs to escape all the "\n". Additionally, the key-value format of JSON improves readability because it is not dependent on parameter order, but instead each what each parameter is is clearly identified. IMO the readability of the above proposed URL inferior to viewing a post body that reads: { domain: "...", path: "...", challenge: "..." }

Finally, I will mention that CloudFlare's original MPIC API implementation I first tested had an issue with the base64-URL escaping system used in ACME that caused an error in about 1 in 10 requests. This has since been fixed, but I do think it reinforces the point that URL escaping can be non-trivial.

sciros commented 2 weeks ago

I definitely advocate not putting anything in the URL in this case as far as request-specific data, for all the reasons @birgelee lays out. Splitting parameters between the URL and body is unintuitive for clients and clunky at best for implementers. Also since this is an HTTP POST that is sending information to the server, it's expected that there is an accompanying request body.

Thinking about the earlier discussion points more, I also don't really like the idea of putting DCV methods (http, etc.) into the URL, because of the way the URL drives logic. DCV vs CAA is quite different logic as far how the check is carried out, and requires different configuration parameters. DCV HTTP vs DCV DNS etc. is on the other hand a bit deeper in the logic and so what will happen is the validation method will get pulled into a configuration parameter anyway, to be tossed over to the remote perspectives who then figure out what to do.

I'm almost thinking Bas's idea of one endpoint for the whole thing ("do MPIC") and then the desired check (dcv, caa, dcv-with-caa) being a parameter might work fairly well. There's one practical issue with it, which is that I like to avoid clients needing to know magic strings whenever possible when specifying params, and this enumeration (dcv, caa, dcv-with-caa) is definitely a bit of that. Explicit URL endpoints spelled out in the OpenAPI spec make this more straightforward. The rest of the parameters are more either numbers, URLs, etc. except for DCV validation method (http, dns, etc.) which have a bit of the same issue. The other thing to worry about is, then, that we still need a parameter for the type of check we're doing, and I suppose "check_type" would work fine but that'd be something else to align on. I suppose in the end it's "six of one, half-dozen of the other."

So I'd either go with mpic/v1/mpic (can't just do mpic/v1/) or mpic/v1/dcv, mpic/dcv/caa and such. Coin-toss as to which; the implementing code can be nearly identical (switch on request path vs switch on check type).

birgelee commented 2 weeks ago

I might put in a slight preference for just one /mpic endpoint over /dcv and /caa because I think splitting the endpoints may cause confusion given that the /dcv endpoint will also do CAA by default.

I was thinking and there is one advantage of using something like /dcv/http but it mostly exists in the OpenAPI context. In an Open API spec we can specify different JSON schemas for different endpoints allowing the distinct schema for /dcv/http and /dcv/dns to be strictly associated with the different endpoints. Thus, if I were to pass a request to /dcv/http with an validation details object formatted for /dcv/dns, we could detect this protocol violation at the spec level (there are several tools that generate request validators based on Open API specs). Given the current system (where a magic string is passed to the method parameter which determines the schema of the validation-details object), the Open API spec can only specify the validation details must be OneOf the required schemas, but cannot associate the proper schema with the magic string passed. Clearly this is an Open API specific consideration and the human-readable format of an RFC is not bound to these types of limitations.

bwesterb commented 2 weeks ago

Do we expect many clients to use the OpenAPI spec as a starting point? If so, I would not mind making the API more OpenAPI friendly. I think it's best to think about that at the end with the full API.

birgelee commented 2 weeks ago

I don't think the open API point I brought up should be a primary concern at this stage. Lets proceed without validation methods in the url for now.

sciros commented 2 weeks ago

the /dcv endpoint will also do CAA by default

@birgelee I believe the current API spec expects an explicit "dcv-with-caa" request for this at the moment. If /dcv were to do CAA by default then it would need a "no_caa" flag exposed. Given that, let's say we go with /mpic as the sole endpoint, I think we need to enumerate what validation/checking behavior can be specified.

Option A Top-level request parameter check_type with values dcv, caa, and dcv-with-caa (current behavior options)

Option B Top-level request parameter check_type with value dcv, caa, and dcv-no-caa (different default behavior for dcv)

I don't care which option we pick, personally. They just flip the meanings of the two non-caa check types so from a client's standpoint it's identical work and so whatever is more intuitive/expected is what we ought to go with.

The name "check_type" is a placeholder -- we can go with a different name. In the implementation model I've for now gone with Sectigo's "checker/check" lexicon.

birgelee commented 2 weeks ago

I think it makes sense to have the /mpic endpoint. @bwesterb Didn't you mention you like the CAA check with DCV by default idea?

bwesterb commented 2 weeks ago

In the current text, there is a method field in the request object which is either http, dns, or caa. The CAA check is also preformed for the http and dns methods unless the optional caa-check field is set to false. This seems very similar to @sciros' proposal.

TheEnbyperor commented 1 week ago

If one API endpoint is used I think it should accept a list of checks to be performed together, rather than having to make multiple requests for each validation type. This also allows new semantics to slot in neatly if there's some new CAA like thing that CAs want to check along with HTTP/DNS and CAA.

I support explicit protocol versioning. I think there should be a metadata document at /mpic/directory (or maybe even /.well-known/mpic given this is IETF work?) that lists what versions the server supports, and configuration parameters (not that I can currently see a need for those). This would allow a client to perform version negotiation, simplifying moving between MPIC providers.

bwesterb commented 1 week ago

I think there should be a metadata document [...]

If required we can punt that to when we actually have a second version. A missing directory (or whatever the mechanism would be) indicates v1.

(Context: I am trying to keep the initial draft as simple as possible, but no simpler.)

romanf commented 1 week ago

Not sure if this question belongs here: Has it been decided that one endpoint will do the corroboration from multiple perspectives? So if somebody wants to run an MPIC instance that party would have to have 2-6 remotes? Or is it the intention that one endpoint will be one perspective?

bwesterb commented 1 week ago

Not sure if this question belongs here: Has it been decided that one endpoint will do the corroboration from multiple perspectives? So if somebody wants to run an MPIC instance that party would have to have 2-6 remotes? Or is it the intention that one endpoint will be one perspective?

The single endpoint will do corroboration from multiple perspectives.

romanf commented 1 week ago

Wouldn't it be more flexible to use a model like with Certificate Transparency? Where a number of organizations could each run one perspective and CAs select the required number of perspectives?

bwesterb commented 1 week ago

Let's discuss that in #15