[pve-devel] [RFC cluster] pvecmn: add sshkeyscan

Thomas Lamprecht t.lamprecht at proxmox.com
Thu Nov 17 13:55:36 CET 2016


Add the sshkeyscan command which connects to all online nodes and
gets their IP on the given network. Those IPs will be used as hosts
for ssh-keyscan to gather the public keys of the nodes.

The collected public keys will then be added to our known_hosts file
in /etc/pve . On the addition we remove duplicate entries.

This is mainly useful for a dedicated migration network, as else the
keys must be collected manually - which can be tiresome on bigger
setups.

If we decide to add the dedicated migration network setting to the
GUI we could use this also to automatically gather the host public
keys.

Signed-off-by: Thomas Lamprecht <t.lamprecht at proxmox.com>
---
 data/PVE/CLI/pvecm.pm | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 93 insertions(+)

diff --git a/data/PVE/CLI/pvecm.pm b/data/PVE/CLI/pvecm.pm
index f5d5422..188ee4e 100755
--- a/data/PVE/CLI/pvecm.pm
+++ b/data/PVE/CLI/pvecm.pm
@@ -887,6 +887,98 @@ __PACKAGE__->register_method ({
 	return undef;
     }});
 
+__PACKAGE__->register_method ({
+    name => 'sshkeyscan',
+    path => 'sshkeyscan',
+    method => 'POST',
+    description => "Gathers all cluster node public keys from the given network " .
+	"and adds them to the known hosts file to allow public key authentication " .
+	"between the nodes on this network.",
+    parameters => {
+	additionalProperties => 0,
+	properties => {
+	    network => {
+		type => 'string',
+		format => 'CIDR',
+		description => 'The network which should be added to the known host file',
+	    },
+	},
+    },
+    returns => { type => 'null'},
+    code => sub {
+	my ($param) = @_;
+
+	if (!PVE::Cluster::check_cfs_quorum(1)) {
+	    print "no quorum\n";
+	    return undef;
+	}
+
+	my $network = $param->{network};
+
+	my $members = PVE::Cluster::get_members();
+
+	my $ssh_cmd = ['ssh', '-o', 'BatchMode=yes' ];
+	my $base_cmd = ['pvecm', 'mtunnel', '--get_migration_ip', '--migration_network', $network];
+
+	# connect to all member to get their local IP on the given network
+	my $addresses = [];
+	foreach my $node (sort keys %$members) {
+	    if (!$members->{$node}->{online}) {
+		warn "skip node '$node', not online\n";
+		next;
+	    }
+
+	    if (my $ip = $members->{$node}->{ip}) {
+
+		my $cmd = [ @$ssh_cmd, $ip, '--', @$base_cmd];
+
+		my $nodeip;
+		PVE::Tools::run_command($cmd, outfunc => sub {
+		    my $line = shift;
+
+		    if ($line =~ m/^ip: '($PVE::Tools::IPRE)'$/) {
+			$nodeip = $1;
+		    } else {
+			# just to be sure
+			die "no ip found for node '$node' in network '$network'\n";
+		    }
+		}, errfunc => sub {
+		    my $line = shift;
+
+		    $line =~ s/^could not get migration ip: //;
+		    print STDERR "error [$node]: $line\n";
+		});
+
+		print "found IP '$nodeip' on node '$node'\n";
+
+		push @$addresses, $nodeip;
+	    } else {
+		warn "skip node '$node', cannot get the cluster IP!\n";
+	    }
+	}
+
+	print "gather public keys\n";
+
+	my $known_hosts_fn = '/etc/pve/priv/known_hosts';
+	my $known_hosts_tmp_fn = "/etc/pve/priv/known_hosts.tmp.$$";
+
+	# scan all nodes IPs from the given network, pipe the public keys we
+	# got through unique sort to avoid duplicate entries
+	my $cmd = [['ssh-keyscan', '-t', 'rsa', @$addresses],
+	    ['sort', '-u', '-', $known_hosts_fn, \'>', $known_hosts_tmp_fn]];
+
+	PVE::Tools::run_command($cmd);
+
+	print "merge new keys in known_hosts file\n";
+
+	rename($known_hosts_tmp_fn, $known_hosts_fn)
+	    or die "activating new known_host file failed - $!!\n";
+
+	print "finished keyscan\n";
+
+	return undef;
+    }});
+
 
 our $cmddef = {
     keygen => [ __PACKAGE__, 'keygen', ['filename']],
@@ -899,6 +991,7 @@ our $cmddef = {
     expected => [ __PACKAGE__, 'expected', ['expected']],
     updatecerts => [ __PACKAGE__, 'updatecerts', []],
     mtunnel => [ __PACKAGE__, 'mtunnel', []],
+    sshkeyscan => [ __PACKAGE__, 'sshkeyscan', ['network']],
 };
 
 1;
-- 
2.1.4





More information about the pve-devel mailing list