SSH

From Dev Wiki
Jump to navigation Jump to search

SSH stands for "Secure Shell". It's used to securely connect to remote machines.

Most common uses are to securely access repositories in sites like Github, GitLab, or Bitbucket. Or to gain access to a remote machine's terminal (such as if you're the admin of said machine).

SSH authentication can be done through either a standard "username + password" combination, or through SSH Keys. Note that SSH Keys are generally considered more secure, as it's a physical code that the user needs access to.


SSH Keys

What are SSH Keys

At their core, SSH keys are based of "difficult to solve" mathematical problems. Generally speaking, these problems have "two part" solutions, where the PublicKey and PrivateKey each represent a part of said solution.

The PublicKey is intended to be shared publicly, such as stored on GitHub for future authentication attempts. The PrivateKey is meant to be stored locally on your machine, and should always be kept secret.

Essentially, when you try to authenticate, these two keys can be used together create a valid solution to the mathematical problem, with minimal computational cost. Meanwhile, because the difficulty of the problem they represent, finding the solution is actually very computationally costly without both keys. Usually, this comes down to simply guessing an unfathomably large number of possible pairs for the "correct" solution.

Types of SSH Keys

Note: Note that there will never be a universally "best" key type, per say, as new key types are being discovered with time. Furthermore, computers are always improving, so keys that "are very secure" right now may not be so in 10 years.

There are multiple SSH Key types, where each key type represents a different mathematical problem.

As of writing this (in year 2020), there appear to be four main types of SSH keys:

  • RSA - Based off the "difficulty of factoring very large numbers".
    • Recommend a minimum strength of 2048 bits. 4096 is preferred for systems that support it.
    • One of the oldest key types, so virtually all devices support it at this point.
  • DSA - Based off the "Discrete Logarithm" problem.
    • Considered essentially equal to RSA as far as security.
    • Faster than RSA in some respects, while slower in others.
  • ECDSA - A specific version of the DSA problem, called the "Elliptic Curve Discrete Logarithm" problem.
    • Keys for this can be much smaller than RSA, while still providing as much security as RSA does.
  • ED25519 - Yet another improvement of ECDSA, using the "Twisted Edwards Curve".
    • Once again, can use smaller key sizes while being as secure as RSA.
    • Has the added benefit of being very fast to verify if you have both keys.
    • Generally newer than other key types, so not all devices/systems support it yet (even if most do by this point).

Generally speaking as of writing this, it seems ED25519 is the preferred type, with RSA as a fallback for systems that don't yet support ED25519.

Generating SSH Keys

As stated above, it's currently best to try an ED25519 key first. If it's not supported by your system yet, then fallback to RSA of at least 2048 bits.

Creating an ED25519 Key:

ssh-keygen -t ed25519 -C "<your_email>"

Creating a RSA Key:

ssh-keygen -o -t rsa -b <bit_length> -C "<your_email>"
  • <bit_length> - Specifies a key bit length of either 2048, 3072, or 4096. Generally higher is better.


Either of the above commands will start the process to create a new key pair.

  • Hit enter to use the default path. Alternatively, retype the path and change the id_rsa to a filename of your choice.
    • If you change the filename, make it something useful and descriptive.
    • For example, if making a RSA key for GitHub, it might be good to change the name to something like github_rsa.
    • This allows you to have multiple keys, where each key corresponds to a different service or use case.


Connecting Via SSH

Connecting via SSH can be as simple as a single command, at least if authenticating via username + password:

ssh <username>@<server_name_or_ip>


If connecting via an SSH Key, then you probably want to Use a Config file.

Once the config file is set up, then you can connect with:

ssh <config_Host_value>


SSH Config Files

It's possible to create config files for SSH connections. This is particularly recommended when regularly connecting to different servers/repositories on a single machine.

Config file should be located at ~/.ssh/config.

Syntax is (generally) as follows:

Host <corresponding_value>
    HostName <corresponding_value>
    <ssh_option> <corresponding_value>

Comments can also be added with #.


Possible options are as follows:

  • Host - Required. Can be any arbitrary value. This is what is typed locally to call this specific SSH configuration.
    • Generally, this is either the same as HostName or an abbreviation of such. But in reality, you can think of it as an alias.
  • HostName - Required. This is the actual address to connect to.
    • Ex: An IP address if connecting to a production server. Or "github.com" if connecting to GitHub. Etc.
  • Port - Required if port is not 22. Self explanatory.
  • User - The username to try to authenticate with, on the server itself.
    • If not provided, then attempts to use the name of the local user invoking the ssh call.
  • PreferredAuthentications - Specifies the order which the client should attempt to authenticate with. Most common options are publickey or password.
  • IdentitiesOnly - Indicates if attempts to connect to the Hostname should ONLY use keys indicated in the config file. See below section for further details.
  • IdentityFile - If applicable, the file to attempt to authenticate through.
    • Ex: In the below examples, we use a github_rsa key and a bitbucket_ed2 key, respectively.


Config File Example

Shows a good example of how a full config may generally look.

# GitHub repo connection.
Host github
    User git
    Hostname github.com
    Port 22
    PreferredAuthentications publickey
    IdentitiesOnly yes
    IdentityFile /home/my_user/.ssh/github_rsa


