Skip to content

Commit cbdb89e

Browse files
committed
Fix DB backup/restore scripts to avoid host process-list secret exposure
1 parent 627f420 commit cbdb89e

File tree

2 files changed

+28
-13
lines changed

2 files changed

+28
-13
lines changed

platform_blueprint/ops/db_backup/backup.sh

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,18 @@ if ! sudo docker ps --format '{{.Names}}' | grep -qx cleanapp_db; then
5555
exit 1
5656
fi
5757

58+
# Never pass secrets via `docker exec -e ...` (those end up visible in host `ps` output).
59+
# Instead, write the secret into a short-lived file inside the container and reference it
60+
# from inside the container process.
61+
pwfile="/tmp/cleanapp_mysql_backup_pw.$$.$RANDOM"
62+
cleanup_pwfile() {
63+
sudo docker exec cleanapp_db sh -lc "rm -f '${pwfile}'" >/dev/null 2>&1 || true
64+
}
65+
trap cleanup_pwfile EXIT
66+
67+
printf '%s' "${MYSQL_ROOT_PASSWORD}" | sudo docker exec -i cleanapp_db sh -lc \
68+
"cat > '${pwfile}' && chmod 600 '${pwfile}'" >/dev/null
69+
5870
if command -v pigz >/dev/null 2>&1; then
5971
COMPRESS=(pigz -1)
6072
else
@@ -65,15 +77,15 @@ started_ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
6577
started_epoch="$(date +%s)"
6678

6779
log "INFO mysqldump stream start"
68-
sudo docker exec -e MYSQL_PWD="${MYSQL_ROOT_PASSWORD}" -i cleanapp_db sh -lc \
69-
'exec mysqldump -uroot \
80+
sudo docker exec -i cleanapp_db sh -lc \
81+
"MYSQL_PWD=\"\$(cat '${pwfile}')\" exec mysqldump -uroot \
7082
--all-databases \
7183
--single-transaction \
7284
--quick \
7385
--lock-tables=false \
7486
--routines --events --triggers \
7587
--hex-blob \
76-
--set-gtid-purged=OFF' \
88+
--set-gtid-purged=OFF" \
7789
| "${COMPRESS[@]}" \
7890
| gsutil -q -o GSUtil:parallel_composite_upload_threshold=150M cp - "${CURRENT_KEY}"
7991

@@ -85,8 +97,8 @@ size_bytes="$(gsutil ls -l "${CURRENT_KEY}" | awk 'NR==1{print $1}')"
8597
size_bytes="${size_bytes:-0}"
8698

8799
log "INFO capturing row counts"
88-
reports_count="$(sudo docker exec -e MYSQL_PWD="${MYSQL_ROOT_PASSWORD}" -i cleanapp_db sh -lc 'mysql -uroot -N -e "SELECT COUNT(*) FROM cleanapp.reports" 2>/dev/null' | tr -d '\r' | tail -n 1 || true)"
89-
analysis_count="$(sudo docker exec -e MYSQL_PWD="${MYSQL_ROOT_PASSWORD}" -i cleanapp_db sh -lc 'mysql -uroot -N -e "SELECT COUNT(*) FROM cleanapp.report_analysis" 2>/dev/null' | tr -d '\r' | tail -n 1 || true)"
100+
reports_count="$(sudo docker exec -i cleanapp_db sh -lc "MYSQL_PWD=\"\$(cat '${pwfile}')\" mysql -uroot -N -e \"SELECT COUNT(*) FROM cleanapp.reports\" 2>/dev/null" | tr -d '\r' | tail -n 1 || true)"
101+
analysis_count="$(sudo docker exec -i cleanapp_db sh -lc "MYSQL_PWD=\"\$(cat '${pwfile}')\" mysql -uroot -N -e \"SELECT COUNT(*) FROM cleanapp.report_analysis\" 2>/dev/null" | tr -d '\r' | tail -n 1 || true)"
90102
reports_count="${reports_count:-0}"
91103
analysis_count="${analysis_count:-0}"
92104
counts_json="{\"reports\":${reports_count},\"report_analysis\":${analysis_count}}"
@@ -120,4 +132,3 @@ if [[ "$(date -u +%u)" == "7" ]]; then
120132
fi
121133

