Adds an example plugin implementing an mTLS-enabled binary cache store (https+mtls:// scheme) using client certificates for authentication. Darwin fix: don't link liblix* into plugins (host resolves symbols at runtime via dynamic_lookup). Explicitly link curl so it binds to Nix-store libcurl, not /usr/lib/libcurl. This prevents the plugin's curl_easy_setopt calls from operating on the wrong libcurl instance. Test portability: BSD sed -i wrapper, OpenSSL -sha256 for cert signing, redirect test server output to log file. Change-Id: I652b987d3ac45e31df50ff4ba1f523294438c2b6
103 lines
2.8 KiB
C++
103 lines
2.8 KiB
C++
#include "lix/libstore/store-api.hh"
|
|
#include "lix/libutil/config.hh"
|
|
#include "lix/libstore/http-binary-cache-store.hh"
|
|
#include <stdlib.h>
|
|
#include <curl/curl.h>
|
|
|
|
namespace nix {
|
|
struct mTLSBinaryCacheStoreConfig : HttpBinaryCacheStoreConfig
|
|
{
|
|
using HttpBinaryCacheStoreConfig::HttpBinaryCacheStoreConfig;
|
|
|
|
const std::string name() override
|
|
{
|
|
return "mTLS HTTP Binary Cache Store";
|
|
}
|
|
|
|
std::string doc() override
|
|
{
|
|
return
|
|
#include "mtls-http-binary-cache-store.md"
|
|
;
|
|
}
|
|
|
|
PathsSetting<nix::Path> tlsCertificate{
|
|
this,
|
|
"",
|
|
"tls-certificate",
|
|
"Path of the TLS client certificate in PEM format as expected by CURLOPT_SSLCERT"
|
|
};
|
|
|
|
PathsSetting<nix::Path> tlsKey{
|
|
this,
|
|
"",
|
|
"tls-private-key",
|
|
"Path of the TLS client certificate private key in PEM format as expected by CURLOPT_SSLKEY"
|
|
};
|
|
};
|
|
|
|
struct mTLSBinaryCacheStoreImpl : public HttpBinaryCacheStore
|
|
{
|
|
struct Keyring
|
|
{
|
|
nix::Path tlsCertificate;
|
|
nix::Path tlsKey;
|
|
};
|
|
|
|
mTLSBinaryCacheStoreConfig config_;
|
|
std::shared_ptr<Keyring> keyring;
|
|
|
|
mTLSBinaryCacheStoreConfig & config() override
|
|
{
|
|
return config_;
|
|
}
|
|
const mTLSBinaryCacheStoreConfig & config() const override
|
|
{
|
|
return config_;
|
|
}
|
|
|
|
mTLSBinaryCacheStoreImpl(
|
|
const std::string & uriScheme, const Path & _cacheUri, mTLSBinaryCacheStoreConfig config
|
|
)
|
|
: Store(config)
|
|
, HttpBinaryCacheStore("https", _cacheUri, config)
|
|
, config_(std::move(config))
|
|
, keyring(std::make_shared<Keyring>(config_.tlsCertificate.get(), config_.tlsKey.get()))
|
|
{
|
|
}
|
|
|
|
FileTransferOptions makeOptions(Headers && headers = {}) override
|
|
{
|
|
auto options = HttpBinaryCacheStore::makeOptions(std::move(headers));
|
|
auto baseExtraSetup = std::move(options.extraSetup);
|
|
auto keyring = this->keyring;
|
|
|
|
options.extraSetup = [keyring, baseExtraSetup{std::move(baseExtraSetup)}](CURL * req) {
|
|
if (baseExtraSetup) {
|
|
baseExtraSetup(req);
|
|
}
|
|
|
|
const bool haveCert = !keyring->tlsCertificate.empty();
|
|
const bool haveKey = !keyring->tlsKey.empty();
|
|
if (!(haveCert && haveKey)) {
|
|
throw Error("https+mtls requires both tls-certificate and tls-private-key");
|
|
}
|
|
curl_easy_setopt(req, CURLOPT_SSLCERT, keyring->tlsCertificate.c_str());
|
|
curl_easy_setopt(req, CURLOPT_SSLKEY, keyring->tlsKey.c_str());
|
|
};
|
|
|
|
return options;
|
|
}
|
|
|
|
static std::set<std::string> uriSchemes()
|
|
{
|
|
return {"https+mtls"};
|
|
}
|
|
};
|
|
}
|
|
|
|
extern "C" void nix_plugin_entry()
|
|
{
|
|
nix::StoreImplementations::add<nix::mTLSBinaryCacheStoreImpl, nix::mTLSBinaryCacheStoreConfig>();
|
|
}
|