Reputation: 326
TL/DR
When I run openssl s_server -port X ...
as ENTRYPOINT in a Docker container, the process starts and waits for connection, but connecting to it on port X fails.
If I connect to the running container (docker exec -it <container> /bin/sh
) and start another openssl s_server -port Y ...
with the exact same parameters except for the port number, then I can successfully connect to that process on port Y.
What could be the reason for this difference in behaviour?
Elaboration
I am trying to run a simple TLS/TCP server using openssl s_server ...
in a Docker container. The following command runs fine when I start it in the running container, but when used as the ENTRYPOINT, connecting to the server fails (the openssl s_server
process is terminated as soon as a connection attempt is made to it):
openssl s_server -debug -CAfile /sshfiles/rootCA.crt -key /sshfiles/usage.key -cert /sshfiles/usage.crt -port 9997 -Verify 3 -verify_return_error
The docker compose part that I am using to start the container (docker compose up tlstcp
):
version: "3"
services:
tlstcp:
build: ./tlstcp
container_name: tlstcp
network_mode: 'host'
volumes:
- ./sshfiles:/sshfiles
- ./logs:/var/log
# Entrypoint is `openssl`, command contains the parameters to be passed to it
command: s_server -debug -CAfile /sshfiles/rootCA.crt -key /sshfiles/usage.key -cert /sshfiles/usage.crt -port 9998 -Verify 3 -verify_return_error
The Dockerfile to build the container:
FROM alpine:latest
RUN apk add --no-cache openssl
COPY start.sh /
COPY runCmd.sh /
RUN chmod +x /start.sh
RUN chmod +x /runCmd.sh
ENTRYPOINT ["openssl"]
The /sshfiles folder that is being referred to contains a valid set of keys and certificates, as verified by successfully being able to locally start an openssl s_server ...
and openssl s_client ...
that connect to one another and allow text to be exchanged.
Connecting to the server is done with the following openssl command (it picks up identical key and certificate files):
openssl s_client -connect 127.0.0.1:9997 -showcerts -debug -CAfile sshfiles/rootCA.crt -key sshfiles/usage.key -cert sshfiles/usage.crt
As stated above, this connection fails (openssl on the server side just terminates) when using the port used by the ENTRYPOINT, but succeeds when using the port used by a separately started server process inside the container.
Versions of components:
[600]$ docker version
Client:
Version: 24.0.2-rd
API version: 1.42 (downgraded from 1.43)
Go version: go1.20.4
Git commit: e63f5fa
Built: Fri May 26 16:39:47 2023
OS/Arch: darwin/amd64
Context: default
Server:
Engine:
Version: 23.0.6
API version: 1.42 (minimum version 1.12)
Go version: go1.20.4
Git commit: 9dbdbd4b6d7681bd18c897a6ba0376073c2a72ff
Built: Fri May 12 13:54:36 2023
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: v1.7.0
GitCommit: 1fbd70374134b891f97ce19c70b6e50c7b9f4e0d
runc:
Version: 1.1.7
GitCommit: 860f061b76bb4fc671f0f9e900f7d80ff93d4eb7
docker-init:
Version: 0.19.0
GitCommit:
Upvotes: 0
Views: 327
Reputation: 159750
The OpenSSL 1.1 openssl-s_server(1) man page notes:
If a connection request is established with an SSL client and neither the -www nor the -WWW option has been used then normally any data received from the client is displayed and any key presses will be sent to the client.
If this text says "anything on the process's standard input is sent back to the client", then that explains the behavior you're seeing. Containers by default don't have a standard input, so when openssl s_server
gets a connection, it starts reading from its stdin but discovers it's closed, so it immediately closes the TCP connection as well.
In principle you can change this by using the Compose stdin_open:
option. However, even if stdin exists, there's no way to provide any data to it.
That is: with this setup, it seems like it's impossible to configure openssl s_server
to actually give any meaningful response to the client.
I might just pick a higher-level tool here; write your actual server in your choice of language and use the language-native TLS server support.
If you really needed to use openssl s_server
here you might give it some sort of static response that it could send back. You could use shell redirection here. It will not work with this particular ENTRYPOINT
/CMD
split, but it's not necessary to break up the command this way in any case.
COPY response.txt ./
# no ENTRYPOINT; shell form CMD
CMD openssl s_server \
-debug \
-CAfile /sshfiles/rootCA.crt \
-key /sshfiles/usage.key \
-cert /sshfiles/usage.crt \
-port 9998 \
-Verify 3 \
-verify_return_error \
< response.txt
Upvotes: 1