Obey no_log even more when using ansible 2.0

Hopefully fixes #645 this time. New function handles recursing down our
results array when it's present, also attempts to proactively protect
against future data leaks by only allowing white listed fields through.
This commit is contained in:
Akita Noek
2016-01-28 11:34:43 -05:00
parent 13c01d91d5
commit 94e6d2a72a

View File

@@ -38,6 +38,7 @@ import os
import pwd import pwd
import urlparse import urlparse
import re import re
from copy import deepcopy
# Requests # Requests
import requests import requests
@@ -47,6 +48,42 @@ import zmq
import psutil import psutil
CENSOR_FIELD_WHITELIST=[
'msg',
'failed',
'changed',
'results',
'start',
'end',
'delta',
'cmd',
'_ansible_no_log',
'cmd',
'rc',
'failed_when_result',
'skip_reason',
]
def censor(obj):
if obj.get('_ansible_no_log', False):
new_obj = {}
for k in CENSOR_FIELD_WHITELIST:
if k in obj:
new_obj[k] = obj[k]
if k == 'cmd' and k in obj:
if re.search(r'\s', obj['cmd']):
new_obj['cmd'] = re.sub(r'^(([^\s\\]|\\\s)+).*$',
r'\1 <censored>',
obj['cmd'])
new_obj['censored'] = "the output has been hidden due to the fact that 'no_log: true' was specified for this result"
obj = new_obj
if 'results' in obj:
for i in xrange(len(obj['results'])):
obj['results'][i] = censor(obj['results'][i])
return obj
class TokenAuth(requests.auth.AuthBase): class TokenAuth(requests.auth.AuthBase):
def __init__(self, token): def __init__(self, token):
@@ -127,31 +164,6 @@ class BaseCallbackModule(object):
self._init_connection() self._init_connection()
if self.context is None: if self.context is None:
self._start_connection() self._start_connection()
if 'res' in event_data \
and event_data['res'].get('_ansible_no_log', False):
res = event_data['res']
if 'stdout' in res and res['stdout']:
res['stdout'] = '<censored>'
if 'stdout_lines' in res and res['stdout_lines']:
res['stdout_lines'] = ['<censored>']
if 'stderr' in res and res['stderr']:
res['stderr'] = '<censored>'
if 'stderr_lines' in res and res['stderr_lines']:
res['stderr_lines'] = ['<censored>']
if res.get('cmd', None) and re.search(r'\s', res['cmd']):
res['cmd'] = re.sub(r'^(([^\s\\]|\\\s)+).*$',
r'\1 <censored>',
res['cmd'])
if 'invocation' in res \
and 'module_args' in res['invocation'] \
and '_raw_params' in res['invocation']['module_args'] \
and re.search(r'\s',
res['invocation']['module_args']['_raw_params']):
res['invocation']['module_args']['_raw_params'] = \
re.sub(r'^(([^\s\\]|\\\s)+).*$',
r'\1 <censored>',
res['invocation']['module_args']['_raw_params'])
msg['event_data']['res'] = res
self.socket.send_json(msg) self.socket.send_json(msg)
self.socket.recv() self.socket.recv()
@@ -185,6 +197,9 @@ class BaseCallbackModule(object):
response.raise_for_status() response.raise_for_status()
def _log_event(self, event, **event_data): def _log_event(self, event, **event_data):
if 'res' in event_data:
event_data['res'] = censor(deepcopy(event_data['res']))
if self.callback_consumer_port: if self.callback_consumer_port:
self._post_job_event_queue_msg(event, event_data) self._post_job_event_queue_msg(event, event_data)
else: else: