Docker containers can simplify the deployment of small services or monoliths. Docker, mostly, provides a lightweight and portable solution that can run on any system. But sometimes either to debug or fix a mess, one might have to access the container directly. While containers are designed to be self-contained and isolated, there are ways to access the container’s shell. To know more about docker, you can read here.
Can you ssh into a docker container? Yes, but should you?
That will depend on the constraint levied on your system. Each solution has its mix of security and ease of access. In this article, we will cover 3 ways to ssh into a docker container.
The easiest way to access a live container would be to use docker exec
.
$ docker exec -it <container-id> /bin/bash
root@<container-id>:/#
# If you do not know the container id your container
# list out the running container like so:
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
85d84ef9dc32 postgres:11.3 "docker-entrypoint.s…" 2 days ago Up About an hour 0.0.0.0:5432->5432/tcp, :::5432->5432/tcp article_test_1
This is the recommended method for accessing the container. It's secure, simple, and traceable via Docker logs. However, in some cases, a container may disable access via bash
or sh
, or you may not have access to the docker-host
. In such situations, you can always fall back on the traditional method of using ssh.
While docker exec
is the recommended way, SSH also has its place. Access via SSH is necessary for testing infrastructure automation or provisioning scripts before running them on production. There are many ways to authenticate with an SSH server, including simple username-password, public-key authentication, Kuberos, and two-factor authentication. We will cover two of these methods:
If the ssh-agent in your docker container, accepts password access then ssh access to the container is as simple as:
# `remotehost` is the host/ip of your docker container instance
$ ssh <username>@<container-ip>
You can find an example Dockerfile that runs an ssh-agent with a specified username/password
FROM ubuntu:latest
RUN apt-get update && \
apt-get install -y openssh-server sudo && \
rm -rf /var/lib/apt/lists/*
RUN useradd -rm -d /home/ubuntu -s /bin/bash -g root -G sudo -u 1000 test && \
echo 'test:supersecretpassword' | chpasswd
RUN mkdir /var/run/sshd
EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]
You can access this container using ssh like:
$ docker run -p 2023:22 -d sshtestcclear
$ ssh -p 2023 test@localhost
test@localhost's password: ********
# you will be prompted to enter password for user `test`
# `supersecretpassword`
If the container is not deployed on your localhost, you can query its IP using the following command:
$ docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' <container_id>
172.18.0.2
You will need to generate a ssh key pair. The public key will be added to the container and the private key would be used by you to authenticate your identity to the container’s ssh-agent. Let’s suppose the names of those are, key.pub and key (to learn more about generating these keys check this article).
FROM alpine:latest
RUN apk add --update --no-cache openssh
RUN addgroup -S test_user_group && adduser -S -G test_user_group test_user
RUN mkdir -p /root/.ssh
# Build image with public key added to authorized_keys file
# of the container
COPY key.pub ./root/.ssh/authorized_keys
# Restrict access for keys to owners of file only
RUN chown test_user:test_user_group /root/.ssh/authorized_keys && chmod 600 /root/.ssh/authorized_keys
RUN ssh-keygen -A
EXPOSE 22
# log to stderr using "-e"
CMD ["/usr/sbin/sshd","-D"]
# build the docker image
$ docker build -t ssh-agent-in-docker .
# run the docker image, exposing port 2023 on host to ssh port in container
$ docker run -p 2023:22 ssh-agent-in-docker
# now you can access the container using ssh by using private key
$ ssh -i /location/to/key -p 2023 test_user@localhost
But what if you don’t have access to docker-daemon and the container is running on a network not exposed to you?
Imagine a situation where you want to access a container running on your home lab from an airport or another location. If you lack a public and static IP for your home network, and the airport Wi-Fi network is not part of your home network, you cannot access the container from outside without a complex private network or VPN setup. Exposing your entire home network via a public IP would also attract negative attention.
Instead of directly exposing the external interface of your home network, you can use a public server as a bridge between you and the container running on your home network. This is because a public server will have a public IP that can be accessed from anywhere.
An example of this is rsshd, which provides a minimal implementation of this. To use it, follow these steps:
server.public
), run the Docker container$ docker run -it --rm \
-p 2222:22 \
--name rsshd \
-p 10000-10100:10000-10100 \
-e PASSWORD=secret \
-v /opt/keys/host:/etc/ssh/keys \
-v /opt/keys/clients:/root/.ssh \
efrecon/rsshd
chpasswd: password for 'root' changed
Server listening on 0.0.0.0 port 22.
Server listening on :: port 22.
This will run bridge on your public server. To access the container remotely via the reverse tunnel, you would first need to create a reverse tunnel on it, by:
$ ssh -fN -R 10000:localhost:22 -p 2222 root@server.public
Now a reverse tunnel (on the port) exists from the container (in the home network) with the container/bridge running on the public server. You can now just ssh to the public server on the port.
$ ssh -p 10000 root@server.public
The authenticity of host '[server.public]:10000 ([::1]:2222)' can't be established.
ED25519 key fingerprint is SHA256:HagFEp3Lxjk4DY/8Xm3gRuMvuYiXchlNZSWKXLGfJlU.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '[server.public]:2222' (ED25519) to the list of known hosts.
root@localhost's password:
Welcome to Alpine!
The Alpine Wiki contains a large amount of how-to guides and general
information about administrating Alpine systems.
See <http://wiki.alpinelinux.org/>.
You can setup the system with the command: setup-alpine
You may change this message by editing /etc/motd.
Note: If you manage your container using Podman or Portainer, you can find more information about their exec functions here and here, respectively.
As teams get bigger, accessing containers within private networks can become increasingly challenging due to heightened access restrictions. It's possible to encounter situations where direct access to the network or the necessary keys to connect to a container is limited. Adaptive makes it easier to access containers in all such cases.
With Adaptive's JIT Access Management platform, you can SSH or access a container's shell using a simple command:
$ adaptive connect <endpoint_name>
where <endpoint_name>
is an Endpoint connected to your Container or VM.