122134
log "INFO backup complete env=${ENV}"
123-

platform_blueprint/ops/db_backup/restore_drill_prod_vm.sh

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,14 @@ name="cleanapp_db_restore_drill_${ts}"
5656
vol="eko_mysql_restore_drill_${ts}"
5757
5858
root_pw="$(python3 -c 'import secrets; print(secrets.token_hex(16))')"
59+
envfile="/tmp/${name}.env"
5960
6061
echo "== create scratch mysql container =="
6162
sudo docker volume create "${vol}" >/dev/null
62-
sudo docker run -d --name "${name}" \
63-
-e MYSQL_ROOT_PASSWORD="${root_pw}" \
63+
umask 077
64+
printf 'MYSQL_ROOT_PASSWORD=%s\n' "${root_pw}" >"${envfile}"
65+
66+
sudo docker run -d --name "${name}" --env-file "${envfile}" \
6467
-p 127.0.0.1:3307:3306 \
6568
-v "${vol}":/var/lib/mysql \
6669
mysql:8.0 \
@@ -72,12 +75,14 @@ cleanup() {
7275
echo "== cleanup =="
7376
sudo docker rm -f "${name}" >/dev/null 2>&1 || true
7477
sudo docker volume rm "${vol}" >/dev/null 2>&1 || true
78+
rm -f "${envfile}" >/dev/null 2>&1 || true
7579
}
7680
trap cleanup EXIT
7781
7882
echo "== wait for mysql ready =="
7983
for i in $(seq 1 120); do
80-
if sudo docker exec -e MYSQL_PWD="${root_pw}" "${name}" mysql -uroot -e "SELECT 1" >/dev/null 2>&1; then
84+
# Use container env var to avoid putting secrets in host-visible process args.
85+
if sudo docker exec "${name}" sh -lc 'mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e "SELECT 1" >/dev/null 2>&1'; then
8186
break
8287
fi
8388
sleep 2
@@ -88,11 +93,11 @@ for i in $(seq 1 120); do
8893
done
8994
9095
echo "== stream restore (this can take a long time) =="
91-
gsutil cat "${obj_sql}" | gunzip -c | sudo docker exec -i -e MYSQL_PWD="${root_pw}" "${name}" mysql -uroot
96+
gsutil cat "${obj_sql}" | gunzip -c | sudo docker exec -i "${name}" sh -lc 'mysql -uroot -p"$MYSQL_ROOT_PASSWORD"'
9297
9398
echo "== verify counts =="
94-
got_reports="$(sudo docker exec -e MYSQL_PWD="${root_pw}" "${name}" mysql -uroot -N -e 'SELECT COUNT(*) FROM cleanapp.reports' 2>/dev/null | tr -d '\r' | tail -n 1)"
95-
got_analysis="$(sudo docker exec -e MYSQL_PWD="${root_pw}" "${name}" mysql -uroot -N -e 'SELECT COUNT(*) FROM cleanapp.report_analysis' 2>/dev/null | tr -d '\r' | tail -n 1)"
99+
got_reports="$(sudo docker exec "${name}" sh -lc 'mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -N -e \"SELECT COUNT(*) FROM cleanapp.reports\" 2>/dev/null' | tr -d '\r' | tail -n 1)"
100+
got_analysis="$(sudo docker exec "${name}" sh -lc 'mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -N -e \"SELECT COUNT(*) FROM cleanapp.report_analysis\" 2>/dev/null' | tr -d '\r' | tail -n 1)"
96101
97102
echo "restored counts: reports=${got_reports} report_analysis=${got_analysis}"
98103
@@ -103,4 +108,3 @@ fi
103108
104109
echo "OK restore drill: counts match metadata"
105110
REMOTE
106-

0 commit comments

Comments
 (0)