JeanMarc
JeanMarc

Reputation: 326

openssl s_server as entrypoint in Docker does not work

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

Answers (1)

David Maze
David Maze

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

Related Questions