SSH – Start to Finish Architecture – Client Config Pt. 1

This week, we’re going to focus on the client side configuration file(s) and how to use them to make ssh a more enjoyable experience. There are a lot of options in the configuration files, so we’re going to break this up into different parts. We’ll cover some common settings people might want to play with for making session handling more efficient, and then after we’ve covered some more advanced topics over the next few weeks, we’ll do a part two to go over some of the more advanced configuration options that mesh with those previously covered topics. This means part two won’t be next week.

There are two default files that handle client side ssh configuration in OpenSSH. The global file is usually found at /etc/ssh/ssh_config, and contains all of the default settings for all users on the system. The user can also write configuration options that override the global config file by including the file “config” inside that user’s .ssh directory. When the ssh client is called, the order of priority when parsing options is covered thusly:

1. command-line options
2. user’s configuration file (~/.ssh/config)
3. system-wide configuration file (/etc/ssh/ssh_config)

This whatever is given on the command line trumps everything else. The user’s config trumps the system-wide config. The system-wide config covers everything not explicitly overridden by the other two. This makes sense, but it’s important to know what the priority of parsing is when troubleshooting issues.

The focus for today will cover the ~/.ssh/config file that should contain customized settings.

One of the first options I set in my own config is the “LogLevel” setting. I prefer to suppress extraneous information (such as banners,) because I like to batch process reports from multiple servers, and I only want the information from the commands I run, not anything else. To suppress these messages, I use:

LogLevel QUIET

You can tune this to whatever level of noise you prefer, all the way up to DEBUG3, which is equivalent to “ssh -vvv” for “verbose debugging.” I don’t recommend using the user config for this, though. Just use the flags to override, and use the config to suppress as above.

The next set of options people often use are the “Match,” “User,” “Host,” and “HostName” settings.
The “User” setting is used to set what the target username to login as should be. This is like going from User_A@Workstation_A to User_B@Server_B scenario we set up before. In this case, setting “User User_B” would mean you could type “ssh Server_B” and it would know to use “User_B” as the target, instead of the default of “User_A.”

The “Host” option sets a block for options that apply to a given hostname until the next “Host” or “Match” block. The name can be a pattern match with wild cards, and can include negation via a preceding “!” if needed. “Host !*.web.com” would say “the following settings up to and not including the next Match or Host block apply to all systems that are NOT like *.web.com.” The previous example is a bad one, but it gets the point across. To set global stuff at the bottom, use a “Host *” option to match everything, and the earlier Match/Host blocks will override as needed, since they have already set values, if something matches them.

The “Match” option is used to fine tune matching against various objects. It can match a username with “Match user” or an address with “Match address” and so on. You can do a “Match host,” but just using “Host” as a block option is probably better for almost all cases.

The “HostName” option lets you set aliases within your config. This would generally be set as an option after a “Host” match. You can use “%h” to indicate the hostname that was passed to ssh on the command line before altering it with the “HostName” so that “HostName” prepends or appends to it as needed. You can also set to this an address to override whatever DNS would have returned, for example.

Using what we’ve learned so far, let’s assume that User_A wants to log in as User_B in almost all cases. However, User_A is an AIX systems administrator, and thus might need to log into a VIO server for virtual IO setup, which means the target user is most likely “padmin” rather than User_A or User_B. Also, AIX is managed by a Hardware Management Console (HMC) which often uses the “hscroot” user, rather than local accounts. Of course, every shop is different, but this is a standard practice, so we’ll go with it. The organization uses a standard naming scheme that all VIO servers have a name that starts with “vio” followed by some unique identifier. The HMCs are similarly named as “hmc” followed by some unique identifier. The VIO servers are also in a different domain than the standard, called ‘internal.net.’ We also know that if the user logs in as root, a key will never be used, so we want to skip the key exchange and force a password for root, instead. Armed with this knowledge, we can make User_A’s life easier if we build out a config that looks like this:

LogLevel QUIET
Host vio*
   HostName “%h.internal.net”
   User padmin
Host hmc*
   User hscroot
Match user root
   PubkeyAuthentication no
   PasswordAuthentication yes
   PreferredAuthentications password
Match user User_B
   PreferredAuthentications publickey,password
Host *
   User User_B

The options we set for the “Match user root” block should be fairly self explanatory at this point. There are many more options than this, and we will cover them eventually, but this is decent general overview of how to build out your config over time. Remember to put your global stuff at the bottom, since it reads top down with first match winning the option to set.