Fix information disclosure caused by unreachable nodes

Currently we can leak secrets if we encounter unreachable nodes
combined with a task using with_items and no_log. In this case the
item variables are written to both the job-output.json and
job-output.txt. Upstream Ansible has the same issue [1].

The text log can be fixed by defining the v2_runner_on_unreachable
callback the same as v2_runner_on_failed.

The json log can be fixed the same way as the upstream Ansible issue.

[1] https://bugzilla.redhat.com/show_bug.cgi?id=1588855

Change-Id: Ie5dd2a6b11e8e276da65fe470f364107f3dd07ef
This commit is contained in:
Tobias Henkel 2018-06-08 15:25:50 +02:00 committed by Tobias Henkel
parent 896df11638
commit ffe7278c08
6 changed files with 90 additions and 1 deletions

View File

@ -0,0 +1,28 @@
- hosts: localhost
gather_facts: no
tasks:
- name: Add a fake host
add_host:
hostname: fake
ansible_host: notexisting.example.notexisting
- hosts: fake
gather_facts: no
tasks:
- name: Run a lineinfile task
vars:
logins:
- machine: foo
login: bar
password: my-very-secret-password-1
- machine: two
login: three
password: my-very-secret-password-2
lineinfile:
path: /tmp/.netrc
mode: 0600
create: true
insertafter: EOF
line: "machine {{ item.machine }} login {{ item.login }} password {{ item.password }}"
with_items: "{{ logins }}"
no_log: true

View File

@ -0,0 +1,26 @@
- pipeline:
name: check
manager: independent
post-review: true
trigger:
gerrit:
- event: patchset-created
success:
gerrit:
Verified: 1
failure:
gerrit:
Verified: -1
- job:
name: base
parent: null
- job:
name: no-log-unreachable
run: playbooks/no-log-unreachable.yaml
- project:
check:
jobs:
- no-log-unreachable

View File

@ -0,0 +1,6 @@
- tenant:
name: tenant-one
source:
gerrit:
config-projects:
- org/project

View File

@ -3844,3 +3844,30 @@ class TestPlugins(AnsibleZuulTestCase):
roles="roles: [{zuul: 'org/project2'}]")
self._run_job('filter-plugin-shared-bare-role',
roles="roles: [{zuul: 'org/project3', name: 'shared'}]")
class TestNoLog(AnsibleZuulTestCase):
tenant_config_file = 'config/ansible-no-log/main.yaml'
def _get_file(self, build, path):
p = os.path.join(build.jobdir.root, path)
with open(p) as f:
return f.read()
def test_no_log_unreachable(self):
# Output extra ansible info so we might see errors.
self.executor_server.verbose = True
self.executor_server.keep_jobdir = True
A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
self.waitUntilSettled()
json_log = self._get_file(self.history[0], 'work/logs/job-output.json')
text_log = self._get_file(self.history[0], 'work/logs/job-output.txt')
self.assertNotIn('my-very-secret-password-1', json_log)
self.assertNotIn('my-very-secret-password-2', json_log)
self.assertNotIn('my-very-secret-password-1', text_log)
self.assertNotIn('my-very-secret-password-2', text_log)

View File

@ -137,7 +137,7 @@ class CallbackModule(CallbackBase):
def v2_runner_on_ok(self, result, **kwargs):
host = result._host
if result._result.get('_ansible_no_log', False):
if result._result.get('_ansible_no_log', False) or result._task.no_log:
self.results[-1]['tasks'][-1]['hosts'][host.name] = dict(
censored="the output has been hidden due to the fact that"
" 'no_log: true' was specified for this result")

View File

@ -606,3 +606,5 @@ class CallbackModule(default.CallbackModule):
delegated_host=delegated_vars['ansible_host'])
else:
return result._host.get_name()
v2_runner_on_unreachable = v2_runner_on_failed