From 5a2716f6d30bf81e3c6d74ae6410db382f5afe84 Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Wed, 24 Feb 2021 20:52:22 -0500 Subject: [PATCH] distributed builds: load remote builder host key from the machines file This is already used by Hydra, and is very useful when materializing a remote builder list from service discovery. This allows the service discovery tool to only sync one file instead of two. --- src/build-remote/build-remote.cc | 2 ++ src/libstore/legacy-ssh-store.cc | 2 ++ src/libstore/ssh-store.cc | 2 ++ src/libstore/ssh.cc | 17 ++++++++++++++--- src/libstore/ssh.hh | 3 ++- 5 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/build-remote/build-remote.cc b/src/build-remote/build-remote.cc index 279ae62f69c..082826edbf0 100644 --- a/src/build-remote/build-remote.cc +++ b/src/build-remote/build-remote.cc @@ -192,6 +192,8 @@ static int _main(int argc, char * * argv) storeParams["log-fd"] = "4"; if (bestMachine->sshKey != "") storeParams["ssh-key"] = bestMachine->sshKey; + if (bestMachine->sshPublicHostKey != "") + storeParams["base64-ssh-public-host-key"] = bestMachine->sshPublicHostKey; } sshStore = openStore(bestMachine->storeUri, storeParams); diff --git a/src/libstore/legacy-ssh-store.cc b/src/libstore/legacy-ssh-store.cc index d5fbdd25aa4..5edd486b6cd 100644 --- a/src/libstore/legacy-ssh-store.cc +++ b/src/libstore/legacy-ssh-store.cc @@ -15,6 +15,7 @@ struct LegacySSHStore : public Store { const Setting maxConnections{this, 1, "max-connections", "maximum number of concurrent SSH connections"}; const Setting sshKey{this, "", "ssh-key", "path to an SSH private key"}; + const Setting sshPublicHostKey{this, "", "base64-ssh-public-host-key", "The public half of the host's SSH key"}; const Setting compress{this, false, "compress", "whether to compress the connection"}; const Setting remoteProgram{this, "nix-store", "remote-program", "path to the nix-store executable on the remote system"}; const Setting remoteStore{this, "", "remote-store", "URI of the store on the remote system"}; @@ -48,6 +49,7 @@ struct LegacySSHStore : public Store , master( host, sshKey, + sshPublicHostKey, // Use SSH master only if using more than 1 connection. connections->capacity() > 1, compress, diff --git a/src/libstore/ssh-store.cc b/src/libstore/ssh-store.cc index 93e11738991..7800968f17e 100644 --- a/src/libstore/ssh-store.cc +++ b/src/libstore/ssh-store.cc @@ -15,6 +15,7 @@ class SSHStore : public RemoteStore public: const Setting sshKey{(Store*) this, "", "ssh-key", "path to an SSH private key"}; + const Setting sshPublicHostKey{(Store*) this, "", "base64-ssh-public-host-key", "The public half of the host's SSH key"}; const Setting compress{(Store*) this, false, "compress", "whether to compress the connection"}; SSHStore(const std::string & host, const Params & params) @@ -24,6 +25,7 @@ class SSHStore : public RemoteStore , master( host, sshKey, + sshPublicHostKey, // Use SSH master only if using more than 1 connection. connections->capacity() > 1, compress) diff --git a/src/libstore/ssh.cc b/src/libstore/ssh.cc index dea16e533ef..c77b13644fb 100644 --- a/src/libstore/ssh.cc +++ b/src/libstore/ssh.cc @@ -2,24 +2,37 @@ namespace nix { -SSHMaster::SSHMaster(const std::string & host, const std::string & keyFile, bool useMaster, bool compress, int logFD) +SSHMaster::SSHMaster(const std::string & host, const std::string & keyFile, const std::string & sshPublicHostKey, bool useMaster, bool compress, int logFD) : host(host) , fakeSSH(host == "localhost") , keyFile(keyFile) + , sshPublicHostKey(sshPublicHostKey) , useMaster(useMaster && !fakeSSH) , compress(compress) , logFD(logFD) { if (host == "" || hasPrefix(host, "-")) throw Error("invalid SSH host name '%s'", host); + + auto state(state_.lock()); + state->tmpDir = std::make_unique(createTempDir("", "nix", true, true, 0700)); } void SSHMaster::addCommonSSHOpts(Strings & args) { + auto state(state_.lock()); + for (auto & i : tokenizeString(getEnv("NIX_SSHOPTS"))) args.push_back(i); if (!keyFile.empty()) args.insert(args.end(), {"-i", keyFile}); + if (!sshPublicHostKey.empty()) { + Path fileName = (Path) *state->tmpDir + "/host-key"; + auto p = host.rfind("@"); + string thost = p != string::npos ? string(host, p + 1) : host; + writeFile(fileName, thost + " " + base64Decode(sshPublicHostKey) + "\n"); + args.insert(args.end(), {"-oUserKnownHostsFile=" + fileName}); + } if (compress) args.push_back("-C"); } @@ -87,8 +100,6 @@ Path SSHMaster::startMaster() if (state->sshMaster != -1) return state->socketPath; - state->tmpDir = std::make_unique(createTempDir("", "nix", true, true, 0700)); - state->socketPath = (Path) *state->tmpDir + "/ssh.sock"; Pipe out; diff --git a/src/libstore/ssh.hh b/src/libstore/ssh.hh index 4f0f0bd29f9..dabbcedda09 100644 --- a/src/libstore/ssh.hh +++ b/src/libstore/ssh.hh @@ -12,6 +12,7 @@ private: const std::string host; bool fakeSSH; const std::string keyFile; + const std::string sshPublicHostKey; const bool useMaster; const bool compress; const int logFD; @@ -29,7 +30,7 @@ private: public: - SSHMaster(const std::string & host, const std::string & keyFile, bool useMaster, bool compress, int logFD = -1); + SSHMaster(const std::string & host, const std::string & keyFile, const std::string & sshPublicHostKey, bool useMaster, bool compress, int logFD = -1); struct Connection {