mirror of
https://github.com/privatevoid-net/nix-super.git
synced 2024-11-29 17:16:15 +02:00
Merge pull request #4574 from grahamc/libstore-ssh-host-key
libstore: support passing a builder's public SSH host key
This commit is contained in:
commit
e64cf8e0a3
6 changed files with 33 additions and 6 deletions
|
@ -112,6 +112,10 @@ default, set it to `-`.
|
||||||
features appear in the derivation’s `requiredSystemFeatures`
|
features appear in the derivation’s `requiredSystemFeatures`
|
||||||
attribute..
|
attribute..
|
||||||
|
|
||||||
|
8. The (base64-encoded) public host key of the remote machine. If omitted, SSH
|
||||||
|
will use its regular known-hosts file. Specifically, the field is calculated
|
||||||
|
via `base64 -w0 /etc/ssh/ssh_host_ed25519_key.pub`.
|
||||||
|
|
||||||
For example, the machine specification
|
For example, the machine specification
|
||||||
|
|
||||||
nix@scratchy.labs.cs.uu.nl i686-linux /home/nix/.ssh/id_scratchy_auto 8 1 kvm
|
nix@scratchy.labs.cs.uu.nl i686-linux /home/nix/.ssh/id_scratchy_auto 8 1 kvm
|
||||||
|
|
|
@ -15,6 +15,7 @@ struct LegacySSHStoreConfig : virtual StoreConfig
|
||||||
using StoreConfig::StoreConfig;
|
using StoreConfig::StoreConfig;
|
||||||
const Setting<int> maxConnections{(StoreConfig*) this, 1, "max-connections", "maximum number of concurrent SSH connections"};
|
const Setting<int> maxConnections{(StoreConfig*) this, 1, "max-connections", "maximum number of concurrent SSH connections"};
|
||||||
const Setting<Path> sshKey{(StoreConfig*) this, "", "ssh-key", "path to an SSH private key"};
|
const Setting<Path> sshKey{(StoreConfig*) this, "", "ssh-key", "path to an SSH private key"};
|
||||||
|
const Setting<std::string> sshPublicHostKey{(StoreConfig*) this, "", "base64-ssh-public-host-key", "The public half of the host's SSH key"};
|
||||||
const Setting<bool> compress{(StoreConfig*) this, false, "compress", "whether to compress the connection"};
|
const Setting<bool> compress{(StoreConfig*) this, false, "compress", "whether to compress the connection"};
|
||||||
const Setting<Path> remoteProgram{(StoreConfig*) this, "nix-store", "remote-program", "path to the nix-store executable on the remote system"};
|
const Setting<Path> remoteProgram{(StoreConfig*) this, "nix-store", "remote-program", "path to the nix-store executable on the remote system"};
|
||||||
const Setting<std::string> remoteStore{(StoreConfig*) this, "", "remote-store", "URI of the store on the remote system"};
|
const Setting<std::string> remoteStore{(StoreConfig*) this, "", "remote-store", "URI of the store on the remote system"};
|
||||||
|
@ -59,6 +60,7 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor
|
||||||
, master(
|
, master(
|
||||||
host,
|
host,
|
||||||
sshKey,
|
sshKey,
|
||||||
|
sshPublicHostKey,
|
||||||
// Use SSH master only if using more than 1 connection.
|
// Use SSH master only if using more than 1 connection.
|
||||||
connections->capacity() > 1,
|
connections->capacity() > 1,
|
||||||
compress,
|
compress,
|
||||||
|
|
|
@ -54,9 +54,15 @@ ref<Store> Machine::openStore() const {
|
||||||
if (hasPrefix(storeUri, "ssh://")) {
|
if (hasPrefix(storeUri, "ssh://")) {
|
||||||
storeParams["max-connections"] = "1";
|
storeParams["max-connections"] = "1";
|
||||||
storeParams["log-fd"] = "4";
|
storeParams["log-fd"] = "4";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasPrefix(storeUri, "ssh://") || hasPrefix(storeUri, "ssh-ng://")) {
|
||||||
if (sshKey != "")
|
if (sshKey != "")
|
||||||
storeParams["ssh-key"] = sshKey;
|
storeParams["ssh-key"] = sshKey;
|
||||||
|
if (sshPublicHostKey != "")
|
||||||
|
storeParams["base64-ssh-public-host-key"] = sshPublicHostKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto & fs = storeParams["system-features"];
|
auto & fs = storeParams["system-features"];
|
||||||
auto append = [&](auto feats) {
|
auto append = [&](auto feats) {
|
||||||
|
|
|
@ -13,6 +13,7 @@ struct SSHStoreConfig : virtual RemoteStoreConfig
|
||||||
using RemoteStoreConfig::RemoteStoreConfig;
|
using RemoteStoreConfig::RemoteStoreConfig;
|
||||||
|
|
||||||
const Setting<Path> sshKey{(StoreConfig*) this, "", "ssh-key", "path to an SSH private key"};
|
const Setting<Path> sshKey{(StoreConfig*) this, "", "ssh-key", "path to an SSH private key"};
|
||||||
|
const Setting<std::string> sshPublicHostKey{(StoreConfig*) this, "", "base64-ssh-public-host-key", "The public half of the host's SSH key"};
|
||||||
const Setting<bool> compress{(StoreConfig*) this, false, "compress", "whether to compress the connection"};
|
const Setting<bool> compress{(StoreConfig*) this, false, "compress", "whether to compress the connection"};
|
||||||
const Setting<Path> remoteProgram{(StoreConfig*) this, "nix-daemon", "remote-program", "path to the nix-daemon executable on the remote system"};
|
const Setting<Path> remoteProgram{(StoreConfig*) this, "nix-daemon", "remote-program", "path to the nix-daemon executable on the remote system"};
|
||||||
const Setting<std::string> remoteStore{(StoreConfig*) this, "", "remote-store", "URI of the store on the remote system"};
|
const Setting<std::string> remoteStore{(StoreConfig*) this, "", "remote-store", "URI of the store on the remote system"};
|
||||||
|
@ -34,6 +35,7 @@ public:
|
||||||
, master(
|
, master(
|
||||||
host,
|
host,
|
||||||
sshKey,
|
sshKey,
|
||||||
|
sshPublicHostKey,
|
||||||
// Use SSH master only if using more than 1 connection.
|
// Use SSH master only if using more than 1 connection.
|
||||||
connections->capacity() > 1,
|
connections->capacity() > 1,
|
||||||
compress)
|
compress)
|
||||||
|
|
|
@ -2,24 +2,37 @@
|
||||||
|
|
||||||
namespace nix {
|
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)
|
: host(host)
|
||||||
, fakeSSH(host == "localhost")
|
, fakeSSH(host == "localhost")
|
||||||
, keyFile(keyFile)
|
, keyFile(keyFile)
|
||||||
|
, sshPublicHostKey(sshPublicHostKey)
|
||||||
, useMaster(useMaster && !fakeSSH)
|
, useMaster(useMaster && !fakeSSH)
|
||||||
, compress(compress)
|
, compress(compress)
|
||||||
, logFD(logFD)
|
, logFD(logFD)
|
||||||
{
|
{
|
||||||
if (host == "" || hasPrefix(host, "-"))
|
if (host == "" || hasPrefix(host, "-"))
|
||||||
throw Error("invalid SSH host name '%s'", host);
|
throw Error("invalid SSH host name '%s'", host);
|
||||||
|
|
||||||
|
auto state(state_.lock());
|
||||||
|
state->tmpDir = std::make_unique<AutoDelete>(createTempDir("", "nix", true, true, 0700));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSHMaster::addCommonSSHOpts(Strings & args)
|
void SSHMaster::addCommonSSHOpts(Strings & args)
|
||||||
{
|
{
|
||||||
|
auto state(state_.lock());
|
||||||
|
|
||||||
for (auto & i : tokenizeString<Strings>(getEnv("NIX_SSHOPTS").value_or("")))
|
for (auto & i : tokenizeString<Strings>(getEnv("NIX_SSHOPTS").value_or("")))
|
||||||
args.push_back(i);
|
args.push_back(i);
|
||||||
if (!keyFile.empty())
|
if (!keyFile.empty())
|
||||||
args.insert(args.end(), {"-i", keyFile});
|
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)
|
if (compress)
|
||||||
args.push_back("-C");
|
args.push_back("-C");
|
||||||
}
|
}
|
||||||
|
@ -87,7 +100,6 @@ Path SSHMaster::startMaster()
|
||||||
|
|
||||||
if (state->sshMaster != -1) return state->socketPath;
|
if (state->sshMaster != -1) return state->socketPath;
|
||||||
|
|
||||||
state->tmpDir = std::make_unique<AutoDelete>(createTempDir("", "nix", true, true, 0700));
|
|
||||||
|
|
||||||
state->socketPath = (Path) *state->tmpDir + "/ssh.sock";
|
state->socketPath = (Path) *state->tmpDir + "/ssh.sock";
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ private:
|
||||||
const std::string host;
|
const std::string host;
|
||||||
bool fakeSSH;
|
bool fakeSSH;
|
||||||
const std::string keyFile;
|
const std::string keyFile;
|
||||||
|
const std::string sshPublicHostKey;
|
||||||
const bool useMaster;
|
const bool useMaster;
|
||||||
const bool compress;
|
const bool compress;
|
||||||
const int logFD;
|
const int logFD;
|
||||||
|
@ -29,7 +30,7 @@ private:
|
||||||
|
|
||||||
public:
|
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
|
struct Connection
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue