Proposal: client authentication mode "none"

As of Caddy 2.9.1, the option client_auth mode accepts values “request”, “require”, “verify_if_given”, “require_and_verify”.

I propose adding a fifth value “none”, which would turn off client_auth entirely, so any specific details about CA pools etc. would be ignored by Caddy and no client certificate would be requested.

The reason is admin comfort. In my experience, setting up client_auth correctly involves a lot of trial and error, especially for people who are doing it for the first time.

It would be valuable to have an easy way to switch off client_auth entirely at once, without having to either remove the directive from Caddyfile, or having to comment it out line-by-line, which is prone to various errors, not least with regard to brackets.

And a value “none” (or possibly, “off”) would provide that way, you would simply instantly turn client_auth off without having to edit your client auth setup heavily. With mode “none”, all the CA set up would be just ignored, but would be ready to be turned on again by changing “mode” to something different from “none”.

Providing configuration disabling knob within an enabling block doesn’t make sense. Not to mention providing none is a foot-gun of exposure/vuln waiting to happen. Let the admin go through the friction of learning how to set it up than providing an escape hatch. It is not valuable. It is vulnerable.

I don’t see it that way, but of course we can disagree.

In Apache mod_ssl, you can turn client auth off by specifying SSLVerifyClient to none, is that considered problematic by the Apache community?

Having a “none” value would also be useful for tools that modify the Caddyfile automatically. Not every edit to a Caddyfile is done manually.

I do not speak for the Apache community, but historical mistakes should not be repeated just because they were done in history. There was a vulnerability a while ago in many JWT implementation due to the "alg": "none" is considered valid, and the consensus amongst security researchers is that "alg": "none" is a mistake and a footgun.

If automation tool is used to generate the Caddyfile, I expect them to be smart enough to remove a whole block on a flag. The same if-condition that will toggle the mode value can act to include/exclude the whole block.

It is a difference between a relatively simple sed command, with which most admins are used to working, and writing a full-blown parser of the Caddyfile format, which isn’t parsable by any standard tools that I know.

I actually did just that (wrote my own Caddyfile parser in PHP 8 a few weeks ago), and there was nothing particularly smart about that. Only a multi-hour slog with a result of uncertain robustness, as there are almost no test files to test the result against (I fished out some Caddyfiles around GitHub, but AFAIK there is no official collection of Caddyfile examples for testing of third-party parsers).

Your advice would be a lot more actionable if Caddyfile format parsers were widely available in languages such as PHP or Python.

Users aiming to automate their Caddy configuration are encouraged to use the JSON format rather than write parsers for the Caddyfile format. JSON itself is ubiquitous and supported in almost all languages (plus jq). Is fact, JSON is the native configuration language of Caddy, and the Caddyfile format is just an adapter to JSON. By aiming for JSON, you can define the config structure as a collection of data classes to be manipulated as objects in your language of choice then unmarshalled into JSON to be posted to Caddy.

Wow, I am ignorant. I always thought it was the other way round: Caddyfile primary, JSON experimental and unguaranteed. Thank you.

I would like to have one more question: it is not clear to me where to put the JSON config. Currently, my Caddyfile resides at

/etc/caddy/Caddyfile

(it is FrankenPHP, in fact). Is there a standard location and a standard name for a JSON config?

1 Like

There’s no standard. Even the location at /etc/caddy is just a Linux/Unix convention. The JSON file can be named anything but you have to tell Caddy where it is and its name by using the --config flag.