Skip to content

Commit dc289d7

Browse files
[DPE-6447] Avoid storing passwords on disk when running mysqlsh (#387)
## Issue We are storing passwords on disk (in the mysqlsh python script) when we execute mysqlsh. This is a security vulnerability ## Solution Avoid writing passwords on disk, and instead use --passwords-from-stdin flag of mysqlsh
1 parent 8264bac commit dc289d7

File tree

3 files changed

+28
-25
lines changed

3 files changed

+28
-25
lines changed

src/container.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,14 +196,20 @@ def run_mysql_router(self, args: typing.List[str], *, timeout: int = None) -> st
196196
return self._run_command(args, timeout=timeout)
197197

198198
# TODO python3.10 min version: Use `list` instead of `typing.List`
199-
def run_mysql_shell(self, args: typing.List[str], *, timeout: int = None) -> str:
199+
def run_mysql_shell(
200+
self,
201+
args: typing.List[str],
202+
*,
203+
timeout: int = None,
204+
input: str = None, # noqa: A002 Match subprocess.run()
205+
) -> str:
200206
"""Run MySQL Shell command.
201207
202208
Raises:
203209
CalledProcessError: Command returns non-zero exit code
204210
"""
205211
args.insert(0, self._mysql_shell_command)
206-
return self._run_command(args, timeout=timeout)
212+
return self._run_command(args, timeout=timeout, input=input)
207213

208214
@abc.abstractmethod
209215
def path(self, *args) -> Path:

src/mysql_shell/__init__.py

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -64,40 +64,36 @@ def _run_code(self, code: str) -> None:
6464
template = _jinja_env.get_template("try_except_wrapper.py.jinja")
6565
error_file = self._container.path("/tmp/mysqlsh_error.json")
6666

67-
def render(connection_info: "relations.database_requires.ConnectionInformation"):
68-
return template.render(
69-
username=connection_info.username,
70-
password=connection_info.password,
71-
host=connection_info.host,
72-
port=connection_info.port,
73-
code=code,
74-
error_filepath=error_file.relative_to_container,
75-
)
76-
77-
# Redact password from log
78-
logged_script = render(self._connection_info.redacted)
67+
script = template.render(code=code, error_filepath=error_file.relative_to_container)
7968

80-
script = render(self._connection_info)
8169
temporary_script_file = self._container.path("/tmp/mysqlsh_script.py")
82-
error_file = self._container.path("/tmp/mysqlsh_error.json")
8370
temporary_script_file.write_text(script)
71+
8472
try:
85-
self._container.run_mysql_shell([
86-
"--no-wizard",
87-
"--python",
88-
"--file",
89-
str(temporary_script_file.relative_to_container),
90-
])
73+
# https://bugs.mysql.com/bug.php?id=117429 details on why --no-wizard is omitted
74+
self._container.run_mysql_shell(
75+
[
76+
"--passwords-from-stdin",
77+
"--uri",
78+
f"{self._connection_info.username}@{self._connection_info.host}:{self._connection_info.port}",
79+
"--python",
80+
"--file",
81+
str(temporary_script_file.relative_to_container),
82+
],
83+
input=self._connection_info.password,
84+
)
9185
except container.CalledProcessError as e:
9286
logger.exception(
93-
f"Failed to run MySQL Shell script:\n{logged_script}\n\nstderr:\n{e.stderr}\n"
87+
f"Failed to run MySQL Shell script:\n{script}\n\nstderr:\n{e.stderr}\n"
9488
)
9589
raise
9690
finally:
9791
temporary_script_file.unlink()
92+
9893
with error_file.open("r") as file:
9994
exception = json.load(file)
10095
error_file.unlink()
96+
10197
try:
10298
if exception:
10399
raise ShellDBError(**exception)
@@ -107,7 +103,7 @@ def render(connection_info: "relations.database_requires.ConnectionInformation")
107103
raise server_exceptions.ConnectionError_
108104
else:
109105
logger.exception(
110-
f"Failed to run MySQL Shell script:\n{logged_script}\n\nMySQL client error {e.code}\nMySQL Shell traceback:\n{e.traceback_message}\n"
106+
f"Failed to run MySQL Shell script:\n{script}\n\nMySQL client error {e.code}\nMySQL Shell traceback:\n{e.traceback_message}\n"
111107
)
112108
raise
113109

src/mysql_shell/templates/try_except_wrapper.py.jinja

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import mysqlsh
33
import traceback
44

55
try:
6-
shell.connect("{{ username }}:{{ password }}@{{ host }}:{{ port }}")
6+
# Disable wizards in this script, since it will be invoked without --no-wizard
7+
shell.options.set('useWizards', False)
78
{{ code|indent(width=4) }}
89
except mysqlsh.DBError as exception:
910
error = {

0 commit comments

Comments
 (0)