fix(security): stop baking the ClickHouse password into the healthcheck command - #64
Merged
Merged
Conversation
…ck command
The ClickHouse healthcheck interpolated ${CLICKHOUSE_PASSWORD} directly into its
test command, so compose baked the literal into the container config and
`docker inspect` printed it in full. That is not theoretical: a live password was
exposed exactly that way on 2026-08-04 and had to be rotated across all three
ClickHouse users.
The check now uses CMD-SHELL and reads the value from the container's own
environment at run time — `$$` escapes to a literal `$` so the shell inside the
container expands it rather than compose. Same check, same semantics, no literal
in the container config.
Being precise about what this does NOT do: the ClickHouse image needs
CLICKHOUSE_PASSWORD in its environment to set the default user's password, so
the value remains visible under `docker inspect`'s .Config.Env. Removing it from
there would mean bind-mounting a users.d config instead of using the image's own
bootstrap, which is a larger change to how the container starts and moves the
secret to a file rather than eliminating it. What this commit removes is the
SECOND copy — the one embedded in a command string, where nobody thinks to look
and where a redaction pattern written for env-var output does not match.
Verified: `docker compose config` renders the command with $CLICKHOUSE_PASSWORD
unexpanded, and a deliberately-set value appears zero times in the output.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The ClickHouse healthcheck interpolated
${CLICKHOUSE_PASSWORD}straight into its test command, so compose baked the literal into the container config anddocker inspectprinted it in full.Not theoretical — a live password was exposed exactly that way on 2026-08-04 and had to be rotated across all three ClickHouse users.
Now uses
CMD-SHELLand reads the value from the container's own environment at run time ($$escapes to a literal$, so the in-container shell expands it rather than compose). Same check, same semantics, no literal in the container config.What this does not do
The ClickHouse image needs
CLICKHOUSE_PASSWORDin its environment to set the default user, so the value remains visible under.Config.Env. Removing it from there would mean bind-mounting ausers.dconfig instead of the image's own bootstrap — a larger change to container startup that moves the secret to a file rather than eliminating it.What this removes is the second copy: the one embedded in a command string, where nobody thinks to look, and where a redaction pattern written for env-var output doesn't match. That is precisely the shape of the leak.
Verification
docker compose configrenders the command with$CLICKHOUSE_PASSWORDunexpanded; a deliberately-set value appears 0 times in the rendered output.