=head1 NAME

ngcp-check-ssh-keys - check system and user SSH keys

=head1 SYNOPSIS

B<ngcp-check-ssh-keys> [I<options>...]

=head1 DESCRIPTION

This program checks the node for all known system and user files containing
SSH keys or files listing SSH keys.
It will print diagnostics on missing required keys,
on weak or deprecated keys.

The following is the list of key types and their security status
in NGCP systems:

=over

=item B<ed25519>

=item B<ed25519-sk>

This is a modern elliptic curve key type.
It is fast and secure, and has short key lengths.

=item B<rsa>

This is a traditional key type.
It is secure, but might be slower when establishing connections,
and has long key lengths.

Keys using 3072 or bits are considered weak.
Keys using more than 3072 bits up to 4096 are considered good.

=item B<ecdsa>

=item B<ecdsa-sk>

This is an elliptic curve key type.
But it is based on DSA, and thus relies on local strong CPRNG,
where a failure in its output might leak the private keys.
It is slower than B<ed25519>,
and there have been concerns about its standardization process not being
transparent, combined with NSA having potentially backdoored other NIST
standards such as B<Dual_EC_DRBG>.

=item B<dsa>

This key type is considered weak, and is not supported anymore by ssh.

=back

The following is the list of message digest types and their security status
in NGCP systems:

=over

=item B<sha512>

=item B<sha256>

Secure, and in most cases hardware accelerated.

=item B<sha1>

=item B<md5>

Weak. Collision attacks are practical.

=back

=head1 DIAGNOSTICS

=over

=item error: key <key> bits are weak (<key_bits> < <weak_bits> < <good_bits>)

=item error: key <key> bits are weak (<key_bits> < <weak_bits>)

=item error: key <key> uses weak digest function (<digest>)

The system or user I<key> is weak,
as it has either not enough bits or uses a weak digest function.

See L<PROCEDURES/Upgrade keys>.

=item error: missing user public key for <seckey>

The user F<seckey> file is missing the public key part,
usually named F<seckey.pub>.

See L<PROCEDURES/Missing public keys>.

=item error: missing user secret key for <pubkey>

The user F<pubkey> file is missing the secret key part,
usually named like F<pubkey> without the F<.pub> suffix.

See L<PROCEDURES/Generate keys>.

=item error: weak key type in authorized_keys <file>: <keytype> <fingerprint> <comment>

The user has a reference in I<file> for a weak authorized keys.

See L<PROCEDURES/Remove authorized_keys entry>.

=item error: weak key type in known_hosts <file>: <hostnames> <keytype> <key> <comment>

The system or user known_hosts F<file> contains a weak host key.

See L<PROCEDURES/Remove known_hosts entry>.

=item error: weak key type in key <file>: <bits> <fingerprint> <user> <algo>

The system or user key F<key> has a weak key type.

See L<PROCEDURES/Remove keys>.

=item warning: deprecated key type in authorized_keys <file>: <keytype> <fingerprint> <comment>

The user authorized_keys F<file> contains an entry for a deprecated key.

See L<PROCEDURES/Remove authorized_keys entry>.

=item warning: deprecated key type in known_hosts <file>: <hostnames> <keytype> <key> <comment>

The system or user known_hosts F<file> contains a deprecated host key.

See L<PROCEDURES/Remove known_hosts entry>.

=item warning: deprecated key type in key <file>: <bits> <fingerprint> <user> <algo>

The system or user F<key> type is deprecated as its security is in question.

See L<PROCEDURES/Remove keys>.

=item warning: key <key> bits are not strong (<key_bits> < <good_bits>)

The system or user uses has a F<key> that is not strong enough.

See L<PROCEDURES/Upgrade keys>.

=item warning: missing required host key <hostkey>

The system host key F<hostkey> is missing.

See L<PROCEDURES/Generate keys>.

=item warning: missing required user public key <pubkey>

=item warning: missing required user secret key <seckey>

