* Updated Database->get_ssh_keys() to store data in a host-specific hash (the previous attempt was brokenn).

* Got System->check_ssh_keys() working (though more testing is still needed).

Signed-off-by: Digimer <digimer@alteeve.ca>
main
Digimer 5 years ago
parent 453f5c6223
commit 1691674850
  1. 18
      Anvil/Tools/Database.pm
  2. 240
      Anvil/Tools/System.pm

@ -2704,13 +2704,11 @@ This loads all known user's SSH public keys and all known machine's public keys
ssh_keys::ssh_key_uuid::<ssh_key_uuid>::ssh_key_host_uuid = <Host UUID the user is from> ssh_keys::ssh_key_uuid::<ssh_key_uuid>::ssh_key_host_uuid = <Host UUID the user is from>
ssh_keys::ssh_key_uuid::<ssh_key_uuid>::ssh_key_user_name = <The user's name> ssh_keys::ssh_key_uuid::<ssh_key_uuid>::ssh_key_user_name = <The user's name>
ssh_keys::ssh_key_uuid::<ssh_key_uuid>::ssh_key_public_key = <The SSH public key> ssh_keys::ssh_key_uuid::<ssh_key_uuid>::ssh_key_public_key = <The SSH public key>
And:
ssh_keys::ssh_key_host_uuid::<ssh_key_host_uuid>::ssh_key_uuid = <UUID of ssh_keys column> And:
ssh_keys::ssh_key_host_uuid::<ssh_key_host_uuid>::ssh_key_user_name = <The user's name>
ssh_keys::ssh_key_host_uuid::<ssh_key_host_uuid>::ssh_key_public_key = <The SSH public key>
ssh_keys::host_uuid::<ssh_key_host_uuid>::ssh_key_user_name::<ssh_key_user_name>::ssh_key_uuid = <ssh_key_uuid entry value>
ssh_keys::host_uuid::<ssh_key_host_uuid>::ssh_key_user_name::<ssh_key_user_name>::ssh_key_public_key = <The SSH public key>
This method takes no parameters. This method takes no parameters.
@ -2771,13 +2769,11 @@ FROM
"ssh_keys::ssh_key_uuid::${ssh_key_uuid}::ssh_key_public_key" => $anvil->data->{ssh_keys}{ssh_key_uuid}{$ssh_key_uuid}{ssh_key_public_key}, "ssh_keys::ssh_key_uuid::${ssh_key_uuid}::ssh_key_public_key" => $anvil->data->{ssh_keys}{ssh_key_uuid}{$ssh_key_uuid}{ssh_key_public_key},
}}); }});
$anvil->data->{ssh_keys}{ssh_key_host_uuid}{$ssh_key_host_uuid}{ssh_key_uuid} = $ssh_key_uuid; $anvil->data->{ssh_keys}{host_uuid}{$ssh_key_host_uuid}{ssh_key_user_name}{$ssh_key_user_name}{ssh_key_uuid} = $ssh_key_uuid;
$anvil->data->{ssh_keys}{ssh_key_host_uuid}{$ssh_key_host_uuid}{ssh_key_user_name} = $ssh_key_user_name; $anvil->data->{ssh_keys}{host_uuid}{$ssh_key_host_uuid}{ssh_key_user_name}{$ssh_key_user_name}{ssh_key_public_key} = $ssh_key_public_key;
$anvil->data->{ssh_keys}{ssh_key_host_uuid}{$ssh_key_host_uuid}{ssh_key_public_key} = $ssh_key_public_key;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"ssh_keys::ssh_key_host_uuid::${ssh_key_host_uuid}::ssh_key_uuid" => $anvil->data->{ssh_keys}{ssh_key_host_uuid}{$ssh_key_host_uuid}{ssh_key_uuid}, "ssh_keys::host_uuid::${ssh_key_host_uuid}::ssh_key_user_name::${ssh_key_user_name}::ssh_key_uuid" => $anvil->data->{ssh_keys}{host_uuid}{$ssh_key_host_uuid}{ssh_key_user_name}{$ssh_key_user_name}{ssh_key_uuid},
"ssh_keys::ssh_key_host_uuid::${ssh_key_host_uuid}::ssh_key_user_name" => $anvil->data->{ssh_keys}{ssh_key_host_uuid}{$ssh_key_host_uuid}{ssh_key_user_name}, "ssh_keys::host_uuid::${ssh_key_host_uuid}::ssh_key_user_name::${ssh_key_user_name}::ssh_key_public_key" => $anvil->data->{ssh_keys}{host_uuid}{$ssh_key_host_uuid}{ssh_key_user_name}{$ssh_key_user_name}{ssh_key_public_key},
"ssh_keys::ssh_key_host_uuid::${ssh_key_host_uuid}::ssh_key_public_key" => $anvil->data->{ssh_keys}{ssh_key_host_uuid}{$ssh_key_host_uuid}{ssh_key_public_key},
}}); }});
} }

