misterperl has asked for the wisdom of the Perl Monks concerning the following question:

I have a ~/.ssh/known_hosts file which stores all my ssh keys for all aps.

Recently I started using the Net::SSH and SFTP Perl modules, and they created and used a new file known_hosts2. Is there a way I can force them to use the existing file, and not add a new one? I need to connect to nodes in the known_hosts file but these modules seem to ignore it.

Remarkably even if I explicitly TELL it what hostfile to use, it ignores that and uses known_hosts2:

my $keyfile='~/.ssh/known_hosts'; Net::SSH::Perl->new( $host, [identity_files => [$keyfile]);
..which seems to be 100% disregarded. I examined the ssh object and this doesn't appear in it at all after returning from login() (it is there after new()

I studied the metacpan page for SFTP; I don't see a way to specify to use the existing file in the new() args, so I'm not sure if this approach is even meaningful.

The known_hosts file has the default privs. According to chatbot AI, privs > 600 are acceptable. They are in fact 700.

Advice please? I don't want to fork this file (for now I cut the new keys from hosts2 and pasted them into hosts, and deleted hosts2.)

Rolf is this in your wheelhouse (hope so , your replies are ALWAYS amazingly helpful!)....

On a related note, I was in the debugger stepping through Net::SSH::Perl::AuthMgr and reached this line:

$code->($amgr, $packet, @args);
I've never seen a syntax like $object->(list) ; seems like the a method name is missing? IS there a default class method? This is the point where the connection errors..

- MP

Replies are listed 'Best First'.
Re: Why does Net::SFTP and Net::SSH::Perl not use "known_hosts"
by pryrt (Abbot) on Apr 20, 2023 at 17:38 UTC
    My reading of the Net::SSH::Perl documentation says that identity_files => [$rsa_file] is for the id_rsa or similar identity , not for your known hosts file -- ie, the key sent to the remote server for authentication. It mentions UserKnownHostsFile in the options section, so that implies that the following might be what you want (untested):

    use Net::SSH::Perl; my $keyfile='~/.ssh/known_hosts'; my $ssh = Net::SSH::Perl->new( $host, options => ["UserKnownHostsFile +$keyfile"] );

    If I run Data::Dump::dd on $ssh , it will show the default path to known_hosts2 if I don't have that options parameter, but shows the new path I indicate if I do have that parameter, so I think it's right. (But I don't have a known-working connection for Net::SSH::Perl to test, since I've never used that module and only installed it to look into this question, and couldn't get a connection working in the 5 min I allocated, so I cannot tell you that it will for-sure work.)


    update: a few hours later, the following SSCCE works for me

    #!perl use 5.012; # strict, // use warnings; use autodie; my $hostname = "obfuscated"; my $username = "obfuscated"; my $known_hosts = '/obfuscated/.ssh/known_hosts'; my ($id_rsa, $id_ecdsa, $id_ed25519) = map '/obfuscated/.ssh/'.$_, qw/ +id_rsa id_ecdsa id_ed25519/; use Net::SSH::Perl; use Data::Dump; my %options = ( # debug => 1, # set this one to help with de +bug protocol => 2, # ssh2 interactive => 1, # ask for password if somethin +g goes wrong strict_host_key_checking => 'yes', # makes sure it actually check +s known hosts options => [ "UserKnownHostsFile $known_hosts", # defines +the user path/name for known_hosts ], identity_files => [$id_rsa, $id_ed25519, $id_ecdsa], # defines +the possible identity_file path strings ); my $ssh = Net::SSH::Perl::->new($hostname, %options) or die "create ss +h: $!"; #dd $ssh; # use this when debugging the +various %options $ssh->login($username) or die "login: $!"; # using id_rsa identificat +ion, at default id_rsa location, or ask for pw if it fails print map { $_//"<undef>\n", "\n----\n"} $ssh->cmd('pwd');

    I tried with known_hosts and known_hosts2 and even the made-up known_hosts3 and they all worked -- if they didn't exist, it would prompt if I wanted to save the host key; if it did exist already, it would use that previously-saved host key.

Re: Why does Net::SFTP and Net::SSH::Perl not use "known_hosts" (coderefs)
by hippo (Archbishop) on Apr 20, 2023 at 15:12 UTC
    I've never seen a syntax like $object->(list)

    The variable is likely not a full object but just a simple coderef. eg:

    #!/usr/bin/env perl use strict; use warnings; my $code = sub { print "I found a $_!\n" for @_ }; $code->('x', 'y', 'z');

    See Arrow Notation in perlref for more.


    🦛

Re: Why does Net::SFTP and Net::SSH::Perl not use "known_hosts"
by kcott (Archbishop) on Apr 20, 2023 at 16:38 UTC

    G'day MP,

    Net::SSH::Perl->new( $host, [identity_files => [$keyfile]);

    It's best to copy-paste code rather than type it manually; I'm assuming that's what you did and introduced a typo.

    $ perl -MO=Deparse -e 'Net::SSH::Perl->new( $host, [identity_files => +[$keyfile]);' syntax error at -e line 1, near "])" Missing right curly or square bracket at -e line 1, at end of line -e had compilation errors.

    So, perhaps your real code has (completely guessing):

    Net::SSH::Perl->new( $host, [identity_files => [$keyfile]]);

    Regardless, if you look at the Net::SSH::Perl doco, you'll see

    Net::SSH::Perl->new($host, %params)

    And, further down in the description of %params: "identity_files ... a reference to an array of strings ...". There's more information there, which you should read, but it would seem that you really want:

    Net::SSH::Perl->new($host, identity_files => [$keyfile]);

    — Ken

Re: Why does Net::SFTP and Net::SSH::Perl not use "known_hosts"
by atcroft (Abbot) on Apr 22, 2023 at 00:26 UTC

    From OP:

    I have a ~/.ssh/known_hosts file which stores all my ssh keys for all aps.

    Others have done a great job of going through the issues you had with your code, but I wanted to clear up something about that sentence. I believe you are misunderstanding the purpose and use of the known_hosts file.

    The known_hosts file contains the public host key of known servers, and is used to protect against impersonation or man-in-the-middle attacks by allowing the user to verify that the server they are connecting to is the same one they connected to previously. When your SSH client connects, it will consult the system's /etc/ssh/ssh_known_hosts and the user's known_hosts file for that system's public host key. If one is present it will be compared and either allowing the connection or failing depending on if it is verified or not. If a public host key is not found, generally a fingerprint of the key will be displayed and there will be the option to add the key to the file.

    The format of a known_hosts file differs from that of either a public or private key file. My experience with these files has been as follows:

    • Private key files have a header and footer indicating the beginning and end of the encoded key.
    • Public key files are one key per line each, consisting of a space-separated key type, key, and optionally a trailing comment (useful when searching for one key out of many).
    • known_hosts files have one line per unique host/port combination which consists of a space-separated host (may have several names/IP addresses comma-separated, and may have the port appended if a non-standard port is used), the key type, followed by the key.

    Out of curiosity I did try using a recent (9.x) OpenSSH client against a constructed known_hosts file consisting only of key file contents (public key, private key, or a mix of the two) and was prompted each time if the server's host key was not present in the known_hosts file. I also tried using the same constructed known_hosts files as the identity file (key file) for a connection and while it did report "invalid known_host entry" lines when done verbosely ("-v" option) it did connect successfully.

    While the default private key file names (in the user's .ssh directory, normally $HOME/.ssh) are id_rsa, id_ecdsa, id_ecdsa_sk, id_ed25519, id_ed25519_sk, and id_dsa (and the associated public key file names are the name with ".pub" appended), key files can be given other names (using ssh-keygen's "-f $filename" option) and specified to the command-line client using the "-i $filename" option, the "-o IdentityFile=$filename" option, or specifying the "IdentityFile $filename" option in an appropriate .ssh/config entry.

    I'm not aware of a particular issue you might encounter at this time, but it might be a good idea to put the files in expected locations -- from a documentation point, a "best practices" point, and especially if you expect someone else may help you with supporting the apps in the future.

    Good luck.


    2023-04-22 - Fixed typo.