Remove ClickHouse password from process argv

This commit is contained in:
igor04091968
2026-07-01 14:41:59 +03:00
parent bb86939179
commit 82691d7d92
9 changed files with 118 additions and 32 deletions
+4
View File
@@ -230,6 +230,10 @@ Expected benefit: long-running production operation has bounded disk behavior.
### P0-5. Remove ClickHouse password exposure from process arguments
Status: addressed by TASK_068. Runtime ClickHouse/1C wrappers keep
`CLICKHOUSE_PASSWORD` in the environment/config path and no longer pass it in
process arguments.
Purpose: keep production credentials out of `ps`/process argv.
Reason: `rg` confirmed `clickhouse-1c/ops/run_*.sh` wrappers pass
+3 -4
View File
@@ -18,13 +18,12 @@ fi
# shellcheck disable=SC1090
. "${ENV_FILE}"
# shellcheck source=clickhouse-1c/ops/clickhouse-client-safe.sh
. "${ROOT}/ops/clickhouse-client-safe.sh"
query_max_age() {
local table="$1"
docker exec "${CH_CONTAINER}" clickhouse-client \
--user "${CLICKHOUSE_USER}" \
--password "${CLICKHOUSE_PASSWORD}" \
--database "${CLICKHOUSE_DB}" \
aw_1c_clickhouse_client \
-q "SELECT if(count()=0, -1, dateDiff('hour', max(ts), now())) FROM ${table}"
}
@@ -0,0 +1,53 @@
#!/usr/bin/env bash
aw_1c_xml_escape() {
local value="$1"
value="${value//&/&}"
value="${value//</&lt;}"
value="${value//>/&gt;}"
value="${value//\"/&quot;}"
value="${value//\'/&apos;}"
printf '%s' "${value}"
}
aw_1c_clickhouse_client() {
local container="${CH_CONTAINER:-${AW_1C_CLICKHOUSE_CONTAINER:-aw-rus-1c-clickhouse}}"
local local_cfg remote_cfg status
if [[ -z "${CLICKHOUSE_USER:-}" ]]; then
echo "CLICKHOUSE_USER is required" >&2
return 1
fi
if [[ -z "${CLICKHOUSE_DB:-}" ]]; then
echo "CLICKHOUSE_DB is required" >&2
return 1
fi
if [[ -z "${CLICKHOUSE_PASSWORD+x}" ]]; then
echo "CLICKHOUSE_PASSWORD is required" >&2
return 1
fi
local_cfg="$(mktemp "${TMPDIR:-/tmp}/aw-1c-clickhouse-client.XXXXXX.xml")"
chmod 0600 "${local_cfg}"
remote_cfg="/tmp/aw-1c-clickhouse-client.$(date +%s).$$.xml"
{
printf '<config>\n'
printf ' <user>%s</user>\n' "$(aw_1c_xml_escape "${CLICKHOUSE_USER}")"
printf ' <password>%s</password>\n' "$(aw_1c_xml_escape "${CLICKHOUSE_PASSWORD}")"
printf ' <database>%s</database>\n' "$(aw_1c_xml_escape "${CLICKHOUSE_DB}")"
printf '</config>\n'
} > "${local_cfg}"
if ! docker exec -i "${container}" sh -c 'umask 077 && cat > "$1"' sh "${remote_cfg}" < "${local_cfg}"; then
rm -f "${local_cfg}"
echo "failed to stage ClickHouse client config in container" >&2
return 1
fi
rm -f "${local_cfg}"
status=0
docker exec -i "${container}" clickhouse-client --config-file "${remote_cfg}" "$@" || status=$?
docker exec "${container}" rm -f "${remote_cfg}" >/dev/null 2>&1 || true
return "${status}"
}
@@ -1,4 +1,5 @@
#!/usr/bin/env bash
# shellcheck disable=SC2119
set -euo pipefail
ROOT="${AW_1C_ROOT:-/opt/activitywatch/clickhouse-1c}"
@@ -21,18 +22,20 @@ if ! docker ps --format '{{.Names}}' | grep -qx "${CH_CONTAINER}"; then
exit 1
fi
# shellcheck disable=SC1090
set -a
# shellcheck source=/dev/null
. "${ENV_FILE}"
set +a
# shellcheck source=clickhouse-1c/ops/clickhouse-client-safe.sh
. "${ROOT}/ops/clickhouse-client-safe.sh"
CH_RUNTIME_HOST="${AW_1C_CLICKHOUSE_RUNTIME_HOST:-${CLICKHOUSE_HOST}}"
if [[ "${CH_RUNTIME_HOST}" == "clickhouse" ]]; then
CH_RUNTIME_HOST="127.0.0.1"
fi
: "${CLICKHOUSE_PORT:?CLICKHOUSE_PORT is required}"
docker exec -i "${CH_CONTAINER}" clickhouse-client \
--user "${CLICKHOUSE_USER}" \
--password "${CLICKHOUSE_PASSWORD}" \
--database "${CLICKHOUSE_DB}" \
aw_1c_clickhouse_client \
< "${ROOT}/clickhouse/init/04_company_intelligence.sql"
"${ROOT}/ops/run_company_registry_bindings_refresh.sh"
@@ -41,5 +44,4 @@ docker exec -i "${CH_CONTAINER}" clickhouse-client \
--host "${CH_RUNTIME_HOST}" \
--port "${CLICKHOUSE_PORT}" \
--user "${CLICKHOUSE_USER}" \
--password "${CLICKHOUSE_PASSWORD}" \
--database "${CLICKHOUSE_DB}"
@@ -15,17 +15,19 @@ if [[ ! -x "${VENV}/bin/python" ]]; then
exit 1
fi
# shellcheck disable=SC1090
set -a
# shellcheck source=/dev/null
. "${ENV_FILE}"
set +a
CH_RUNTIME_HOST="${AW_1C_CLICKHOUSE_RUNTIME_HOST:-${CLICKHOUSE_HOST}}"
if [[ "${CH_RUNTIME_HOST}" == "clickhouse" ]]; then
CH_RUNTIME_HOST="127.0.0.1"
fi
: "${CLICKHOUSE_PORT:?CLICKHOUSE_PORT is required}"
"${VENV}/bin/python" "${ROOT}/ai/refresh_company_registry_bindings.py" \
--host "${CH_RUNTIME_HOST}" \
--port "${CLICKHOUSE_PORT}" \
--user "${CLICKHOUSE_USER}" \
--password "${CLICKHOUSE_PASSWORD}" \
--database "${CLICKHOUSE_DB}"
+7 -16
View File
@@ -1,4 +1,5 @@
#!/usr/bin/env bash
# shellcheck disable=SC2119
set -euo pipefail
ROOT="${AW_1C_ROOT:-/opt/activitywatch/clickhouse-1c}"
@@ -40,6 +41,8 @@ fi
# shellcheck disable=SC1090
. "${ENV_FILE}"
# shellcheck source=clickhouse-1c/ops/clickhouse-client-safe.sh
. "${ROOT}/ops/clickhouse-client-safe.sh"
if [[ "${RUN_MCP_TOOLKIT_EXTRACT_BEFORE_INGEST}" == "1" ]]; then
"${VENV}/bin/python" "${ROOT}/etl/extract_1c_mcp_toolkit.py" --config "${CONFIG}"
@@ -49,31 +52,19 @@ fi
"${VENV}/bin/python" "${ROOT}/etl/load_1c_exports.py" --config "${CONFIG}"
"${VENV}/bin/python" "${ROOT}/etl/load_company_registry_xlsx.py" --config "${CONFIG}" --landing "${ROOT}/landing/registry"
docker exec -i "${CH_CONTAINER}" clickhouse-client \
--user "${CLICKHOUSE_USER}" \
--password "${CLICKHOUSE_PASSWORD}" \
--database "${CLICKHOUSE_DB}" \
aw_1c_clickhouse_client \
< "${ROOT}/detections/build_entity_timeline.sql"
docker exec -i "${CH_CONTAINER}" clickhouse-client \
--user "${CLICKHOUSE_USER}" \
--password "${CLICKHOUSE_PASSWORD}" \
--database "${CLICKHOUSE_DB}" \
aw_1c_clickhouse_client \
< "${ROOT}/clickhouse/init/04_company_intelligence.sql"
"${ROOT}/ops/run_company_registry_bindings_refresh.sh"
"${ROOT}/ops/run_company_intelligence_refresh.sh"
docker exec -i "${CH_CONTAINER}" clickhouse-client \
--user "${CLICKHOUSE_USER}" \
--password "${CLICKHOUSE_PASSWORD}" \
--database "${CLICKHOUSE_DB}" \
aw_1c_clickhouse_client \
< "${ROOT}/detections/insert_detections.sql"
docker exec -i "${CH_CONTAINER}" clickhouse-client \
--user "${CLICKHOUSE_USER}" \
--password "${CLICKHOUSE_PASSWORD}" \
--database "${CLICKHOUSE_DB}" \
aw_1c_clickhouse_client \
< "${ROOT}/detections/open_cases_from_detections.sql"
if [[ "${RUN_MANAGER_BRIEF_AFTER_INGEST}" == "1" ]]; then
+2 -2
View File
@@ -19,8 +19,8 @@ if [[ ! -x "${VENV}/bin/python" ]]; then
exit 1
fi
# shellcheck disable=SC1090
set -a
# shellcheck source=/dev/null
. "${ENV_FILE}"
set +a
@@ -28,6 +28,7 @@ CH_RUNTIME_HOST="${AW_1C_CLICKHOUSE_RUNTIME_HOST:-${CLICKHOUSE_HOST}}"
if [[ "${CH_RUNTIME_HOST}" == "clickhouse" ]]; then
CH_RUNTIME_HOST="127.0.0.1"
fi
: "${CLICKHOUSE_PORT:?CLICKHOUSE_PORT is required}"
export CLICKHOUSE_HOST="${CH_RUNTIME_HOST}"
@@ -43,7 +44,6 @@ while (( attempt <= RETRIES )); do
--host "${CH_RUNTIME_HOST}" \
--port "${CLICKHOUSE_PORT}" \
--user "${CLICKHOUSE_USER}" \
--password "${CLICKHOUSE_PASSWORD}" \
--database "${CLICKHOUSE_DB}"; then
exit 0
fi
+2 -2
View File
@@ -19,8 +19,8 @@ if [[ ! -x "${VENV}/bin/python" ]]; then
exit 1
fi
# shellcheck disable=SC1090
set -a
# shellcheck source=/dev/null
. "${ENV_FILE}"
set +a
@@ -28,6 +28,7 @@ CH_RUNTIME_HOST="${AW_1C_CLICKHOUSE_RUNTIME_HOST:-${CLICKHOUSE_HOST}}"
if [[ "${CH_RUNTIME_HOST}" == "clickhouse" ]]; then
CH_RUNTIME_HOST="127.0.0.1"
fi
: "${CLICKHOUSE_PORT:?CLICKHOUSE_PORT is required}"
exec 9>"${LOCK_FILE}"
if ! flock -w "${LOCK_WAIT_SEC}" 9; then
@@ -41,7 +42,6 @@ while (( attempt <= RETRIES )); do
--host "${CH_RUNTIME_HOST}" \
--port "${CLICKHOUSE_PORT}" \
--user "${CLICKHOUSE_USER}" \
--password "${CLICKHOUSE_PASSWORD}" \
--database "${CLICKHOUSE_DB}"; then
exit 0
fi
+35
View File
@@ -228,3 +228,38 @@ powershell.exe -ExecutionPolicy Bypass `
Запрещено вручную удалять Windows collector queues, incident artifacts, DLP
evidence, Hayabusa archives, Grafana data или ClickHouse tables без отдельного
operator approval и backup/restore plan.
## Проверка отсутствия ClickHouse-пароля в argv
Цель проверки - убедиться, что ClickHouse/1C runtime wrappers не передают
`CLICKHOUSE_PASSWORD` через аргументы процессов. Пароль должен поступать из
`/opt/activitywatch/clickhouse-1c/.env` в окружение или временный client config,
а не через `--password`.
Статическая проверка wrappers:
```bash
rg -n -- '--password[= ]+"?\$[{]?CLICKHOUSE_PASSWORD' \
/opt/activitywatch/clickhouse-1c/ops
```
Ожидаемый результат: команда не выводит совпадений.
Runtime smoke во время ingest/brief refresh:
```bash
set -a
. /opt/activitywatch/clickhouse-1c/.env
set +a
ps -eo args= | grep -E 'clickhouse-client|generate_.*brief|refresh_company' |
while IFS= read -r line; do
if printf '%s' "${line}" | grep -F -- "${CLICKHOUSE_PASSWORD}" >/dev/null; then
echo "FAIL: ClickHouse password is visible in process argv" >&2
exit 1
fi
done
```
Ожидаемый результат: команда завершается с кодом `0` и не печатает секрет.
Если проверка падает, остановить rollout и вернуть предыдущий release artifact.