Reputation: 1503
My docker-compose.yml
file creates a service api
listening on port 9000
and a remote server 123.1.2.3
needs to access it. An SSH tunnel is required because there is a firewall preventing direct access to the Docker host port 9000.
version: "3.9"
services:
api:
image: my/api-service:latest
ports:
- "9000:9000"
I'm currently manually creating this SSH tunnel by running this command on the Docker host
ssh -fN -R 9000:127.0.0.1:9000 [email protected]
Is it possible to create another service in this docker-compose.yml
file to create this SSH tunnel on running docker-compose up
, using a SSH private key in the same directory as the docker-compose.yml
file?
Upvotes: 0
Views: 2128
Reputation: 158647
This should be possible. Looking at a copy of the ssh(1) man page, the ssh -R
option sets up a port forward from the remote machine back to the local machine
ssh -R port:host:hostport
where port
on the remote host is forwarded through the ssh tunnel, making outbound connections to host:hostport
from the local system.
In your case, if the ssh tunnel was launched from a container, you could use normal Docker networking, and connect to api:9000
, using the standard port number of the container.
The first thing you'll need is an image with the ssh client. This is easy enough to build from source, so we'll do that
FROM ubuntu:22.04
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive \
apt-get install --no-install-recommends --assume-yes openssh-client
Do not copy the ssh keys into the image. Anything that's in an image can be trivially extracted later, and you don't want to compromise your ssh keys this way.
Instead, we'll bind mount our ssh keys into the container when it runs. ssh is extremely particular about the permissions of the ssh keys, so you need to make sure the container runs as the same numeric user ID as on your host system. Run
id -u
and remember that number (on an Ubuntu system, it might be 1000).
Now, in the Compose file, in addition to the original server, we need to
version: '3.8'
services:
api:
image: my/api-service:latest
# ports: ['9000:9000'] # optional
tunnel:
build:
context: .
dockerfile: Dockerfile.ssh
user: 1000
volumes:
- /home/yourname/.ssh:/home/.ssh
environment:
HOME: /home
command: ssh -N -R 9000:api:9000 [email protected]
In the last line the first 9000
is the port number on the remote system, and api:9000
is the container name and standard port number for the target container. ports:
would also publish the port on the local system and aren't required (or considered) for connections between containers. I've omitted the ssh -f
option so that the ssh tunnel runs as a foreground process, as the only process in its container.
Upvotes: 2