Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tls: modularize trusted CA providers #5784

Merged
merged 18 commits into from
Jan 25, 2024
Merged

tls: modularize trusted CA providers #5784

merged 18 commits into from
Jan 25, 2024

Conversation

mohammed90
Copy link
Member

@mohammed90 mohammed90 commented Aug 25, 2023

The current implementation of client authentication requires the CA to be either known in DER format or available on disk as PEM files. This prevents the advanced usage of client authentication by standing on the shoulders of the PKI app or to fetch the certs from shared Caddy storage. The current implementation makes it hard to share the same trusted client CAs across a cluster of Caddy servers without having to produce the root certs first then plugging them. This is a long way of saying, the trusted root CA is very rigid and not extensible.

This implementation allows for the trust CA to be any Caddy module that satisfies an interface. It also provides 4 basic providers:

  • File, to maintain backwards compatibility
  • Root certs from the PKI app
  • Intermediate certs from the PKI app
  • Storage

TODO:

  • Caddyfile
  • Tests
  • Docs

@mohammed90 mohammed90 added feature ⚙️ New feature or request needs docs ✍️ Requires documentation changes needs tests 💯 Requires automated tests do not merge ⛔ Not ready yet! labels Aug 25, 2023
@mohammed90 mohammed90 added this to the 2.9.0 milestone Aug 25, 2023
@mohammed90 mohammed90 requested a review from mholt August 25, 2023 22:02
Copy link
Member

@mholt mholt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh this is actually awesome -- thank you for contributing this!

It's pretty close to what I'd do.

  • Exported types and their fields will need godocs.
  • It's a slight bummer we can't combine the PKI*CAPool types. (Unless we can? I wonder what that would look like. It's just a matter of what the admin wants to sign the certs with, right?)

I have little in the way of criticism of this change. Nice work 😃

@mohammed90
Copy link
Member Author

* Exported types and their fields will need godocs.

* It's a _slight_ bummer we can't combine the PKI*CAPool types. (Unless we can? I wonder what that would look like. It's just a matter of what the admin wants to sign the certs with, right?)

I'll come back to it when I'm in a better head-space.

One more thing, I did consider Lazy for some of them, which delays the load-and-parse until the pool is requested, allowing the pool certs to updated without having to reload Caddy. I changed my mind because this will be on a hot-path, and such delay will be unacceptable. They can be 3rd party modules if at all needed.

@mohammed90 mohammed90 removed the needs docs ✍️ Requires documentation changes label Jan 10, 2024
@mohammed90 mohammed90 changed the title tls: modularize client authentication trusted CA tls: modularize trusted CA providers Jan 10, 2024
@mohammed90
Copy link
Member Author

I did consider Lazy for some of them, which delays the load-and-parse until the pool is requested, allowing the pool certs to updated without having to reload Caddy.

Implemented for consideration.

I realized last week that this can be generalized to be the RootCA provider for other use cases, e.g. reverse-proxy transport. I will not touch the reverse-proxy transport in this PR though.

modules/caddytls/capools.go Outdated Show resolved Hide resolved
modules/caddytls/capools.go Outdated Show resolved Hide resolved
modules/caddytls/capools.go Outdated Show resolved Hide resolved
modules/caddytls/capools.go Outdated Show resolved Hide resolved
modules/caddytls/capools.go Outdated Show resolved Hide resolved
modules/caddytls/capools.go Outdated Show resolved Hide resolved
modules/caddytls/capools.go Outdated Show resolved Hide resolved
modules/caddytls/capools.go Show resolved Hide resolved
modules/caddytls/capools.go Outdated Show resolved Hide resolved
modules/caddytls/capools.go Outdated Show resolved Hide resolved
@mohammed90 mohammed90 marked this pull request as ready for review January 23, 2024 14:31
@mohammed90 mohammed90 added under review 🧐 Review is pending before merging and removed needs tests 💯 Requires automated tests do not merge ⛔ Not ready yet! labels Jan 23, 2024
@mholt
Copy link
Member

mholt commented Jan 23, 2024

Wow, I really appreciate all the work that went into these tests. Can't wait to review!!

Copy link
Member

@mholt mholt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a big improvement. 7 client auth provider modules built-in, that's pretty awesome! Thanks for working on this. LGTM.

"Matt, how can you approve a 2,500 line change without any review comments?" -- because Mohammed writes good code and nothing obvious stuck out to me. This is a bigger PR than I usually review, so yes I'm sure some details got overlooked. But I'd rather get this merged in and tested before a release than try to find all the problems with my tired eyes right now. 🙂

@mohammed90 mohammed90 merged commit e965b11 into master Jan 25, 2024
25 checks passed
@mohammed90 mohammed90 deleted the modular-client-ca branch January 25, 2024 08:44
@mholt
Copy link
Member

mholt commented Jan 25, 2024

Nice work on this :)

@Gr33nbl00d
Copy link
Contributor

Correct me if i am wrong but It seems you accidently broke #6022
With your change. The verifiers are not parsed anymore. In the conpollicy go you missed the verifiers section.
It is missing here :

@mohammed90
Copy link
Member Author

Correct me if i am wrong but It seems you accidently broke #6022
With your change. The verifiers are not parsed anymore. In the conpollicy go you missed the verifiers section.
It is missing here :

It shouldn't break. I was aware of it and tried my best to avoid breakage. The certificates are still parsed when the directive has the _leaf suffix. Do you have a test case/proof of the break?

@Gr33nbl00d
Copy link
Contributor

No you got it wrong, i try to explain it better: in the referenced pull request there was support added to load client certificate verifier modules via caddyfile. Which was previously only possible via json config. This has nothing to do with leaf certificates. It is used to do additional checks on client certificates. For example revocation checks via my plugin

https://github.com/Gr33nbl00d/caddy-revocation-validator

In line 437 this seems to be missing:

		case "verifier":
			if !d.NextArg() {
				return d.ArgErr()
			}

			vType := d.Val()
			modID := "tls.client_auth." + vType
			unm, err := caddyfile.UnmarshalModule(d, modID)
			if err != nil {
				return err
			}

			_, ok := unm.(ClientCertificateVerifier)
			if !ok {
				return d.Errf("module %s is not a caddytls.ClientCertificatVerifier", modID)
			}

@Gr33nbl00d
Copy link
Contributor

You can see it here in the old builtins.go line 221 the verifier section was there:
e965b11#diff-7761c0c9beafcd055ce9c6c894b6c54b888bc00598767551dfcc51b07bb81c36L221

@Gr33nbl00d
Copy link
Contributor

Correction i forgot 2 lines to copy :) Last 2 lines were missing in my previous comment

