Is there a way to use a previously specified ssh-config entry in specifying `Hostname`? - ssh

edit: I have seen cases where this works and cases where this doe not and I'm not sure I follow when/why it does.
Suppose I have a complicated enough entry where I specify multiple parameters to get to thathost:
Host thathost
ControlMaster auto
ServerAliveInterval 8
ConnectTimeout 8
Hostname 192.168.5.1
User mememe
ProxyJump thejumpbox
I want to re-use this definition in creating additional entries that provide different functionality by adding or overriding some configs. Specifically specifying an alternate port (no, I don't want it on the command-line).
Ideally I'd be able to do something like
Host theirhost
Hostname thathost
User themthem
or
Host my-remote-serialport
Hostname thathost
RequestTTY yes
RemoteCommand some-script-that-launches-kermit-on-a-specific-dev-tty
or
Host my-remote-serialport
Hostname thathost
Port 3004
I'm strictly looking to specify one host in terms of another existing one, I'm not looking to modify my Host entries to match some pattern "tricks".
Obviously I can utilize ProxyCommand ssh -q nc thathost... or ProxyJump thathost +Hostname localhost followed by all the other overrides (well for port override would pass that to nc) but that's both ugly and wasteful (an extra session) - please don't answer with that.
For me this has been the missing feature of ssh-config, but maybe I did not look hard enough.

It can't be used in the way you asked, like reuse a hostname definition, but the provided solution of ssh can solve much more problems.
A host rule can span multiple hosts.
Host thathost theirhost my-remote-serialport
ControlMaster auto
ServerAliveInterval 8
ConnectTimeout 8
Hostname 192.168.5.1
User mememe
ProxyJump thejumpbox
But obviously this doesn't solve your problem with modifying some properties.
The trick is, that the ssh config uses the first wins strategy for properties.
In your case you just has to add the modifications in front of the main config
Host theirhost
Hostname thathost
User themthem
Host my-remote-serialport
Hostname thathost
Port 3004
Host thathost theirhost my-remote-serialport
ControlMaster auto
ServerAliveInterval 8
ConnectTimeout 8
Hostname 192.168.5.1
User mememe
ProxyJump thejumpbox
theirhost is defined at two places, the properties Hostname and User are taken from the first definition, all other properties from the second definition.
The host part also accepts wildcards, example for a jumpbox with multiple reverse ssh endpoints:
HOST my_1
port 2001
HOST my_2
port 2002
HOST my_3
port 2003
HOST my_*
user pi
hostname localhost
ProxyJump thejumpbox

There's no way to reference a different block; however, you can include a specific configuration file that has a global configuration. For example, create a file meant for use by thathost, theirhost, and my-remote-serialport. Let's just call it foo-config.
ControlMaster auto
ServerAliveInterval 8
ConnectTimeout 8
Hostname 192.168.5.1
User mememe
ProxyJump thejumpbox
Then you can use the Include directive to read this in as needed:
Host theirhost
Include foo-config
User themthem
Host my-remote-serialport
Include foo-config
RequestTTY yes
RemoteCommand some-script-that-launches-kermit-on-a-specific-dev-tty
Host my-remote-serialport
Include foo-config
Port 3004
However, I suspect this approach is rarely necessary, and the approach given by jeb will probably be sufficient in most cases.

Related

SSH Config ProxyJump - Port forwarding from proxy

i have a question regarding port forwarding in combination with proxy jump in my ssh config:
Is it possible to make use of DynamicForward from the host used as proxy? Here's my config:
Host proxy
HostName proxy.private.com
User user
IdentityFile ~/path/to/file
DynamicForward 3000
Host target
HostName target.somewhere.com
User user
IdentityFile ~/path/to/file
ProxyJump proxy
It does not work with this config, but this would be exactly what i need.
Any tips on how to get it to work?
If there is nothing preventing you from using ProxyCommand you can most likely use this approach:
In your ~/.ssh/config file:
Host target
HostName target.somewhere.com
User target-user
IdentityFile ~/path/to/target-user-file
ProxyCommand ssh -A <proxy-user>#<proxy-host> -i <proxy-user-key> -W %h:%p
DynamicForward 3000
You can then run this command on your local machine:
ssh target -D 3000
I was able to test this by running this command locally and retreiving public IP of the target host:
curl -x socks5h://localhost:3000 https://ifconfig.me/
Usefull links I read:
More details on these use cases can be found here
Detail on this very approach can be found on this site (sadly not in english nor HTTPS)
You can probably define another Host on top to avoid having to mess with ssh parameter each time. This would be done by using CanonicalizeHostname, but I couldn't manage to it. An alias might be more interesting at that point ?

CanonicalHostname and ssh connections through a jumphost

Say I have an internal subdomain named internal.sub.domain.net with hosts like foo.internal.sub.domain.net and bar.internal.sub.domain.net. Furthermore, these hosts are only accessible from the outside world through the jumphost internal.sub.domain.net. Thus, the following ~/.ssh/config allows me to directly connect to either of the internal hosts from outside:
Host foo bar
HostName %h.internal.sub.domain.net
ProxyJump internal.sub.domain.net
This is fine for a subdomain with just only a couple of hosts, but it quickly becomes rather unmaintainable if the number of hosts is large and / or changes occasionally. But wildcards may come to the rescue:
Host *.internal.sub.domain.net
ProxyJump internal.sub.domain.net
This avoids the maintenance issue, but forces to always specify the fully qualified hostname to connect, which is rather tedious. From looking at the ssh_config man-page, the CannonicalizeHostname and CannonicalDomains options seems to fix that:
CannonicalizeHostname always
CannonicalDomains internal.sub.domain.net
Host *.internal.sub.domain.net
ProxyJump internal.sub.domain.net
But this would only work if the name lookup for the host that is to be connected succeeds. But as these hosts are internal by definition, it is no surprise that name resolution fails.
A not really helpful but very illustrative hack is to fake successful name resolutions by just adding all the internal hosts as aliases for e.g. 127.0.0.1 to /etc/hosts, i.e. adding the following line to /etc/hosts:
127.0.0.1 foo.internal.sub.domain.net bar.internal.sub.domain.net
With that line in place, the last ~/.ssh/config works like a charm. But apart from the fact that this would be quite a hack, it just only shifts the maintenance issue form ~/.ssh/config to /etc/hosts.
As the described scenario should not be so uncommon, is there a way to make it work? To phrase it in one sentence again:
I want to be able to ssh to all internal hosts that live in the internal.sub.domain.net, i.e. that are only accessible through the internal.sub.domain.net jumphost without having to list each of these hosts somewhere, as they may frequently be added or removed from the internal domain and without being forced to always type their fully qualified hostnames.
If you are invoking ssh from a shell, you could define a short variable for the internal domain and append that to the relevant hostnames:
e.g. in your ~/.bashrc or similar:
i=".internal.sub.domain.net"
Then, on the command line:
ssh foo$i
ssh bar$i
At least until a better solution comes along. It's not perfect but it's only 2 extra characters on the command line.
Update: A better solution has come along.
A better solution, by Peter Stuge on the openssh mailing list, is to have something like this in your config file:
Host *.i
ProxyCommand ssh -W %hnternal.sub.domain.net:%p jumphost
This enables the use of abbreviated hostnames like foo.i (rather than foo$i in my first answer). Being able to use . rather than $ is better because it doesn't require the use of the shift key.
However, this is limited to a single remote jumphost whose internal domain starts with i. I think that internal domains that start with internal. are common. If you need to connect to multiple such internal domains, the above needs a slight (but very ugly) tweak. I apologize in advance if anyone's eyes start to bleed.
For example, if you need to connect to these internal domains:
internal.a.com
internal.b.net
Then the above needs to be changed to something like this:
Host *.a
ProxyCommand sh -c "H=%h; exec sh -c \"exec ssh -W \${H%%.a}.internal.a.com:%p jumphosta\""
Host *.b
ProxyCommand sh -c "H=%h; exec sh -c \"exec ssh -W \${H%%.b}.internal.b.net:%p jumphostb\""
Believe me, I wish it could be simpler but that's the shortest thing that I could get to work (without using a separate shell script or environment variables).
If a username is supplied on the command line, it only applies to the jumped-to host. Your local username will be used by default for the jumphost.
If you need to use a username for the jumphost that isn't the same as your local username, add it in the ProxyCommand (e.g. jumpuser#jumphosta).

How to configure Ansible to use my local SSH configuration?

I'm testing out Ansible and am already stuck on a fairly simple thing. I configured my /etc/ansible/hosts to contain the IP of my server:
[web]
1.2.3.4
Now, connecting to it with ansible all -vvvv -m ping fails since my ~/.ssh/config for the specified server uses a custom port, a key file not in the default location, etc. How do I tell Ansible to reuse my SSH configuration for the connection?
It's a little esoteric, so it's understandable you missed it. This is from the Ansible Inventory page:
If you have hosts that run on non-standard SSH ports you can put the port number after the hostname with a colon. Ports listed in your SSH config file won’t be used with the paramiko connection but will be used with the openssh connection.
To make things explicit, it is suggested that you set them if things are not running on the default port
So, in your case:
[web]
1.2.3.4:9000
(Using 9000 as your alt port, of course)
Ansible uses paramiko on systems with a dated version of ssh, such as CentOS/RHEL.
What tedder42 said plus there are other slightly more advanced ways of defining your ssh config on a per host basis.
[web]
1.2.3.4 ansible_ssh_port=9000
This only makes sense if you're also using the other ansible_ssh special variables like ansible_ssh_user and ansible_ssh_host.
ansible_ssh_host is helpful if you want to be able to refer to a server by a name of your choosing instead of its IP.
[web]
apache ansible_ssh_host=1.2.3.4 ansible_ssh_port=9000
If you end up with multiple hosts with the same alternative ssh port you can makes use of Ansible's group variable function.
[web]
1.2.3.4
5.6.7.8
9.10.11.12
[web:vars]
ansible_ssh_port=9000
Now Ansible will use port 9000 on all three of the hosts In the web group.
Understanding how to organize your inventory data goes a long way to your success with Ansible.

How to add socks proxy to ssh config file?

I know how to forward SOCKS proxy on the command like below
ssh -D port_number user#host
This works well but I want to be able to put that forwarding into my SSH config file. But I am not able to locate any useful information or tutorial about.
I have bunch of normal SSH profiles in the config so I prefer to have the forwardings attached to the SSH profiles.
Use the config setting "DynamicForward" Here is a quick example of what it should look like:
Host example.com
User username
DynamicForward 8080
If the DynamicForward option is only given a port number, then it will bind to localhost:port.
You can add a specific IP to get it to bind to an address other than the localhost. Using "*:8080" will bind the proxy to all IP addresses on the box.
To use an IPv6 address enclose the address in square brackets:
[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8080
For details, please see the ssh_config man page (type man ssh_config).
I do not recommend use socat because it only support socks4
But you can use ncat
install ncat
add this in your ssh config file ProxyCommand ncat --proxy-type socks5 --proxy 127.0.0.1:1080 %h %p
You may need to check ncat options if it does not work.
This is how it is done:
Host server-fwd
Hostname a.b.c.d
User username
Port 22
LocalForward localhost:AAAA localhost:DD
LocalForward localhost:BBBB localhost:EEE
LocalForward localhost:CCCC localhost:FFFF
Change the "server-fwd" to whatever name you like, change "a.b.c.d" to the IP you're connecting to, change "username" to whatever your account is, maybe change the port number if necessary.
The LocalForward lines are the ones you have been looking for. The middle column (i.e. AAAA, BBBB and CCCC) are the ports on the system you are running the ssh command from. The right column (i.e. DD, EEE and FFFF) are the ports on the server you're connecting to. It's localhost in both cases because in the first case it's when the ssh command is run locally and in the second case it is relative to the server you just logged into.
Yes, I use this a lot. ;)

gitolite with non-default port

To clone a repository managed by gitolite one usually uses following syntax
git clone gitolite#server:repository
This tells the SSH client to connect to port 22 of server using gitolite as user name. When I try it with the port number:
git clone gitolite#server:22:repository
Git complains that the repository 22:repository is not available. What syntax should be used if the SSH server uses a different port?
The “SCP style” Git URL syntax (user#server:path) does not support including a port. To include a port, you must use an ssh:// “Git URL”. For example:
ssh://gitolite#server:2222/repository
Note: As compared to gitolite#server:repository, this presents a slightly different repository path to the remote end (the absolute /repository instead of the relative path repository); Gitolite accepts both types of paths, other systems may vary.
An alternative is to use a Host entry in your ~/.ssh/config (see your ssh_config(5) manpage). With such an entry, you can create an “SSH host nickname” that incorporates the server name/address, the remote user name, and the non-default port number (as well as any other SSH options you might like):
Host gitolite
User gitolite
HostName server
Port 2222
Then you can use very simple Git URLs like gitolite:repository.
If you have to document (and or configure) this for multiple people, I would go with ssh:// URLs, since there is no extra configuration involved.
If this is just for you (especially if you might end up accessing multiple repositories from the same server), it might be nice to have the SSH host nickname to save some typing.
It is explained in great detail here: https://github.com/sitaramc/gitolite/blob/pu/doc/ssh-troubleshooting.mkd#_appendix_4_host_aliases
Using a "host" para in ~/.ssh/config lets you nicely encapsulate all this within ssh and give it a short, easy-to-remember, name. Example:
host gitolite
user git
hostname a.long.server.name.or.annoying.IP.address
port 22
identityfile ~/.ssh/id_rsa
Now you can simply use the one word gitolite (which is the host alias we defined here) and ssh will infer all those details defined under it -- just say ssh gitolite and git clone gitolite:reponame and things will work.