28

Recently OpenSSH on macOS Sierra was upgraded to 7.3p1 which means that the Include config directive is available, hurray!

However I'm having problems actually using it.

I have the following ~/.ssh/config:

Host github.com
Hostname github.com
User git
IdentityFile ~/.ssh/keys/github_rsa

Host den
HostName narzt-desktop.local
User camden
GSSAPIAuthentication no
AddressFamily inet

Host walle
User CamdenNarzt
HostName WALLE.local
AddressFamily inet
GSSAPIAuthentication no

Include ~/.ssh/config.d/*

I saw here that there might be some useful debug output if I added a bunch of -v flags to my ssh commands, yet when I test the config for a host in one of the included files I get this:

$ \ssh -vvvvG git-codecommit.us-east-1.amazonaws.com
OpenSSH_7.3p1, LibreSSL 2.4.1
debug1: Reading configuration data /Users/camdennarzt/.ssh/config
debug3: /Users/camdennarzt/.ssh/config line 31: Including file /Users/camdennarzt/.ssh/config.d/family.conf depth 0 (parse only)
debug1: Reading configuration data /Users/camdennarzt/.ssh/config.d/family.conf
debug3: /Users/camdennarzt/.ssh/config line 31: Including file /Users/camdennarzt/.ssh/config.d/icloud.conf depth 0 (parse only)
debug1: Reading configuration data /Users/camdennarzt/.ssh/config.d/icloud.conf
debug3: /Users/camdennarzt/.ssh/config line 31: Including file /Users/camdennarzt/.ssh/config.d/metabolistics.conf depth 0 (parse only)
debug1: Reading configuration data /Users/camdennarzt/.ssh/config.d/metabolistics.conf
debug3: /Users/camdennarzt/.ssh/config line 31: Including file /Users/camdennarzt/.ssh/config.d/scanimetrics.conf depth 0 (parse only)
debug1: Reading configuration data /Users/camdennarzt/.ssh/config.d/scanimetrics.conf
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 20: Applying options for *
debug1: /etc/ssh/ssh_config line 56: Applying options for *
user camdennarzt
hostname git-codecommit.us-east-1.amazonaws.com
port 22
addressfamily any
batchmode no
canonicalizefallbacklocal yes
canonicalizehostname false
challengeresponseauthentication yes
checkhostip yes
compression no
controlmaster false
enablesshkeysign no
clearallforwardings no
exitonforwardfailure no
fingerprinthash SHA256
forwardagent no
forwardx11 no
forwardx11trusted no
gatewayports no
gssapiauthentication no
gssapidelegatecredentials no
hashknownhosts no
hostbasedauthentication no
identitiesonly no
kbdinteractiveauthentication yes
nohostauthenticationforlocalhost no
passwordauthentication yes
permitlocalcommand no
protocol 2
proxyusefdpass no
pubkeyauthentication yes
requesttty auto
rhostsrsaauthentication no
rsaauthentication yes
streamlocalbindunlink no
stricthostkeychecking ask
tcpkeepalive yes
tunnel false
useprivilegedport no
verifyhostkeydns false
visualhostkey no
updatehostkeys false
canonicalizemaxdots 1
compressionlevel 6
connectionattempts 1
forwardx11timeout 1200
numberofpasswordprompts 3
serveralivecountmax 3
serveraliveinterval 0
ciphers [email protected],aes128-ctr,aes192-ctr,aes256-ctr,[email protected],[email protected],aes128-cbc,aes192-cbc,aes256-cbc,3des-cbc
hostkeyalgorithms [email protected],[email protected],[email protected],[email protected],[email protected],ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa
hostbasedkeytypes [email protected],[email protected],[email protected],[email protected],[email protected],ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa
kexalgorithms [email protected],ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha256,diffie-hellman-group14-sha1
loglevel DEBUG3
macs [email protected],[email protected],[email protected],[email protected],[email protected],[email protected],[email protected],hmac-sha2-256,hmac-sha2-512,hmac-sha1
pubkeyacceptedkeytypes [email protected],[email protected],[email protected],[email protected],[email protected],ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa
xauthlocation /opt/X11/bin/xauth
identityfile ~/.ssh/id_rsa
identityfile ~/.ssh/id_dsa
identityfile ~/.ssh/id_ecdsa
identityfile ~/.ssh/id_ed25519
canonicaldomains
globalknownhostsfile /etc/ssh/ssh_known_hosts /etc/ssh/ssh_known_hosts2
userknownhostsfile ~/.ssh/known_hosts ~/.ssh/known_hosts2
sendenv LANG
sendenv LC_*
connecttimeout none
tunneldevice any:any
controlpersist no
escapechar ~
ipqos lowdelay throughput
rekeylimit 0 0
streamlocalbindmask 0177

(Ignore the line numbers in the first bit, I deleted some comments to save space in the question) The user should be the user specified in the ~/.ssh/config.d/metabolistics.conf file, and the identity file should likewise be the one specified in the included config file. I can't post the contents of the ~/.ssh/config.d/metabolistics.conf file, but it's format is exactly the same as the main ~/.ssh/config file but without any further includes.

I checked the permissions and they look fine to me:

$ ls -lhRa ~/.ssh/config* 
-rw-------  1 camdennarzt  staff   541B  1 Jan 14:22 /Users/camdennarzt/.ssh/config

/Users/camdennarzt/.ssh/config.d:
total 32
drwxr-xr-x  6 camdennarzt  staff   204B  1 Jan 14:37 .
drwx------  9 camdennarzt  staff   306B  1 Jan 14:22 ..
-rw-------  1 camdennarzt  staff   260B  1 Jan 14:16 family.conf
-rw-------  1 camdennarzt  staff   303B  1 Jan 14:17 icloud.conf
-rw-------  1 camdennarzt  staff   524B  1 Jan 14:15 metabolistics.conf
-rw-------  1 camdennarzt  staff   1.6K  1 Jan 14:15 scanimetrics.conf

4 Answers 4

52

Figured it out myself. The clue was in the ssh_config man page:

Include

Include the specified configuration file(s). Multiple pathnames may be specified and each pathname may contain glob(3) wildcards and, for user configurations, shell-like ``~'' references to user home directories.

Files without absolute paths are assumed to be in ~/.ssh if included in a user configuration file or /etc/ssh if included from the system configuration file. Include directive may appear inside a Match or Host block to perform conditional inclusion.

I had my Include statement trailing a Host directive so it was being included into that Host's config.

5
  • 18
    In other words the Include directive must go to the top of the config file (before the "body" made of Host blocks)
    – lucianf
    Aug 6, 2018 at 12:13
  • 3
    Thanks, while that does follow from the docs it isn't immediately obvious when trying to figure out why a config isn't working :)
    – larsks
    Oct 15, 2018 at 2:09
  • @larsks Agree, wasted so many hours debugging because of this rule.
    – mss
    Oct 14, 2021 at 20:43
  • How does "Include directive may appear inside a Match or Host block to perform conditional inclusion." imply "Include must go at the top of the file in order to wortk"?
    – Alecz
    Dec 15, 2021 at 14:54
  • 2
    Indenting the Host/Match blocks with a TAB really helps debugging, and also remembering that the only global statements are the start of a file, everything after the first block belongs to a block (that's why you need Match all or Host * for trailing statements)
    – MestreLion
    Jun 3, 2023 at 23:28
17

You can leave the Include statement at the end of the file if you precede it with Match all. This terminates the previous Host/Match, and then conditionally always includes the file(s). So, the file would end with:

Match all
Include config.d/*
1
  • 1
    As an aside, only lines starting with # or empty lines count as comments; you can't put a comment on the same line as Match or Host.
    – Iiridayn
    Apr 17, 2020 at 0:18
4

Actually no.

It's a short-circuit bug in the SSHCONF_NEVERMATCH flag's use.

I'm working on diffs to fix the mess. Includes should be able to go anywhere (and also be recursive) be it main body or inside a Host|Match block.

The only tricky bit is knowing when you've unrolled the stack of read_config_file_depth() and can resume processing Host|Match again.

I'll be posting to my branch when I have something.

-1

The main configuration file is probably:

CheckHostIP yes
Host *
[Indent] [Here are some global configurations required by all hosts]
[line break]
Host github.com
[Indent][Some configurations]
[line break]
Include other configuration files

The contents of other configuration files are:

Host specific host name
[indent] Configuration of this host

At this time, other configuration files cannot take effect. If you change the main configuration file to:

CheckHostIP yes
Host *
[Indent] [Here are some global configurations required by all hosts]
[line break]
Include other configuration files
[line break]
Host github.com
[Indent][Some configurations]

Or:

CheckHostIP yes
Include other configuration files
Host *
[Indent] [Here are some global configurations required by all hosts]
[line break]
Host github.com
[Indent][Some configurations]
[line break]

or:

CheckHostIP yes
Host *
[Indent] [Here are some global configurations required by all hosts]
[line break]
Host github.com
[Indent][Some configurations]
[line break]
Match all
Include other configuration files

Then the global configuration and other configuration files can take effect.

And as @mestrelion said, I had added indent already, but it is no effect, useless for debugging...Hummmmmm...

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .