Safely add Ansible password lookup plugin
Ansible's password lookup plugin can be useful for generating random passwords, but has other uses which could allow a nefarious user to create new files or read the contents of existing files outside the workspace (as long as those paths are writeable or readable by the user under which Ansible is executing). To that end, short-circuit and return an error if an untrusted use attempts to escape the workspace in these ways. Also increase the wait timeout for the plugins test by 25% (from 4 to 5 minutes) since this change increases the number of jobs in it. Change-Id: I0e372dda3a0f0f74d9e343c439514317dceb4d24
This commit is contained in:
parent
94ef36eb7f
commit
19def7045e
5
tests/fixtures/config/ansible/git/org_plugin-project/playbooks/password_create_bad.yaml
vendored
Normal file
5
tests/fixtures/config/ansible/git/org_plugin-project/playbooks/password_create_bad.yaml
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
- hosts: all
|
||||||
|
vars:
|
||||||
|
value: "{{ lookup('password', '/etc/passwd') }}"
|
||||||
|
tasks:
|
||||||
|
- debug: msg="value is {{ value }}"
|
5
tests/fixtures/config/ansible/git/org_plugin-project/playbooks/password_create_good.yaml
vendored
Normal file
5
tests/fixtures/config/ansible/git/org_plugin-project/playbooks/password_create_good.yaml
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
- hosts: all
|
||||||
|
vars:
|
||||||
|
value: "{{ lookup('password', '{{ zuul.executor.work_root }}/test.newpassword') }}"
|
||||||
|
tasks:
|
||||||
|
- debug: msg="value is {{ value }}"
|
5
tests/fixtures/config/ansible/git/org_plugin-project/playbooks/password_null_good.yaml
vendored
Normal file
5
tests/fixtures/config/ansible/git/org_plugin-project/playbooks/password_null_good.yaml
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
- hosts: all
|
||||||
|
vars:
|
||||||
|
value: "{{ lookup('password', '/dev/null') }}"
|
||||||
|
tasks:
|
||||||
|
- debug: msg="value is {{ value }}"
|
5
tests/fixtures/config/ansible/git/org_plugin-project/playbooks/password_read_bad.yaml
vendored
Normal file
5
tests/fixtures/config/ansible/git/org_plugin-project/playbooks/password_read_bad.yaml
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
- hosts: all
|
||||||
|
vars:
|
||||||
|
value: "{{ lookup('password', '/etc/passwd') }}"
|
||||||
|
tasks:
|
||||||
|
- debug: msg="value is {{ value }}"
|
10
tests/fixtures/config/ansible/git/org_plugin-project/playbooks/password_read_good.yaml
vendored
Normal file
10
tests/fixtures/config/ansible/git/org_plugin-project/playbooks/password_read_good.yaml
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
- hosts: all
|
||||||
|
tasks:
|
||||||
|
- copy:
|
||||||
|
content: 'an_example_password'
|
||||||
|
dest: "{{zuul.executor.work_root}}/test.password"
|
||||||
|
- hosts: all
|
||||||
|
vars:
|
||||||
|
value: "{{ lookup('password', '{{zuul.executor.work_root}}/test.password') }}"
|
||||||
|
tasks:
|
||||||
|
- debug: msg="value is {{ value }}"
|
|
@ -2556,7 +2556,7 @@ class TestAnsible25(AnsibleZuulTestCase):
|
||||||
|
|
||||||
def test_playbook(self):
|
def test_playbook(self):
|
||||||
# This test runs a bit long and needs extra time.
|
# This test runs a bit long and needs extra time.
|
||||||
self.wait_timeout = 240
|
self.wait_timeout = 300
|
||||||
# Keep the jobdir around so we can inspect contents if an
|
# Keep the jobdir around so we can inspect contents if an
|
||||||
# assert fails.
|
# assert fails.
|
||||||
self.executor_server.keep_jobdir = True
|
self.executor_server.keep_jobdir = True
|
||||||
|
@ -2707,7 +2707,13 @@ class TestAnsible25(AnsibleZuulTestCase):
|
||||||
('file_local_good', 'SUCCESS'),
|
('file_local_good', 'SUCCESS'),
|
||||||
('file_local_bad', 'FAILURE'),
|
('file_local_bad', 'FAILURE'),
|
||||||
('zuul_return', 'SUCCESS'),
|
('zuul_return', 'SUCCESS'),
|
||||||
|
('password_create_good', 'SUCCESS'),
|
||||||
|
('password_null_good', 'SUCCESS'),
|
||||||
|
('password_read_good', 'SUCCESS'),
|
||||||
|
('password_create_bad', 'FAILURE'),
|
||||||
|
('password_read_bad', 'FAILURE'),
|
||||||
]
|
]
|
||||||
|
|
||||||
for job_name, result in plugin_tests:
|
for job_name, result in plugin_tests:
|
||||||
count += 1
|
count += 1
|
||||||
self._add_job(job_name)
|
self._add_job(job_name)
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
_banned.py
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
# Copyright 2019 OpenStack Foundation
|
||||||
|
#
|
||||||
|
# This module is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This software is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this software. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
from zuul.ansible import paths
|
||||||
|
password = paths._import_ansible_lookup_plugin("password")
|
||||||
|
|
||||||
|
|
||||||
|
class LookupModule(password.LookupModule):
|
||||||
|
|
||||||
|
def run(self, terms, variables, **kwargs):
|
||||||
|
for term in terms:
|
||||||
|
relpath = password._parse_parameters(term)[0]
|
||||||
|
# /dev/null is whitelisted because it's interpreted specially
|
||||||
|
if relpath != "/dev/null":
|
||||||
|
path = self._loader.path_dwim(relpath)
|
||||||
|
paths._fail_if_unsafe(path, allow_trusted=True)
|
||||||
|
return super(LookupModule, self).run(terms, variables, **kwargs)
|
Loading…
Reference in New Issue