Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

access host's ssh tunnel from docker container

Using ubuntu tusty, there is a service running on a remote machine, that I can access via port forwarding through an ssh tunnel from localhost:9999.

I have a docker container running. I need to access that remote service via the host's tunnel, from within the container.

I tried tunneling from the container to the host with -L 9000:host-ip:9999 , then accessing the service through 127.0.0.1:9000 from within the container fails to connect. To check wether the port mapping was on, I tried nc -luv -p 9999 # at host nc -luv -p 9000 # at container

following this, parag. 2 but there was no perceived communication, even when doing nc -luv host-ip -p 9000 at the container

I also tried mapping the ports via docker run -p 9999:9000 , but this reports that the bind failed because the host port is already in use (from the host tunnel to the remote machine, presumably).

So my questions are

1 - How will I achieve the connection? Do I need to setup an ssh tunnel to the host, or can this be achieved with the docker port mapping alone?

2 - What's a quick way to test that the connection is up? Via bash, preferably.

Thanks.

like image 880
npit Avatar asked Aug 25 '16 11:08

npit


3 Answers

Using your hosts network as network for your containers via --net=host or in docker-compose via network_mode: host is one option but this has the unwanted side effect that (a) you now expose the container ports in your host system and (b) that you cannot connect to those containers anymore that are not mapped to your host network.

In your case, a quick and cleaner solution would be to make your ssh tunnel "available" to your docker containers (e.g. by binding ssh to the docker0 bridge) instead of exposing your docker containers in your host environment (as suggested in the accepted answer).

Setting up the tunnel:

For this to work, retrieve the ip your docker0 bridge is using via:

ifconfig

you will see something like this:

docker0   Link encap:Ethernet  HWaddr 03:41:4a:26:b7:31  
          inet addr:172.17.0.1  Bcast:172.17.255.255  Mask:255.255.0.0

Now you need to tell ssh to bind to this ip to listen for traffic directed towards port 9000 via

ssh -L 172.17.0.1:9000:host-ip:9999

Without setting the bind_address, :9000 would only be available to your host's loopback interface and not per se to your docker containers.

Side note: You could also bind your tunnel to 0.0.0.0, which will make ssh listen to all interfaces.

Setting up your application:

In your containerized application use the same docker0 ip to connect to the server: 172.17.0.1:9000. Now traffic being routed through your docker0 bridge will also reach your ssh tunnel :)

For example, if you have a "DOT.NET Core" application that needs to connect to a remote db located at :9000, your "ConnectionString" would contain "server=172.17.0.1,9000;.

Forwarding multiple connections:

When dealing with multiple outgoing connections (e.g. a docker container needs to connect to multiple remote DB's via tunnel), several valid techniques exist but an easy and straightforward way is to simply create multiple tunnels listening to traffic arriving at different docker0 bridge ports.

Within your ssh tunnel command (ssh -L [bind_address:]port:host:hostport] [user@]hostname), the port part of the bind_address does not have to match the hostport of the host and, therefore, can be freely chosen by you. So within your docker containers just channel the traffic to different ports of your docker0 bridge and then create several ssh tunnel commands (one for each port you are listening to) that intercept data at these ports and then forward it to the different hosts and hostports of your choice.

like image 146
B12Toaster Avatar answered Oct 20 '22 13:10

B12Toaster


on MacOS (tested in v19.03.2),

1) create a tunnel on host

ssh -i key.pem username@jump_server -L 3336:mysql_host:3306 -N

2) from container, you can use host.docker.internal or docker.for.mac.localhost or docker.for.mac.host.internal to reference host.

example,

mysql -h host.docker.internal -P 3336 -u admin -p

note from docker-for-mac official doc

I WANT TO CONNECT FROM A CONTAINER TO A SERVICE ON THE HOST

The host has a changing IP address (or none if you have no network access). From 18.03 onwards our recommendation is to connect to the special DNS name host.docker.internal, which resolves to the internal IP address used by the host. This is for development purpose and will not work in a production environment outside of Docker Desktop for Mac.

The gateway is also reachable as gateway.docker.internal.

like image 45
prayagupa Avatar answered Oct 20 '22 12:10

prayagupa


I think you can do it by adding --net=host to your docker run. But see also this question: Forward host port to docker container

like image 20
Matthew Avatar answered Oct 20 '22 12:10

Matthew