Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redact access tokens from extension's output #2811

Merged
merged 2 commits into from
Apr 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion azurelinuxagent/common/utils/extensionprocessutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#

import os
import re
import signal
import time

Expand Down Expand Up @@ -87,6 +88,9 @@ def handle_process_completion(process, command, timeout, stdout, stderr, error_c
return process_output


SAS_TOKEN_RE = re.compile(r'(https://\S+\?)((sv|st|se|sr|sp|sip|spr|sig)=\S+)+', flags=re.IGNORECASE)


def read_output(stdout, stderr):
"""
Read the output of the process sent to stdout and stderr and trim them to the max appropriate length.
Expand All @@ -103,7 +107,11 @@ def read_output(stdout, stderr):
stderr = ustr(stderr.read(TELEMETRY_MESSAGE_MAX_LEN), encoding='utf-8',
errors='backslashreplace')

return format_stdout_stderr(stdout, stderr)
def redact(s):
# redact query strings that look like SAS tokens
return SAS_TOKEN_RE.sub(r'\1<redacted>', s)

return format_stdout_stderr(redact(stdout), redact(stderr))
except Exception as e:
return format_stdout_stderr("", "Cannot read stdout/stderr: {0}".format(ustr(e)))

Expand Down
27 changes: 27 additions & 0 deletions tests/ga/test_extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -3418,6 +3418,33 @@ def http_get_handler(url, *_, **kwargs):
self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0.0")
self.assertEqual("1", protocol.report_vm_status.call_args[0][0].vmAgent.vm_artifacts_aggregate_status.goal_state_aggregate_status.in_svd_seq_no, "SVD sequence number mismatch")

def test_it_should_redact_access_tokens_in_extension_output(self):
original = r'''ONE https://foo.blob.core.windows.net/bar?sv=2000&ss=bfqt&srt=sco&sp=rw&se=2025&st=2022&spr=https&sig=SI%3D
TWO:HTTPS://bar.blob.core.com/foo/bar/foo.txt?sv=2018&sr=b&sig=Yx%3D&st=2023%3A52Z&se=9999%3A59%3A59Z&sp=r TWO
https://bar.com/foo?uid=2018&sr=b THREE'''
expected = r'''ONE https://foo.blob.core.windows.net/bar?<redacted>
TWO:HTTPS://bar.blob.core.com/foo/bar/foo.txt?<redacted> TWO
https://bar.com/foo?uid=2018&sr=b THREE'''

with mock_wire_protocol(mockwiredata.DATA_FILE) as protocol:
exthandlers_handler = get_exthandlers_handler(protocol)

original_popen = subprocess.Popen

def mock_popen(cmd, *args, **kwargs):
if cmd.endswith("sample.py -enable"):
cmd = "echo '{0}'; >&2 echo '{0}'; exit 1".format(original)
return original_popen(cmd, *args, **kwargs)

with patch.object(subprocess, 'Popen', side_effect=mock_popen):
exthandlers_handler.run()

status = exthandlers_handler.report_ext_handlers_status()
self.assertEqual(1, len(status.vmAgent.extensionHandlers), 'Expected exactly 1 extension status')
message = status.vmAgent.extensionHandlers[0].message
self.assertIn('[stdout]\n{0}'.format(expected), message, "The extension's stdout was not redacted correctly")
self.assertIn('[stderr]\n{0}'.format(expected), message, "The extension's stderr was not redacted correctly")


if __name__ == '__main__':
unittest.main()