From 8265934c2d1c41c1ad314d4672bb6203cd5e10e9 Mon Sep 17 00:00:00 2001 From: Bill Nottingham Date: Wed, 28 Sep 2016 16:57:06 -0400 Subject: [PATCH 1/3] Use bubblewrap (https://github.com/projectatomic/bubblewrap) instead of proot. --- awx/main/utils.py | 11 +++++------ awx/settings/defaults.py | 12 ++++++------ 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/awx/main/utils.py b/awx/main/utils.py index 0bb8ccc149..a4ef6a36d1 100644 --- a/awx/main/utils.py +++ b/awx/main/utils.py @@ -538,7 +538,7 @@ def check_proot_installed(): Check that proot is installed. ''' from django.conf import settings - cmd = [getattr(settings, 'AWX_PROOT_CMD', 'proot'), '--version'] + cmd = [getattr(settings, 'AWX_PROOT_CMD', 'bwrap'), '--version'] try: proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) @@ -566,8 +566,7 @@ def wrap_args_with_proot(args, cwd, **kwargs): - /tmp (except for own tmp files) ''' from django.conf import settings - new_args = [getattr(settings, 'AWX_PROOT_CMD', 'proot'), '-v', - str(getattr(settings, 'AWX_PROOT_VERBOSITY', '0')), '-r', '/'] + new_args = [getattr(settings, 'AWX_PROOT_CMD', 'bwrap'), '--dev-bind', '/', '/'] hide_paths = ['/etc/tower', '/var/lib/awx', '/var/log', tempfile.gettempdir(), settings.PROJECTS_ROOT, settings.JOBOUTPUT_ROOT] @@ -582,7 +581,7 @@ def wrap_args_with_proot(args, cwd, **kwargs): handle, new_path = tempfile.mkstemp(dir=kwargs['proot_temp_dir']) os.close(handle) os.chmod(new_path, stat.S_IRUSR | stat.S_IWUSR) - new_args.extend(['-b', '%s:%s' % (new_path, path)]) + new_args.extend(['--bind', '%s' %(new_path,), '%s' % (path,)]) if 'private_data_dir' in kwargs: show_paths = [cwd, kwargs['private_data_dir']] else: @@ -595,8 +594,8 @@ def wrap_args_with_proot(args, cwd, **kwargs): for path in sorted(set(show_paths)): if not os.path.exists(path): continue - new_args.extend(['-b', '%s:%s' % (path, path)]) - new_args.extend(['-w', cwd]) + new_args.extend(['--bind', '%s' % (path,), '%s' % (path,)]) + new_args.extend(['--chdir', cwd]) new_args.extend(args) return new_args diff --git a/awx/settings/defaults.py b/awx/settings/defaults.py index 9da2142c19..7d73d7c049 100644 --- a/awx/settings/defaults.py +++ b/awx/settings/defaults.py @@ -495,25 +495,25 @@ JOB_EVENT_MAX_QUEUE_SIZE = 100 # Flag to enable/disable updating hosts M2M when saving job events. CAPTURE_JOB_EVENT_HOSTS = False -# Enable proot support for running jobs (playbook runs only). +# Enable bubblewrap support for running jobs (playbook runs only). # Note: This setting may be overridden by database settings. AWX_PROOT_ENABLED = False -# Command/path to proot. -AWX_PROOT_CMD = 'proot' +# Command/path to bubblewrap. +AWX_PROOT_CMD = 'bwrap' -# Additional paths to hide from jobs using proot. +# Additional paths to hide from jobs using bubblewrap. # Note: This setting may be overridden by database settings. AWX_PROOT_HIDE_PATHS = [] -# Additional paths to show for jobs using proot. +# Additional paths to show for jobs using bubbelwrap. # Note: This setting may be overridden by database settings. AWX_PROOT_SHOW_PATHS = [] # Number of jobs to show as part of the job template history AWX_JOB_TEMPLATE_HISTORY = 10 -# The directory in which proot will create new temporary directories for its root +# The directory in which bubblewrap will create new temporary directories for its root # Note: This setting may be overridden by database settings. AWX_PROOT_BASE_PATH = "/tmp" From d4bffd31e7883291d978509f0d5a31f917bb33dc Mon Sep 17 00:00:00 2001 From: Bill Nottingham Date: Wed, 28 Sep 2016 17:07:43 -0400 Subject: [PATCH 2/3] Update old tests. --- awx/main/tests/old/ad_hoc.py | 20 ++++++++++---------- awx/main/tests/old/tasks.py | 22 +++++++++++----------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/awx/main/tests/old/ad_hoc.py b/awx/main/tests/old/ad_hoc.py index ec3204e6d7..2e05ae8017 100644 --- a/awx/main/tests/old/ad_hoc.py +++ b/awx/main/tests/old/ad_hoc.py @@ -319,19 +319,19 @@ class RunAdHocCommandTest(BaseAdHocCommandTest): self.assertIn('ssh-agent', ad_hoc_command.job_args) self.assertNotIn('Bad passphrase', ad_hoc_command.result_stdout) - def test_run_with_proot(self): - # Only run test if proot is installed - cmd = [getattr(settings, 'AWX_PROOT_CMD', 'proot'), '--version'] + def test_run_with_bubblewrap(self): + # Only run test if bubblewrap is installed + cmd = [getattr(settings, 'AWX_PROOT_CMD', 'bwrap'), '--version'] try: proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) proc.communicate() - has_proot = bool(proc.returncode == 0) + has_bubblewrap = bool(proc.returncode == 0) except (OSError, ValueError): - has_proot = False - if not has_proot: - self.skipTest('proot is not installed') - # Enable proot for this test. + has_bubblewrap = False + if not has_bubblewrap: + self.skipTest('bubblewrap is not installed') + # Enable bubblewrap for this test. settings.AWX_PROOT_ENABLED = True # Hide local settings path. settings.AWX_PROOT_HIDE_PATHS = [os.path.join(settings.BASE_DIR, 'settings')] @@ -362,8 +362,8 @@ class RunAdHocCommandTest(BaseAdHocCommandTest): self.check_ad_hoc_command_events(ad_hoc_command, 'ok') @mock.patch('awx.main.tasks.BaseTask.run_pexpect', return_value=('failed', 0)) - def test_run_with_proot_not_installed(self, ignore): - # Enable proot for this test, specify invalid proot cmd. + def test_run_with_bubblewrap_not_installed(self, ignore): + # Enable bubblewrap for this test, specify invalid bubblewrap cmd. settings.AWX_PROOT_ENABLED = True settings.AWX_PROOT_CMD = 'PR00T' ad_hoc_command = self.create_test_ad_hoc_command() diff --git a/awx/main/tests/old/tasks.py b/awx/main/tests/old/tasks.py index fdd30bf854..a80ea07b87 100644 --- a/awx/main/tests/old/tasks.py +++ b/awx/main/tests/old/tasks.py @@ -150,7 +150,7 @@ TEST_ASYNC_NOWAIT_PLAYBOOK = ''' ''' TEST_PROOT_PLAYBOOK = ''' -- name: test proot environment +- name: test bubblewrap environment hosts: test-group gather_facts: false connection: local @@ -1177,19 +1177,19 @@ class RunJobTest(BaseJobExecutionTest): @unittest.skipUnless(settings.BROKER_URL == 'redis://localhost/', 'Non-default Redis setup.') - def test_run_job_with_proot(self): - # Only run test if proot is installed - cmd = [getattr(settings, 'AWX_PROOT_CMD', 'proot'), '--version'] + def test_run_job_with_bubblewrap(self): + # Only run test if bubblewrap is installed + cmd = [getattr(settings, 'AWX_PROOT_CMD', 'bwrap'), '--version'] try: proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) proc.communicate() - has_proot = bool(proc.returncode == 0) + has_bubblewrap = bool(proc.returncode == 0) except (OSError, ValueError): - has_proot = False - if not has_proot: - self.skipTest('proot is not installed') - # Enable proot for this test. + has_bubblewrap = False + if not has_bubblewrap: + self.skipTest('bubblewrap is not installed') + # Enable bubblewrap for this test. settings.AWX_PROOT_ENABLED = True # Hide local settings path. settings.AWX_PROOT_HIDE_PATHS = [os.path.join(settings.BASE_DIR, 'settings')] @@ -1227,8 +1227,8 @@ class RunJobTest(BaseJobExecutionTest): job = Job.objects.get(pk=job.pk) self.check_job_result(job, 'successful') - def test_run_job_with_proot_not_installed(self): - # Enable proot for this test, specify invalid proot cmd. + def test_run_job_with_bubblewrap_not_installed(self): + # Enable bubblewrap for this test, specify invalid bubblewrap cmd. settings.AWX_PROOT_ENABLED = True settings.AWX_PROOT_CMD = 'PR00T' self.create_test_credential() From f3d4fb7d5ba2063a269a70d3b7e1be097e4e2ed4 Mon Sep 17 00:00:00 2001 From: Bill Nottingham Date: Wed, 28 Sep 2016 17:10:15 -0400 Subject: [PATCH 3/3] Use implementation-neutral label/descriptions for proot/bubblewrap configuration items. --- awx/main/conf.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/awx/main/conf.py b/awx/main/conf.py index e0d16e8542..ffce3ea61f 100644 --- a/awx/main/conf.py +++ b/awx/main/conf.py @@ -112,7 +112,7 @@ register( register( 'AWX_PROOT_ENABLED', field_class=fields.BooleanField, - label=_('Enable PRoot for Job Execution'), + label=_('Enable job isloation'), help_text=_('Isolates an Ansible job from protected parts of the Tower system to prevent exposing sensitive information.'), category=_('Jobs'), category_slug='jobs', @@ -121,8 +121,8 @@ register( register( 'AWX_PROOT_BASE_PATH', field_class=fields.CharField, - label=_('Base PRoot execution path'), - help_text=_('The location that PRoot will create its temporary working directory.'), + label=_('Job isolation execution path'), + help_text=_('Create temporary working directories for isolated jobs in this location.'), category=_('Jobs'), category_slug='jobs', ) @@ -130,8 +130,8 @@ register( register( 'AWX_PROOT_HIDE_PATHS', field_class=fields.StringListField, - label=_('Paths to hide from PRoot jobs'), - help_text=_('Extra paths to hide from PRoot isolated processes.'), + label=_('Paths to hide from isolated jobs'), + help_text=_('Additional paths to hide from isolated processes.'), category=_('Jobs'), category_slug='jobs', ) @@ -139,8 +139,8 @@ register( register( 'AWX_PROOT_SHOW_PATHS', field_class=fields.StringListField, - label=_('Paths to expose to PRoot jobs'), - help_text=_('Explicit whitelist of paths to expose to PRoot jobs.'), + label=_('Paths to expose to isolated jobs'), + help_text=_('Whitelist of paths that would otherwise be hidden to expose to isolated jobs.'), category=_('Jobs'), category_slug='jobs', )