Why are rules not combining in an ssh config file?
From the ssh_config
man page:
For each parameter, the first obtained value will be used. The configuration files contain sections separated by “Host” specifications, and that section is only applied for hosts that match one of the patterns given in the specification. The matched host name is the one given on the command line.
Since the first obtained value for each parameter is used, more host-specific declarations should be given near the beginning of the file, and general defaults at the end.
Additionally I'd make sure I understand these 2 sections if you're unclear how the Host and PATTERNS function. There is only 1 level of matching going on. This facility is very basic in its regex capabilities, but is still powerful once you grok it.
Host sections
The possible keywords and their meanings are as follows (note that keywords
are case-insensitive and arguments are case-sensitive):
Host Restricts the following declarations (up to the next Host keyword)
to be only for those hosts that match one of the patterns given
after the keyword. If more than one pattern is provided, they
should be separated by whitespace. A single ‘*’ as a pattern can
be used to provide global defaults for all hosts. The host is the
hostname argument given on the command line (i.e. the name is not
converted to a canonicalized host name before matching).
A pattern entry may be negated by prefixing it with an exclamation
mark (‘!’). If a negated entry is matched, then the Host entry is
ignored, regardless of whether any other patterns on the line
match. Negated matches are therefore useful to provide exceptions
for wildcard matches.
See PATTERNS for more information on patterns.
PATTERNS
A pattern consists of zero or more non-whitespace characters, ‘*’ (a
wildcard that matches zero or more characters), or ‘?’ (a wildcard that
matches exactly one character). For example, to specify a set of
declarations for any host in the “.co.uk” set of domains, the following
pattern could be used:
Host *.co.uk
The following pattern would match any host in the 192.168.0.[0-9] network
range:
Host 192.168.0.?
A pattern-list is a comma-separated list of patterns. Patterns within
pattern-lists may be negated by preceding them with an exclamation
mark (‘!’). For example, to allow a key to be used from anywhere within an
organisation except from the “dialup” pool, the following entry
(in authorized_keys) could be used:
from="!*.dialup.example.com,*.example.com"
Layering rules
The problem with your approach is that the pattern that matches the 1st Host section doesn't match the 2nd. I typically do something like this:
Host *
User myuser
IdentityFile ~/.ssh/myidentity
Host blah
HostName complicated.hostname.com
One thing that people don't usually pick up on with these rules is that they can repeat. So what I often times do is have multiple sections and I break them up using Host *
's.
Host *
User user1
Host blah1
HostName complicated1.hostname.com
Host blah2
HostName complicated2.hostname.com
Host *
User user2
SSH applies all the sections that match the hostname as provided on the command line (ie. the HostName
rules it encounters do not affect subsequent conditions checks). If CanonicalizeHostname
is enabled, it will reapply the configuration files again when it is finished, using the updated hostname. (Some SSH versions did this regardless of CanonicalizeHostname
and your example would work with those versions; but that's considered a bug by the SSH devs. See #2267.)
Which means you can use CanonicalizeHostname
to make your example work, by adding
Host *
CanonicalizeHostname yes
CanonicalizeFallbackLocal no
which will not do any canonicalization but will enable doing a second pass with the updated hostname. (Note that it will still not make the configuration parsing "recursive", just repeat it once. So if you change the hostname twice, that wouldn't work.)