The user is missing either the F<seckey>, the F<pubkey> parts or both
for a required key type.

See L<PROCEDURES/Generate keys>.

=item warning: unknown format in authorized_keys <file>: <keytype> <fingerprint> <comment>

=item warning: unknown key type in authorized_keys <file>: <keytype> <fingerprint> <comment>

=item warning: unknown key type in known_hosts <file>: <hostnames> <keytype> <key> <comment>

The specified F<authorized_keys> or F<known_hosts> files contain an entry
with an unknown format so its contents cannot be analyzed.

See L<PROCEDURES/Unknown or damaged files>.

=item warning: unknown key type in key <file>: <bits> <fingerprint> <user> <algo>

The system or user F<key> file contains a key with an unknown type,
its security cannot be analyzed.

See L<PROCEDURES/Unknown or damaged files>.

=back

=head1 PROCEDURES

=head2 Missing public keys

The public part of an existing secret key is missing, but it can be recovered
from the private key by running:

  ssh-keygen -y -f seckey >seckey.pub

=head2 Generate keys

Either a system or a user key needs to be generated.
This can be accomplished with L<ssh-keygen(1)>.

After the keys have been generated they might need to be added into
remote systems, either with L<ssh-copy-id(1)> for user keys,
or by adding references in known_hosts in the remote system for system keys.

=head2 Remove authorized_keys entry

If the user controlling the connecting client has secure keys listed then
it might be safe to remove the problematic references.
The removal still needs to be coordinated with the user in case they
use the problematic keys from outdated systems that do not support the
secure ones.
If there are no other secure keys listed, the remote users will need to
generate them and then add the public keys to the file before proceeding
with the removal.

Once this is done the entry can be removed from the file.

=head2 Remove known_hosts entry

If the host provides more secure key types,
then the problematic host key reference should be removed from the
F<known_hosts>.
Otherwise it might require generating a new host key on the specified
remote host, then updating the F<known_hosts> file.

=head2 Remove keys

Before proceeding with removing any keys,
remote systems need to be checked whether the users can still connect to,
for both system and user keys.
If after removing the keys there would remain no secure keys,
then those need to be generated proceeding further,
following L<PROCEDURES/Generate keys>.

For system keys this implies checking whether connecting systems know and
can use other secure keys.
Once it is deemed safe to remove them,
their type needs to be removed from the B<sshd.host_key_types> knob
in F<config.yml>,
the templates regenerated,
and then they keys removed from the F<etc/ssh/> directory.
The entries from the F<~/.ssh/known_hosts> in the remote systems can then
be removed.

For user keys this implies making sure the servers where they are used to
connect to contain other secure keys in their F<~/.ssh/authorized_keys> file.
Once it is deemed safe to remove them,
they can be removed from the user F<~/.ssh/> directory.
The entries from the F<~/.ssh/authorized_keys> in the remote systems can
then be removed.

=head2 Upgrade keys

The specified keys are weak or not strong enough due, to using a weak
digest algorithm or not using enough bits.

The keys need to be generated anew following L<PROCEDURES/Generate keys>,
and the affected keys need to be phased out following
L<PROCEDURES/Remove keys>.

=head2 Unknown or damaged files

The format for the file is unknown, perhaps due to very ancient key types
that are not known to the script (and neither to B<ssh> and B<sshd>).
Or perhaps the file has been damaged and contains garbage.
The file needs to be analyzed.

=head1 EXIT STATUS

Exit code 0 means everything looks good.
Exit code 1 means warnings were emitted.
Exit code 2 means errors were emitted.

=head1 SEE ALSO

L<authorized_keys(5)>,
L<ssh-keygen(1)>,
L<ssh(1)>,
L<sshd(8)>.

=head1 BUGS AND LIMITATIONS

Please report problems you notice to the Sipwise
Development Team <support@sipwise.com>.

=head1 AUTHOR

Guillem Jover <gjover@sipwise.com>

=head1 LICENSE

Copyright (C) 2024 Sipwise GmbH, Austria

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
