mirror of
https://github.com/ansible/awx.git
synced 2026-05-19 14:57:39 -02:30
Merge pull request #3569 from wenottingham/forever_blowing_bubbles
Use bubblewrap (https://github.com/projectatomic/bubblewrap) instead of proot.
This commit is contained in:
@@ -112,7 +112,7 @@ register(
|
|||||||
register(
|
register(
|
||||||
'AWX_PROOT_ENABLED',
|
'AWX_PROOT_ENABLED',
|
||||||
field_class=fields.BooleanField,
|
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.'),
|
help_text=_('Isolates an Ansible job from protected parts of the Tower system to prevent exposing sensitive information.'),
|
||||||
category=_('Jobs'),
|
category=_('Jobs'),
|
||||||
category_slug='jobs',
|
category_slug='jobs',
|
||||||
@@ -121,8 +121,8 @@ register(
|
|||||||
register(
|
register(
|
||||||
'AWX_PROOT_BASE_PATH',
|
'AWX_PROOT_BASE_PATH',
|
||||||
field_class=fields.CharField,
|
field_class=fields.CharField,
|
||||||
label=_('Base PRoot execution path'),
|
label=_('Job isolation execution path'),
|
||||||
help_text=_('The location that PRoot will create its temporary working directory.'),
|
help_text=_('Create temporary working directories for isolated jobs in this location.'),
|
||||||
category=_('Jobs'),
|
category=_('Jobs'),
|
||||||
category_slug='jobs',
|
category_slug='jobs',
|
||||||
)
|
)
|
||||||
@@ -130,8 +130,8 @@ register(
|
|||||||
register(
|
register(
|
||||||
'AWX_PROOT_HIDE_PATHS',
|
'AWX_PROOT_HIDE_PATHS',
|
||||||
field_class=fields.StringListField,
|
field_class=fields.StringListField,
|
||||||
label=_('Paths to hide from PRoot jobs'),
|
label=_('Paths to hide from isolated jobs'),
|
||||||
help_text=_('Extra paths to hide from PRoot isolated processes.'),
|
help_text=_('Additional paths to hide from isolated processes.'),
|
||||||
category=_('Jobs'),
|
category=_('Jobs'),
|
||||||
category_slug='jobs',
|
category_slug='jobs',
|
||||||
)
|
)
|
||||||
@@ -139,8 +139,8 @@ register(
|
|||||||
register(
|
register(
|
||||||
'AWX_PROOT_SHOW_PATHS',
|
'AWX_PROOT_SHOW_PATHS',
|
||||||
field_class=fields.StringListField,
|
field_class=fields.StringListField,
|
||||||
label=_('Paths to expose to PRoot jobs'),
|
label=_('Paths to expose to isolated jobs'),
|
||||||
help_text=_('Explicit whitelist of paths to expose to PRoot jobs.'),
|
help_text=_('Whitelist of paths that would otherwise be hidden to expose to isolated jobs.'),
|
||||||
category=_('Jobs'),
|
category=_('Jobs'),
|
||||||
category_slug='jobs',
|
category_slug='jobs',
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -319,19 +319,19 @@ class RunAdHocCommandTest(BaseAdHocCommandTest):
|
|||||||
self.assertIn('ssh-agent', ad_hoc_command.job_args)
|
self.assertIn('ssh-agent', ad_hoc_command.job_args)
|
||||||
self.assertNotIn('Bad passphrase', ad_hoc_command.result_stdout)
|
self.assertNotIn('Bad passphrase', ad_hoc_command.result_stdout)
|
||||||
|
|
||||||
def test_run_with_proot(self):
|
def test_run_with_bubblewrap(self):
|
||||||
# Only run test if proot is installed
|
# Only run test if bubblewrap is installed
|
||||||
cmd = [getattr(settings, 'AWX_PROOT_CMD', 'proot'), '--version']
|
cmd = [getattr(settings, 'AWX_PROOT_CMD', 'bwrap'), '--version']
|
||||||
try:
|
try:
|
||||||
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
|
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.PIPE)
|
stderr=subprocess.PIPE)
|
||||||
proc.communicate()
|
proc.communicate()
|
||||||
has_proot = bool(proc.returncode == 0)
|
has_bubblewrap = bool(proc.returncode == 0)
|
||||||
except (OSError, ValueError):
|
except (OSError, ValueError):
|
||||||
has_proot = False
|
has_bubblewrap = False
|
||||||
if not has_proot:
|
if not has_bubblewrap:
|
||||||
self.skipTest('proot is not installed')
|
self.skipTest('bubblewrap is not installed')
|
||||||
# Enable proot for this test.
|
# Enable bubblewrap for this test.
|
||||||
settings.AWX_PROOT_ENABLED = True
|
settings.AWX_PROOT_ENABLED = True
|
||||||
# Hide local settings path.
|
# Hide local settings path.
|
||||||
settings.AWX_PROOT_HIDE_PATHS = [os.path.join(settings.BASE_DIR, 'settings')]
|
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')
|
self.check_ad_hoc_command_events(ad_hoc_command, 'ok')
|
||||||
|
|
||||||
@mock.patch('awx.main.tasks.BaseTask.run_pexpect', return_value=('failed', 0))
|
@mock.patch('awx.main.tasks.BaseTask.run_pexpect', return_value=('failed', 0))
|
||||||
def test_run_with_proot_not_installed(self, ignore):
|
def test_run_with_bubblewrap_not_installed(self, ignore):
|
||||||
# Enable proot for this test, specify invalid proot cmd.
|
# Enable bubblewrap for this test, specify invalid bubblewrap cmd.
|
||||||
settings.AWX_PROOT_ENABLED = True
|
settings.AWX_PROOT_ENABLED = True
|
||||||
settings.AWX_PROOT_CMD = 'PR00T'
|
settings.AWX_PROOT_CMD = 'PR00T'
|
||||||
ad_hoc_command = self.create_test_ad_hoc_command()
|
ad_hoc_command = self.create_test_ad_hoc_command()
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ TEST_ASYNC_NOWAIT_PLAYBOOK = '''
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
TEST_PROOT_PLAYBOOK = '''
|
TEST_PROOT_PLAYBOOK = '''
|
||||||
- name: test proot environment
|
- name: test bubblewrap environment
|
||||||
hosts: test-group
|
hosts: test-group
|
||||||
gather_facts: false
|
gather_facts: false
|
||||||
connection: local
|
connection: local
|
||||||
@@ -1177,19 +1177,19 @@ class RunJobTest(BaseJobExecutionTest):
|
|||||||
|
|
||||||
@unittest.skipUnless(settings.BROKER_URL == 'redis://localhost/',
|
@unittest.skipUnless(settings.BROKER_URL == 'redis://localhost/',
|
||||||
'Non-default Redis setup.')
|
'Non-default Redis setup.')
|
||||||
def test_run_job_with_proot(self):
|
def test_run_job_with_bubblewrap(self):
|
||||||
# Only run test if proot is installed
|
# Only run test if bubblewrap is installed
|
||||||
cmd = [getattr(settings, 'AWX_PROOT_CMD', 'proot'), '--version']
|
cmd = [getattr(settings, 'AWX_PROOT_CMD', 'bwrap'), '--version']
|
||||||
try:
|
try:
|
||||||
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
|
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.PIPE)
|
stderr=subprocess.PIPE)
|
||||||
proc.communicate()
|
proc.communicate()
|
||||||
has_proot = bool(proc.returncode == 0)
|
has_bubblewrap = bool(proc.returncode == 0)
|
||||||
except (OSError, ValueError):
|
except (OSError, ValueError):
|
||||||
has_proot = False
|
has_bubblewrap = False
|
||||||
if not has_proot:
|
if not has_bubblewrap:
|
||||||
self.skipTest('proot is not installed')
|
self.skipTest('bubblewrap is not installed')
|
||||||
# Enable proot for this test.
|
# Enable bubblewrap for this test.
|
||||||
settings.AWX_PROOT_ENABLED = True
|
settings.AWX_PROOT_ENABLED = True
|
||||||
# Hide local settings path.
|
# Hide local settings path.
|
||||||
settings.AWX_PROOT_HIDE_PATHS = [os.path.join(settings.BASE_DIR, 'settings')]
|
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)
|
job = Job.objects.get(pk=job.pk)
|
||||||
self.check_job_result(job, 'successful')
|
self.check_job_result(job, 'successful')
|
||||||
|
|
||||||
def test_run_job_with_proot_not_installed(self):
|
def test_run_job_with_bubblewrap_not_installed(self):
|
||||||
# Enable proot for this test, specify invalid proot cmd.
|
# Enable bubblewrap for this test, specify invalid bubblewrap cmd.
|
||||||
settings.AWX_PROOT_ENABLED = True
|
settings.AWX_PROOT_ENABLED = True
|
||||||
settings.AWX_PROOT_CMD = 'PR00T'
|
settings.AWX_PROOT_CMD = 'PR00T'
|
||||||
self.create_test_credential()
|
self.create_test_credential()
|
||||||
|
|||||||
@@ -525,7 +525,7 @@ def check_proot_installed():
|
|||||||
Check that proot is installed.
|
Check that proot is installed.
|
||||||
'''
|
'''
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
cmd = [getattr(settings, 'AWX_PROOT_CMD', 'proot'), '--version']
|
cmd = [getattr(settings, 'AWX_PROOT_CMD', 'bwrap'), '--version']
|
||||||
try:
|
try:
|
||||||
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
|
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.PIPE)
|
stderr=subprocess.PIPE)
|
||||||
@@ -553,8 +553,7 @@ def wrap_args_with_proot(args, cwd, **kwargs):
|
|||||||
- /tmp (except for own tmp files)
|
- /tmp (except for own tmp files)
|
||||||
'''
|
'''
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
new_args = [getattr(settings, 'AWX_PROOT_CMD', 'proot'), '-v',
|
new_args = [getattr(settings, 'AWX_PROOT_CMD', 'bwrap'), '--dev-bind', '/', '/']
|
||||||
str(getattr(settings, 'AWX_PROOT_VERBOSITY', '0')), '-r', '/']
|
|
||||||
hide_paths = ['/etc/tower', '/var/lib/awx', '/var/log',
|
hide_paths = ['/etc/tower', '/var/lib/awx', '/var/log',
|
||||||
tempfile.gettempdir(), settings.PROJECTS_ROOT,
|
tempfile.gettempdir(), settings.PROJECTS_ROOT,
|
||||||
settings.JOBOUTPUT_ROOT]
|
settings.JOBOUTPUT_ROOT]
|
||||||
@@ -569,7 +568,7 @@ def wrap_args_with_proot(args, cwd, **kwargs):
|
|||||||
handle, new_path = tempfile.mkstemp(dir=kwargs['proot_temp_dir'])
|
handle, new_path = tempfile.mkstemp(dir=kwargs['proot_temp_dir'])
|
||||||
os.close(handle)
|
os.close(handle)
|
||||||
os.chmod(new_path, stat.S_IRUSR | stat.S_IWUSR)
|
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:
|
if 'private_data_dir' in kwargs:
|
||||||
show_paths = [cwd, kwargs['private_data_dir']]
|
show_paths = [cwd, kwargs['private_data_dir']]
|
||||||
else:
|
else:
|
||||||
@@ -582,8 +581,8 @@ def wrap_args_with_proot(args, cwd, **kwargs):
|
|||||||
for path in sorted(set(show_paths)):
|
for path in sorted(set(show_paths)):
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
continue
|
continue
|
||||||
new_args.extend(['-b', '%s:%s' % (path, path)])
|
new_args.extend(['--bind', '%s' % (path,), '%s' % (path,)])
|
||||||
new_args.extend(['-w', cwd])
|
new_args.extend(['--chdir', cwd])
|
||||||
new_args.extend(args)
|
new_args.extend(args)
|
||||||
return new_args
|
return new_args
|
||||||
|
|
||||||
|
|||||||
@@ -501,25 +501,25 @@ JOB_EVENT_MAX_QUEUE_SIZE = 100
|
|||||||
# Flag to enable/disable updating hosts M2M when saving job events.
|
# Flag to enable/disable updating hosts M2M when saving job events.
|
||||||
CAPTURE_JOB_EVENT_HOSTS = False
|
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.
|
# Note: This setting may be overridden by database settings.
|
||||||
AWX_PROOT_ENABLED = False
|
AWX_PROOT_ENABLED = False
|
||||||
|
|
||||||
# Command/path to proot.
|
# Command/path to bubblewrap.
|
||||||
AWX_PROOT_CMD = 'proot'
|
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.
|
# Note: This setting may be overridden by database settings.
|
||||||
AWX_PROOT_HIDE_PATHS = []
|
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.
|
# Note: This setting may be overridden by database settings.
|
||||||
AWX_PROOT_SHOW_PATHS = []
|
AWX_PROOT_SHOW_PATHS = []
|
||||||
|
|
||||||
# Number of jobs to show as part of the job template history
|
# Number of jobs to show as part of the job template history
|
||||||
AWX_JOB_TEMPLATE_HISTORY = 10
|
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.
|
# Note: This setting may be overridden by database settings.
|
||||||
AWX_PROOT_BASE_PATH = "/tmp"
|
AWX_PROOT_BASE_PATH = "/tmp"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user