Mask the password when logging a MongoDB dump or restore command (#848).
This commit is contained in:
parent
f9182514d8
commit
7e51c41ebf
3 changed files with 40 additions and 1 deletions
1
NEWS
1
NEWS
|
@ -9,6 +9,7 @@
|
|||
* #843: Add documentation link to Loki dashboard for borgmatic:
|
||||
https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#loki-hook
|
||||
* #847: Fix "--json" error when Borg includes non-JSON warnings in JSON output.
|
||||
* #848: SECURITY: Mask the password when logging a MongoDB dump or restore command.
|
||||
* Fix handling of the NO_COLOR environment variable to ignore an empty value.
|
||||
* Add documentation about backing up containerized databases by configuring borgmatic to exec into
|
||||
a container to run a dump command:
|
||||
|
|
|
@ -220,6 +220,24 @@ def log_outputs(processes, exclude_stdouts, output_log_level, borg_local_path, b
|
|||
}
|
||||
|
||||
|
||||
SECRET_COMMAND_FLAG_NAMES = {'--password'}
|
||||
|
||||
|
||||
def mask_command_secrets(full_command):
|
||||
'''
|
||||
Given a command as a sequence, mask secret values for flags like "--password" in preparation for
|
||||
logging.
|
||||
'''
|
||||
masked_command = []
|
||||
previous_piece = None
|
||||
|
||||
for piece in full_command:
|
||||
masked_command.append('***' if previous_piece in SECRET_COMMAND_FLAG_NAMES else piece)
|
||||
previous_piece = piece
|
||||
|
||||
return tuple(masked_command)
|
||||
|
||||
|
||||
MAX_LOGGED_COMMAND_LENGTH = 1000
|
||||
|
||||
|
||||
|
@ -231,7 +249,8 @@ def log_command(full_command, input_file=None, output_file=None, environment=Non
|
|||
logger.debug(
|
||||
textwrap.shorten(
|
||||
' '.join(
|
||||
tuple(f'{key}=***' for key in (environment or {}).keys()) + tuple(full_command)
|
||||
tuple(f'{key}=***' for key in (environment or {}).keys())
|
||||
+ mask_command_secrets(full_command)
|
||||
),
|
||||
width=MAX_LOGGED_COMMAND_LENGTH,
|
||||
placeholder=' ...',
|
||||
|
|
|
@ -117,6 +117,24 @@ def test_append_last_lines_with_output_log_level_none_appends_captured_output():
|
|||
assert captured_output == ['captured', 'line']
|
||||
|
||||
|
||||
def test_mask_command_secrets_masks_password_flag_value():
|
||||
assert module.mask_command_secrets(('cooldb', '--username', 'bob', '--password', 'pass')) == (
|
||||
'cooldb',
|
||||
'--username',
|
||||
'bob',
|
||||
'--password',
|
||||
'***',
|
||||
)
|
||||
|
||||
|
||||
def test_mask_command_secrets_passes_through_other_commands():
|
||||
assert module.mask_command_secrets(('cooldb', '--username', 'bob')) == (
|
||||
'cooldb',
|
||||
'--username',
|
||||
'bob',
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'full_command,input_file,output_file,environment,expected_result',
|
||||
(
|
||||
|
@ -149,6 +167,7 @@ def test_append_last_lines_with_output_log_level_none_appends_captured_output():
|
|||
def test_log_command_logs_command_constructed_from_arguments(
|
||||
full_command, input_file, output_file, environment, expected_result
|
||||
):
|
||||
flexmock(module).should_receive('mask_command_secrets').replace_with(lambda command: command)
|
||||
flexmock(module.logger).should_receive('debug').with_args(expected_result).once()
|
||||
|
||||
module.log_command(full_command, input_file, output_file, environment)
|
||||
|
|
Loading…
Reference in a new issue