From 368352dfa4f7a81125b12f29461e66ee740a1575 Mon Sep 17 00:00:00 2001 From: Damien Diederen Date: Wed, 17 May 2023 11:11:40 +0200 Subject: [PATCH] http-binary-cache-store: Add 'ssl-cert' and 'ssl-key' settings Those are set via the store's URI, e.g.: https://substituter.invalid?ssl-cert=/path/to/cert.pem&ssl-key=/path/to/key.pem --- doc/manual/rl-next/mtls-substituter.md | 13 ++++++++++++ src/libstore/filetransfer.cc | 6 ++++++ src/libstore/http-binary-cache-store.cc | 21 +++++++++++++++++-- .../include/nix/store/filetransfer.hh | 2 ++ .../nix/store/http-binary-cache-store.hh | 6 ++++++ 5 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 doc/manual/rl-next/mtls-substituter.md diff --git a/doc/manual/rl-next/mtls-substituter.md b/doc/manual/rl-next/mtls-substituter.md new file mode 100644 index 000000000..21f5401e4 --- /dev/null +++ b/doc/manual/rl-next/mtls-substituter.md @@ -0,0 +1,13 @@ +--- +synopsis: Support substituters using mTLS (client certificate) authentication +issues: [] +prs: [13030] +--- + +Added support for `ssl-cert` and `ssl-key` options in substituter URLs. + +Example: + + https://substituter.invalid?ssl-cert=/path/to/cert.pem&ssl-key=/path/to/key.pem + +When these options are configured, Nix will use this certificate/private key pair to authenticate to the server. diff --git a/src/libstore/filetransfer.cc b/src/libstore/filetransfer.cc index 8080fcfdd..ed1f4cbb5 100644 --- a/src/libstore/filetransfer.cc +++ b/src/libstore/filetransfer.cc @@ -410,6 +410,12 @@ struct curlFileTransfer : public FileTransfer if (writtenToSink) curl_easy_setopt(req, CURLOPT_RESUME_FROM_LARGE, writtenToSink); + if (!request.sslCert.empty()) + curl_easy_setopt(req, CURLOPT_SSLCERT, request.sslCert.c_str()); + + if (!request.sslKey.empty()) + curl_easy_setopt(req, CURLOPT_SSLKEY, request.sslKey.c_str()); + curl_easy_setopt(req, CURLOPT_ERRORBUFFER, errbuf); errbuf[0] = 0; diff --git a/src/libstore/http-binary-cache-store.cc b/src/libstore/http-binary-cache-store.cc index 2b591dda9..43519cd00 100644 --- a/src/libstore/http-binary-cache-store.cc +++ b/src/libstore/http-binary-cache-store.cc @@ -152,11 +152,28 @@ protected: FileTransferRequest makeRequest(const std::string & path) { - return FileTransferRequest( - hasPrefix(path, "https://") || hasPrefix(path, "http://") || hasPrefix(path, "file://") + bool absolute = hasPrefix(path, "https://") || hasPrefix(path, "http://") || hasPrefix(path, "file://"); + + FileTransferRequest request( + absolute ? path : config->cacheUri + "/" + path); + if (!absolute) { + Path sslCert = config->sslCert.get(); + if (!sslCert.empty()) { + debug("configuring SSL client certificate '%s' for '%s'", sslCert, request.uri); + request.sslCert = sslCert; + } + + Path sslKey = config->sslKey.get(); + if (!sslKey.empty()) { + debug("configuring SSL client certificate key '%s' for '%s'", sslKey, request.uri); + request.sslKey = sslKey; + } + } + + return request; } void getFile(const std::string & path, Sink & sink) override diff --git a/src/libstore/include/nix/store/filetransfer.hh b/src/libstore/include/nix/store/filetransfer.hh index 10c3ec7ef..1567e055f 100644 --- a/src/libstore/include/nix/store/filetransfer.hh +++ b/src/libstore/include/nix/store/filetransfer.hh @@ -65,6 +65,8 @@ struct FileTransferRequest std::string uri; Headers headers; std::string expectedETag; + Path sslCert; + Path sslKey; bool verifyTLS = true; bool head = false; bool post = false; diff --git a/src/libstore/include/nix/store/http-binary-cache-store.hh b/src/libstore/include/nix/store/http-binary-cache-store.hh index 66ec5f8d2..fe2bde144 100644 --- a/src/libstore/include/nix/store/http-binary-cache-store.hh +++ b/src/libstore/include/nix/store/http-binary-cache-store.hh @@ -13,6 +13,12 @@ struct HttpBinaryCacheStoreConfig : std::enable_shared_from_this sslCert{ + this, "", "ssl-cert", "An optional SSL client certificate in PEM format; see CURLOPT_SSLCERT."}; + + const Setting sslKey{ + this, "", "ssl-key", "The SSL client certificate key in PEM format; see CURLOPT_SSLKEY."}; + static const std::string name() { return "HTTP Binary Cache Store";