No you got it wrong, i try to explain it better: in the referenced pull request there was support added to load client certificate verifier modules via caddyfile. Which was previously only possible via json config. This has nothing to do with leaf certificates. It is used to do additional checks on client certificates. For example revocation checks via my plugin

https://github.com/Gr33nbl00d/caddy-revocation-validator

In line 437 this seems to be missing:

		case "verifier":
			if !d.NextArg() {
				return d.ArgErr()
			}

			vType := d.Val()
			modID := "tls.client_auth." + vType
			unm, err := caddyfile.UnmarshalModule(d, modID)
			if err != nil {
				return err
			}

			_, ok := unm.(ClientCertificateVerifier)
			if !ok {
				return d.Errf("module %s is not a caddytls.ClientCertificatVerifier", modID)
			}
                       cp.ClientAuthentication.VerifiersRaw = append(cp.ClientAuthentication.VerifiersRaw, 
                       caddyconfig.JSONModuleObject(unm, "verifier", vType, h.warnings))

@francislavoie
Copy link
Member

Yeah I see what you mean @Gr33nbl00d. It got lost in translation somewhere.

I think this happened because ultimately, we don't have any actual implementation of that module interface in Caddy itself, so it's not possible to write a test using anything built-in.

We should probably make a mock cert verifier module in a _test.go file which would let us run a Caddyfile adapt test for the verifier option.

PRs welcome!

@Gr33nbl00d
Copy link
Contributor

Yes you are right i had the same idea ;) It would definitly help to harden the code. It was maybe because a merge conflict in the builtin.go file because 2 different prs affected the same file.

@mohammed90
Copy link
Member Author

Aaah I see your point, @Gr33nbl00d. Sorry 😔 I'll definitely review a PR to add it back (with a test 🙂). If you don't beat me, I'll add it back but it might take me a while.

@Gr33nbl00d
Copy link
Contributor

Aaah I see your point, @Gr33nbl00d. Sorry 😔 I'll definitely review a PR to add it back (with a test 🙂). If you don't beat me, I'll add it back but it might take me a while.

No problem, this can always happen. We are humans not machines and we make mistakes. I am still in the process of implementing the caddy file support. This is not yet released :) So take your time

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature ⚙️ New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants