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
Author

Choose a reason for hiding this comment

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

However I think if this just becomes a Store setting and part of the substitutes url, this should make a new settings system harder than what we currently have.

I am not sure, I understand this sentence. Should I try to reimplement this in a similar way as #12976?

Copy link
Member

Choose a reason for hiding this comment

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

Yes. Updated my response. If we can specify this per URL than it's more flexible because it doesn't make sense to have this as a global configuration.

Copy link

Choose a reason for hiding this comment

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

Hi @vlaci, @Mic92,

Sorry for not jumping on this earlier, but you may want to steal bits from these two commits, which implement per-substituter mTLS via ...?ssl-cert=...&ssl-key=... (the semantics are cURL's):

https://github.com/ztzg/nix/commits/xt-16104-iwei-mtls-store/

Copy link
Member

Choose a reason for hiding this comment

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

@ztzg looks good. I only don't understand why this adds ssl certificates for file://

Copy link

@ztzg ztzg May 3, 2025

Choose a reason for hiding this comment

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

Hi @Mic92,

I only don't understand why this adds ssl certificates for file://

I suppose you are referring to this fragment:

bool absolute = hasPrefix(path, "https://") || hasPrefix(path, "http://") || hasPrefix(path, "file://");

The expression was just lifted from the existing code to store its value; its semantics haven't changed.

Note the subsequent if (!absolute) [...]: the certificate and key are not configured for such "absolute" requests, as their URL components would not be applied to the substituter's "base URL."

(There are probably better ways of filtering out absolute URLs, but I haven't tried improving that.)

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
3 participants