@ -755,28 +755,34 @@ sub check_ssh_keys
# and the key has changed, update the line with the new key. If it isn't found, add it. Once # and the key has changed, update the line with the new key. If it isn't found, add it. Once
# we check the old body for this entry, change the "old" body to the new one, then repeat the # we check the old body for this entry, change the "old" body to the new one, then repeat the
# process. # process.
my $local_host_uuid = $anvil->Get->host_type;
my $in_anvil = $anvil->data->{hosts}{host_uuid}{$local_host_uuid}{anvil_name};
my $trusted_host_uuids = []; my $trusted_host_uuids = [];
if ($anvil->Get->host_type eq "striker") foreach my $host_uuid (keys %{$anvil->data->{hosts}{host_uuid}})
{ {
# Add all known machines # Skip ourselves.
} next if $host_uuid eq $anvil->Get->host_uuid;
else
{ my $host_name = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_name};
# Add dashboard (using postgres connection info), the UUID is the host UUID. my $host_type = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_type};
foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{database}}) my $anvil_name = $anvil->data->{hosts}{host_uuid}{$host_uuid}{anvil_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
host_name => $host_name,
host_type => $host_type,
anvil_name => $anvil_name,
}});
if ($anvil->Get->host_type eq "striker")
{ {
# Periodically, autovivication causes and empty key to appear. # Add all known machines
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uuid => $uuid }}); push @{$trusted_host_uuids}, $host_uuid;
next if ((not $uuid) or (not $anvil->Validate->is_uuid({uuid => $uuid}))); }
elsif ((($in_anvil) && ($anvil_name eq $in_anvil)) or (exists $anvil->data->{database}{$host_uuid}))
push @{$trusted_host_uuids}, $uuid; {
# Add dashboards we use and peers
push @{$trusted_host_uuids}, $host_uuid;
} }
# Now add our peers.
} }
my $peers = [];
# Look at all the hosts I know about (other than myself) and see if any of the machine or # Look at all the hosts I know about (other than myself) and see if any of the machine or
# user keys either don't exist or have changed. # user keys either don't exist or have changed.
my $update_known_hosts = 0; my $update_known_hosts = 0;
@ -784,68 +790,69 @@ sub check_ssh_keys
my $known_hosts_new_lines = ""; my $known_hosts_new_lines = "";
my $authorized_keys_new_lines = ""; my $authorized_keys_new_lines = "";
### TODO: We need to handle all the IP addresses and host names with
### <short_hostname>.<bc|s|ifnX>, while dealing with duplicates.
# Check for changes to known_hosts # Check for changes to known_hosts
foreach my $host_uuid (keys %{$anvil->data->{peers}{ssh_keys}}) foreach my $host_uuid (@{$trusted_host_uuids})
{ {
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_uuid => $host_uuid }}); my $host_name = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_name};
foreach my $host_name (sort {$a cmp $b} keys %{$anvil->data->{peers}{ssh_keys}{$host_uuid}{host}}) my $host_key = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_key};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
host_name => $host_name,
host_uuid => $host_uuid,
host_key => $host_key,
}});
# Is this in the file and, if so, has it changed?
my $found = 0;
my $test_line = $host_name." ".$host_key;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { test_line => $test_line }});
foreach my $line (split/\n/, $known_hosts_old_body)
{ {
my $key = $anvil->data->{peers}{ssh_keys}{$host_uuid}{host}{$host_name}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { if ($line eq $test_line)
's1:host_name' => $host_name,
's2:key' => $key,
}});
# Is this in the file and, if so, has it changed?
my $found = 0;
my $test_line = $host_name." ".$key;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { test_line => $test_line }});
foreach my $line (split/\n/, $known_hosts_old_body)
{ {
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }}); # No change needed, key is the same.
if ($line eq $test_line) $found = 1;
{ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { found => $found }});
# No change needed, key is the same.
$found = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { found => $found }});
}
elsif ($line =~ /^$host_name /)
{
# Key has changed, update.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0274", variables => {
machine => $host_name,
old_key => $line,
new_key => $test_line,
}});
$found = 1;
$line = $test_line;
$update_known_hosts = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
found => $found,
line => $line,
update_known_hosts => $update_known_hosts,
}});
}
$known_hosts_new_body .= $line."\n";
} }
# If we didn't find the key, add it. elsif ($line =~ /^$host_name /)
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { found => $found }});
if (not $found)
{ {
$update_known_hosts = 1; # Key has changed, update.
$known_hosts_new_lines .= $test_line."\n"; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0274", variables => {
machine => $host_name,
old_key => $line,
new_key => $test_line,
}});
$found = 1;
$line = $test_line;
$update_known_hosts = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:update_known_hosts' => $update_known_hosts, found => $found,
's2:known_hosts_new_lines' => $known_hosts_new_lines, line => $line,
update_known_hosts => $update_known_hosts,
}}); }});
} }
$known_hosts_new_body .= $line."\n";
# Move the new body over to the old body (even though it may not have
# changed) and then clear the new body to prepare for the next pass.
$known_hosts_old_body = $known_hosts_new_body;
$known_hosts_new_body = "";
} }
# If we didn't find the key, add it.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { found => $found }});
if (not $found)
{
$update_known_hosts = 1;
$known_hosts_new_lines .= $test_line."\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:update_known_hosts' => $update_known_hosts,
's2:known_hosts_new_lines' => $known_hosts_new_lines,
}});
}
# Move the new body over to the old body (even though it may not have
# changed) and then clear the new body to prepare for the next pass.
$known_hosts_old_body = $known_hosts_new_body;
$known_hosts_new_body = "";
} }
# Lastly, copy the last version of the old body to the new body, # Lastly, copy the last version of the old body to the new body,
@ -857,61 +864,61 @@ sub check_ssh_keys
's4:difference' => diff \$known_hosts_file_body, \$known_hosts_new_body, { STYLE => 'Unified' }, 's4:difference' => diff \$known_hosts_file_body, \$known_hosts_new_body, { STYLE => 'Unified' },
}}); }});
### TODO: Change this to not use all hosts, but on dashboards we use, plus if we're in an Anvil!, those machines.
=cut
# Check for changes to authorized_keys # Check for changes to authorized_keys
foreach my $host_uuid (keys %{$anvil->data->{peers}{ssh_keys}}) foreach my $host_uuid (@{$trusted_host_uuids})
{ {
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_uuid => $host_uuid }}); my $host_name = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_name};
foreach my $ssh_key_user_name (sort {$a cmp $b} keys %{$anvil->data->{peers}{ssh_keys}{$host_uuid}{user}}) $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
host_uuid => $host_uuid,
host_name => $host_name,
}});
foreach my $user (sort {$a cmp $b} @{$users})
{ {
my $ssh_key_public_key = $anvil->data->{peers}{ssh_keys}{$host_uuid}{user}{$ssh_key_user_name}; if ((exists $anvil->data->{ssh_keys}{host_uuid}{$host_uuid}{ssh_key_user_name}{$user}) && ($anvil->data->{ssh_keys}{host_uuid}{$host_uuid}{ssh_key_user_name}{$user}{ssh_key_public_key}))
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:ssh_key_user_name' => $ssh_key_user_name,
's2:ssh_key_public_key' => $ssh_key_public_key,
}});
# The key in the file might have a different trailing suffix (user@host_name)
# and doesn't really matter. So we search by the key type and public key to
# see if it exists already.
my $found = 0;
my $test_line = ($ssh_key_public_key =~ /^(ssh-.*? .*?) /)[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { test_line => $test_line }});
foreach my $line (split/\n/, $authorized_keys_old_body)
{ {
# NOTE: Use '\Q...\E' so that the '+' characters in the key aren't my $ssh_key_public_key = $anvil->data->{ssh_keys}{host_uuid}{$host_uuid}{ssh_key_user_name}{$user}{ssh_key_public_key};
# evaluated as part of the regex.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }});
if ($line =~ /^\Q$test_line\E/)
{
# No change needed, key is the same.
$found = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { found => $found }});
}
# We don't look for changes (yet). Might be worth looking for stale
# keys by ckecking of the host at the end matches an entry in the
# database and then verifying the keys haven't changed, but that's
# for another day.
$authorized_keys_new_body .= $line."\n";
}
# If we didn't find the key, add it.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { found => $found }});
if (not $found)
{
$update_authorized_keys = 1;
$authorized_keys_new_lines .= $ssh_key_public_key."\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:update_authorized_keys' => $update_authorized_keys, 's1:user' => $user,
's2:authorized_keys_new_lines' => $authorized_keys_new_lines, 's2:host_name' => $host_name,
's3:ssh_key_public_key' => $ssh_key_public_key,
}}); }});
# The key in the file might have a different trailing suffix (user@host_name)
# and doesn't really matter. So we search by the key type and public key to
# see if it exists already.
my $found = 0;
my $test_line = ($ssh_key_public_key =~ /^(ssh-.*? .*?) /)[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { test_line => $test_line }});
foreach my $line (split/\n/, $authorized_keys_old_body)
{
# NOTE: Use '\Q...\E' so that the '+' characters in the key aren't
# evaluated as part of the regex.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }});
if ($line =~ /^\Q$test_line\E/)
{
# No change needed, key is the same.
$found = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { found => $found }});
}
$authorized_keys_new_body .= $line."\n";
}
# If we didn't find the key, add it.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { found => $found }});
if (not $found)
{
$update_authorized_keys = 1;
$authorized_keys_new_lines .= $ssh_key_public_key."\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:update_authorized_keys' => $update_authorized_keys,
's2:authorized_keys_new_lines' => $authorized_keys_new_lines,
}});
}
# Move the new body over to the old body (even though it may not have
# changed) and then clear the new body to prepare for the next pass.
$authorized_keys_old_body = $authorized_keys_new_body;
$authorized_keys_new_body = "";
} }
# Move the new body over to the old body (even though it may not have
# changed) and then clear the new body to prepare for the next pass.
$authorized_keys_old_body = $authorized_keys_new_body;
$authorized_keys_new_body = "";
} }
} }
@ -923,7 +930,6 @@ sub check_ssh_keys
's3:authorized_keys_new_body' => $authorized_keys_new_body, 's3:authorized_keys_new_body' => $authorized_keys_new_body,
's4:difference' => diff \$authorized_keys_file_body, \$authorized_keys_new_body, { STYLE => 'Unified' }, 's4:difference' => diff \$authorized_keys_file_body, \$authorized_keys_new_body, { STYLE => 'Unified' },
}}); }});
=cut
# Update the known_hosts files, if needed. # Update the known_hosts files, if needed.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { update_known_hosts => $update_known_hosts }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { update_known_hosts => $update_known_hosts }});

Loading…
Cancel
Save