Skip to content

fix(security): stop baking the ClickHouse password into the healthcheck command - #64

Merged
marselsel merged 1 commit into
mainfrom
fix/healthcheck-no-literal-password
Aug 5, 2026
Merged

fix(security): stop baking the ClickHouse password into the healthcheck command#64
marselsel merged 1 commit into
mainfrom
fix/healthcheck-no-literal-password

Conversation

@marselsel

Copy link
Copy Markdown
Collaborator

The ClickHouse healthcheck interpolated ${CLICKHOUSE_PASSWORD} straight into its test command, so compose baked the literal into the container config and docker inspect printed 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-SHELL and 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_PASSWORD in its environment to set the default user, so the value remains visible under .Config.Env. Removing it from there would mean bind-mounting a users.d config 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 config renders the command with $CLICKHOUSE_PASSWORD unexpanded; a deliberately-set value appears 0 times in the rendered output.

…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.
@marselsel
marselsel merged commit d241a8c into main Aug 5, 2026
12 checks passed
@marselsel
marselsel deleted the fix/healthcheck-no-literal-password branch August 5, 2026 09:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant