Skip to content

Docker SDK adapter: WithHTTPClient clobbers TLS config from DOCKER_TLS_VERIFY / DOCKER_CERT_PATH #607

@CybotTM

Description

@CybotTM

Follow-up to #605 / #606.

Symptom

When DOCKER_HOST=https://... is used together with DOCKER_TLS_VERIFY=1 and DOCKER_CERT_PATH=..., Ofelia's HTTP transport does not pick up the env-supplied TLS material. The dial will either fail the TLS handshake (server-cert pinning misconfigured) or silently downgrade to plain TLS against the system roots — depending on the daemon's requirements.

Root cause

In core/adapters/docker/client.go::NewClientWithConfig, the option list is:

opts := []client.Opt{
    client.FromEnv,                  // sets host + TLS config on default transport
    client.WithAPIVersionNegotiation(),
}
// ...
if httpClient != nil {
    opts = append(opts, client.WithHTTPClient(httpClient))  // replaces c.client entirely
}

client.FromEnv internally calls WithTLSClientConfigFromEnv(), which installs a *tls.Config on the SDK client's default http.Client.Transport. Then WithHTTPClient(httpClient) overwrites c.client with our custom client, discarding the TLS config.

#606 fixed the parallel host/dialer divergence (where the SDK targeted TCP but our transport dialed a unix socket). The TLS-config equivalent of that divergence is still present.

Suggested fix

Read DOCKER_TLS_VERIFY and DOCKER_CERT_PATH (or call tlsconfig.Client(...) from github.com/docker/go-connections/tlsconfig) inside createHTTPClient when the resolved scheme is https://, and assign the resulting *tls.Config to transport.TLSClientConfig. Mirror the precedence: explicit ClientConfig TLS fields > env > none.

Impact

  • Not exploitable; affects only operators who configure TLS env vars expecting them to be honored. Worst case is connection failure or unauthenticated TLS where mTLS was intended.
  • Latent since the SDK adapter landed in v0.12.0.

Reproduction

export DOCKER_HOST=https://docker.example.com:2376
export DOCKER_TLS_VERIFY=1
export DOCKER_CERT_PATH=/path/to/certs
ofelia daemon --config /etc/ofelia/config.ini
# Expect: connects with client cert + CA from $DOCKER_CERT_PATH
# Actual: handshake without those, or unexpected TLS failure

Acceptance criteria

  • A test analogous to TestCreateHTTPClient_DockerHostEnvVar asserts that with DOCKER_HOST=https://... and DOCKER_CERT_PATH pointing at a fixture, transport.TLSClientConfig carries the expected Certificates / RootCAs.
  • Manual verification with a real TLS-protected Docker daemon (or a stub TLS server) shows the client cert is presented.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions