Browse Source

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
tags/3.1.0
Tobias Henkel 1 year ago
parent
commit
ffe7278c08

+ 28
- 0
tests/fixtures/config/ansible-no-log/git/org_project/playbooks/no-log-unreachable.yaml View File

@@ -0,0 +1,28 @@
1
+- hosts: localhost
2
+  gather_facts: no
3
+  tasks:
4
+    - name: Add a fake host
5
+      add_host:
6
+        hostname: fake
7
+        ansible_host: notexisting.example.notexisting
8
+
9
+- hosts: fake
10
+  gather_facts: no
11
+  tasks:
12
+    - name: Run a lineinfile task
13
+      vars:
14
+        logins:
15
+          - machine: foo
16
+            login: bar
17
+            password: my-very-secret-password-1
18
+          - machine: two
19
+            login: three
20
+            password: my-very-secret-password-2
21
+      lineinfile:
22
+        path: /tmp/.netrc
23
+        mode: 0600
24
+        create: true
25
+        insertafter: EOF
26
+        line: "machine {{ item.machine }} login {{ item.login }} password {{ item.password }}"
27
+      with_items: "{{ logins }}"
28
+      no_log: true

+ 26
- 0
tests/fixtures/config/ansible-no-log/git/org_project/zuul.yaml View File

@@ -0,0 +1,26 @@
1
+- pipeline:
2
+    name: check
3
+    manager: independent
4
+    post-review: true
5
+    trigger:
6
+      gerrit:
7
+        - event: patchset-created
8
+    success:
9
+      gerrit:
10
+        Verified: 1
11
+    failure:
12
+      gerrit:
13
+        Verified: -1
14
+
15
+- job:
16
+    name: base
17
+    parent: null
18
+
19
+- job:
20
+    name: no-log-unreachable
21
+    run: playbooks/no-log-unreachable.yaml
22
+
23
+- project:
24
+    check:
25
+      jobs:
26
+        - no-log-unreachable

+ 6
- 0
tests/fixtures/config/ansible-no-log/main.yaml View File

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

+ 27
- 0
tests/unit/test_v3.py View File

@@ -3844,3 +3844,30 @@ class TestPlugins(AnsibleZuulTestCase):
3844 3844
                       roles="roles: [{zuul: 'org/project2'}]")
3845 3845
         self._run_job('filter-plugin-shared-bare-role',
3846 3846
                       roles="roles: [{zuul: 'org/project3', name: 'shared'}]")
3847
+
3848
+
3849
+class TestNoLog(AnsibleZuulTestCase):
3850
+    tenant_config_file = 'config/ansible-no-log/main.yaml'
3851
+
3852
+    def _get_file(self, build, path):
3853
+        p = os.path.join(build.jobdir.root, path)
3854
+        with open(p) as f:
3855
+            return f.read()
3856
+
3857
+    def test_no_log_unreachable(self):
3858
+        # Output extra ansible info so we might see errors.
3859
+        self.executor_server.verbose = True
3860
+        self.executor_server.keep_jobdir = True
3861
+
3862
+        A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3863
+
3864
+        self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3865
+        self.waitUntilSettled()
3866
+
3867
+        json_log = self._get_file(self.history[0], 'work/logs/job-output.json')
3868
+        text_log = self._get_file(self.history[0], 'work/logs/job-output.txt')
3869
+
3870
+        self.assertNotIn('my-very-secret-password-1', json_log)
3871
+        self.assertNotIn('my-very-secret-password-2', json_log)
3872
+        self.assertNotIn('my-very-secret-password-1', text_log)
3873
+        self.assertNotIn('my-very-secret-password-2', text_log)

+ 1
- 1
zuul/ansible/callback/zuul_json.py View File

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

+ 2
- 0
zuul/ansible/callback/zuul_stream.py View File

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

Loading…
Cancel
Save