Skip to content

libstore/filetransfer: add support for MTLS authentication #13030

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

vlaci
Copy link

@vlaci vlaci commented Apr 15, 2025

Certificate/private-key pair can be configured globally and it will be handled by libcurl.

Motivation

In our setup, we use client certificate authentication extensively to access company resources. It would be very easy for us to deploy a binary cache and setup authentication the same way.

Context

Fixes #13002

Questions

  • Is it okay to support only one certificate globally?
    I've gone with that as I don't think, that many people use different certificates for different HTTPS services, and implementing per-domain certificate handling would greatly complicate the implementation
  • I've added the settings to globals, as netrc and CA verification settings are already there. IDK if that is the rignt place.

Add 👍 to pull requests you find important.

The Nix maintainer team uses a GitHub project board to schedule and track reviews.

Certificate/private-key pair can be configured globally and it will be
handled by libcurl.
@vlaci vlaci requested a review from Ericson2314 as a code owner April 15, 2025 14:18
@Mic92 Mic92 added this to Nix team Apr 15, 2025
@github-project-automation github-project-automation bot moved this to To triage in Nix team Apr 15, 2025
@@ -371,6 +371,11 @@ struct curlFileTransfer : public FileTransfer
curl_easy_setopt(req, CURLOPT_SSL_VERIFYHOST, 0);
}

if (settings.clientCertFile != "" && settings.clientKeyFile != "") {
curl_easy_setopt(req, CURLOPT_SSLCERT, settings.clientCertFile.get().c_str());
Copy link
Member

Choose a reason for hiding this comment

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

Is there a privacy implication if we start sending this to all binary caches unconditionally?

Copy link
Author

Choose a reason for hiding this comment

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

My understanding is that the server asks the client to present its certificate by sending the list of accepted issuers in a CertificateRequest message. It won't be presented, unless the configured certificate matches the requested issuer.

https://www.rfc-editor.org/rfc/rfc5246#section-7.4.4

Copy link
Member

@Mic92 Mic92 Apr 16, 2025

Choose a reason for hiding this comment

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

Would this allow to have multiple ssl certificates in a single file and curl than uses whatever is requested? Than there would be a reasonable way to support multiple caches with different certs each.

Copy link
Author

Choose a reason for hiding this comment

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

Copy link
Author

@vlaci vlaci Apr 16, 2025

Choose a reason for hiding this comment

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

  • We could add a config mapping similar to trusted-public-keys mapping domains to certificate paths. A cert and private key can be put in the same file.
  • or we could also support a directory structure similar to what docker uses for mtls. This clashes with the existing server CA configuration option a bit, though.

Copy link
Member

Choose a reason for hiding this comment

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

Oh. That certs.d directory looks really nice. Because if you someone creates tooling for adding caches, all they need to do is to drop the certificate in the right directory and ask the user to extend the substitute list. Will try to get some feedback on this today from the Nix team.

Copy link
Member

Choose a reason for hiding this comment

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

Another question, what does the error looks like if a certificate is expired? Just want to make sure the error is easy to understand.

Copy link
Author

@vlaci vlaci Apr 16, 2025

Choose a reason for hiding this comment

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

If the error happens during handshake, nix will print something like this

warning: error: unable to download 'https://foobar/hw81q3s8a7bz7jz7gp0h81838y5251p1.narinfo': SSL peer certificate or SSH remote key was not OK (60) SSL certificate problem: certificate has expired; retrying in 2283 ms

EDIT: nope, see below

The error also depends on the server setup. In my case, the server accepts any certificate during the handshake and checks it later, allowing it to return an HTTP 400 response which will be printed to standard output.

Copy link
Author

@vlaci vlaci Apr 16, 2025

Choose a reason for hiding this comment

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

I've actually tested it, and it looks like I was mistaken. If the handshake fails due to client cert error, it returns something like this, currently:

OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno 0;

It looks totally implementation defined~, as I see no way for the server to signal an issue with the certificate back to the client in the handshake itself.~
So a nodejs http server will just abort the connection (see above), but nginx for example will send an http error response.

Reading the RFC, it looks like, the server could send, for example a bad_certificate alert message, but it won't contain any detail about the error. I think this is one of the reasons why servers usually signal the error at the http layer.

Copy link
Member

@Mic92 Mic92 Apr 16, 2025

Choose a reason for hiding this comment

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

So we are still discussing what we do with #11139
(probably we get more updates on Monday), but we potentially can have this option being scoped to a substituter list, which would be more on point.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: To triage
Development

Successfully merging this pull request may close these issues.

Client certificate authentication support for binary caches
2 participants