# BitBucket repo connection.
Host bitbucket
    User my_user
    Hostname bitbucket.org
    Port 22
    PreferredAuthentications publickey
    IdentitiesOnly yes
    IdentityFile /home/my_user/.ssh/bitbucket_ed2


On Using IdentitiesOnly

From manual testing, this arg doesn't seem to harm anything as long as you define all your connections in the config file. With this in mind, then it seems to be best to always set `IdentitiesOnly yes` for every entry in the config. Then just make sure to always add new entries into your config, every time there's a new ssh authentication you need (frankly, you should be always adding to the config anyways, it's just easier in the long run).

Think of the following edge-case scenarios:


Scenario 1 - You want to connect to some site with ssh, but using a password and not a generated ssh key

This is fine, set everything as needed similar to the above examples. The only difference being that you won't need the `IdentityFile` line (you want to provide a password, not provide a key), and that you want to set PreferredAuthentications password.


Scenario 2 - You want to connect to a site to access repos on two or more different accounts (such as github)

Because you're connecting to repos, and not as a full ssh authentication login, you can't specify the user account in the config (it uses `git` as a base value for username)


Short Answer: IdentitiesOnly yes accounts for this.


Long Answer: Every time you try to authenticate, your ssh might actually send multiple different auth attempts, when multiple sets of credentials match the Hostname. (To Verify, you can try to connect with extra-verbose ({ic |-vvv}} flag) prior to adding the `IdentitiesOnly` line). In essence, ssh does not magically know how it's meant to connect unless you tell it. So it might try to incorrectly guess and lead to behavior that "seems dumb" to you as the end user. Such as trying to prompt for a password when the proper entry is clearly in the config.


By setting the IdentitiesOnly yes line, you're telling ssh "this connection to the HostName is definitely defined in here, even if the first one or two you try end up wrong." So it will only try values explicitly in the config file, and give up if has exhausted all applicable config entries.

Note: If you have many different accounts to a single host (three accounts, four, or even more), then it's possible this method won't be enough either. Even when forced to only try specific config entries, it still might run out of authentication attempts and error before getting to the "correct one". See https://superuser.com/a/272613 for more information in that case. But if you only have two or maybe three accounts to a single hostname, then most likely it will work just by setting the IdentitiesOnly yes line.


Scenario 3 - You have many entries (15+) in your config file

I'm not sure of the exact point this starts happening, but there are some instances when ssh config credentials start being problematic, once you have too many entries in your config.


Now this might have been fixed, it was last observed in 2021 or so. But at least at the time, after a certain threshold of config entries, you might start getting prompts to enter a password, despite having a proper config entry defined and wanting to connect password-less. Or alternatively, you might get an authentication error, despite having a properly defined config entry.


Basically, the reason for this is kind of similar to above Scenario 2, only this case seems to be more of a bug, where the number of config entries makes behavior stupid, and it starts trying entries where the HostName doesn't actually make sense.


In either case, setting the IdentitiesOnly yes line seems to fix this, as it forces ssh to only check values explicitly defined in the config.


Passing Your PubKey to the Remote Service

Essentially, this allows secure connections via your credentials, without having to enter your password anymore. It's generally considered more secure, and thus recommended.

Setting Up Keys for Remote Repositories

This allows connect to things like GitHub and Gitlab, and to pull and push repositories of code easier.

The process is generally fairly straightforward:

  • First, log into the associated website, and find the page to upload SSH Keys for your user account.
  • After Generating a SSH Key, find the newly created PublicKey location.
    • On Linux, the default location will be something like ~/.ssh/<key_name>.pub.
  • Copy the full contents of the PublicKey file, and paste it into the box on the website.
  • Give a meaningful title if provided an option to. Ex: Home_Desktop_GitHub.
  • Save and Test Your SSH Key.

Testing SSH Keys

For remote repositories, they usually have a built in method to test your key once uploaded.

Usually, this is done via terminal, via something like ssh -T git@<website>.

  • Ex: To test a key on GitHub, you would use ssh -T git@github.com.
  • To troubleshoot, you can add the -v, -vv, or -vvv flags, where each one provides a little bit more information.

Setting up Password-less Server Credentials

This allows you to remote into a server (via Terminal) without entering your password every time.

First, you'll need to be able to make SSH connections using passwords. If not already enabled on the server, then enable it with the following:

  • Note that this requires enabling at least one user that can log in with a standard password. AWS EC2, for example, does not create such a user by default.
  • Edit the file /etc/ssh/sshd_config.
  • Update the line PasswordAuthentication to yes.
  • Restart the service with sudo service ssh restart.

Next, pass your public key to the server with the command:

ssh-copy-id -i <public_key_to_pass> <server_address>

Test that it works by connecting to the server with ssh. It should connect without asking for a password.

Finally, disable ssh connections with passwords to make the server more secure:

  • Edit the file /etc/ssh/sshd_config.
  • Update the line PasswordAuthentication to no.
  • Restart the service with sudo service ssh restart


SSH not Prompting for Password

https://askubuntu.com/a/419562