diff --git a/awx/conf/migrations/0009_rename_proot_settings.py b/awx/conf/migrations/0009_rename_proot_settings.py
new file mode 100644
index 0000000000..2b0e2175aa
--- /dev/null
+++ b/awx/conf/migrations/0009_rename_proot_settings.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+from django.db import migrations
+from awx.conf.migrations import _rename_setting
+
+
+def rename_proot_settings(apps, schema_editor):
+ _rename_setting.rename_setting(apps, schema_editor, old_key='AWX_PROOT_BASE_PATH', new_key='AWX_ISOLATION_BASE_PATH')
+ _rename_setting.rename_setting(apps, schema_editor, old_key='AWX_PROOT_SHOW_PATHS', new_key='AWX_ISOLATION_SHOW_PATHS')
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [('conf', '0008_subscriptions')]
+
+ operations = [migrations.RunPython(rename_proot_settings)]
diff --git a/awx/main/conf.py b/awx/main/conf.py
index 2cfe06a25f..dbeaec9040 100644
--- a/awx/main/conf.py
+++ b/awx/main/conf.py
@@ -233,16 +233,7 @@ register(
)
register(
- 'AWX_PROOT_ENABLED',
- field_class=fields.BooleanField,
- label=_('Enable job isolation'),
- help_text=_('Isolates an Ansible job from protected parts of the system to prevent exposing sensitive information.'),
- category=_('Jobs'),
- category_slug='jobs',
-)
-
-register(
- 'AWX_PROOT_BASE_PATH',
+ 'AWX_ISOLATION_BASE_PATH',
field_class=fields.CharField,
label=_('Job execution path'),
help_text=_(
@@ -255,17 +246,7 @@ register(
)
register(
- 'AWX_PROOT_HIDE_PATHS',
- field_class=fields.StringListField,
- required=False,
- label=_('Paths to hide from isolated jobs'),
- help_text=_('Additional paths to hide from isolated processes. Enter one path per line.'),
- category=_('Jobs'),
- category_slug='jobs',
-)
-
-register(
- 'AWX_PROOT_SHOW_PATHS',
+ 'AWX_ISOLATION_SHOW_PATHS',
field_class=fields.StringListField,
required=False,
label=_('Paths to expose to isolated jobs'),
diff --git a/awx/main/constants.py b/awx/main/constants.py
index db2e9c44d7..6a44087c28 100644
--- a/awx/main/constants.py
+++ b/awx/main/constants.py
@@ -52,7 +52,6 @@ ENV_BLOCKLIST = frozenset(
'VIRTUAL_ENV',
'PATH',
'PYTHONPATH',
- 'PROOT_TMP_DIR',
'JOB_ID',
'INVENTORY_ID',
'INVENTORY_SOURCE_ID',
diff --git a/awx/main/isolated/manager.py b/awx/main/isolated/manager.py
index 79dac4445f..3fbda06ab8 100644
--- a/awx/main/isolated/manager.py
+++ b/awx/main/isolated/manager.py
@@ -135,7 +135,7 @@ class IsolatedManager(object):
extravars = {
'src': self.private_data_dir,
- 'dest': settings.AWX_PROOT_BASE_PATH,
+ 'dest': settings.AWX_ISOLATION_BASE_PATH,
'ident': self.ident,
'job_id': self.instance.id,
}
@@ -304,7 +304,7 @@ class IsolatedManager(object):
if not len(instance_qs):
return
try:
- private_data_dir = tempfile.mkdtemp(prefix='awx_iso_heartbeat_', dir=settings.AWX_PROOT_BASE_PATH)
+ private_data_dir = tempfile.mkdtemp(prefix='awx_iso_heartbeat_', dir=settings.AWX_ISOLATION_BASE_PATH)
self.runner_params = self.build_runner_params([instance.hostname for instance in instance_qs])
self.runner_params['private_data_dir'] = private_data_dir
self.runner_params['forks'] = len(instance_qs)
diff --git a/awx/main/management/commands/inventory_import.py b/awx/main/management/commands/inventory_import.py
index 0a2a19937d..9cdd2f3017 100644
--- a/awx/main/management/commands/inventory_import.py
+++ b/awx/main/management/commands/inventory_import.py
@@ -69,8 +69,6 @@ class AnsibleInventoryLoader(object):
def __init__(self, source, venv_path=None, verbosity=0):
self.source = source
self.verbosity = verbosity
- # TODO: remove once proot has been removed
- self.tmp_private_dir = None
if venv_path:
self.venv_path = venv_path
else:
diff --git a/awx/main/management/commands/test_isolated_connection.py b/awx/main/management/commands/test_isolated_connection.py
index 3983967251..c89b71a892 100644
--- a/awx/main/management/commands/test_isolated_connection.py
+++ b/awx/main/management/commands/test_isolated_connection.py
@@ -25,7 +25,7 @@ class Command(BaseCommand):
raise CommandError("--hostname is a required argument")
try:
- path = tempfile.mkdtemp(prefix='awx_isolated_ssh', dir=settings.AWX_PROOT_BASE_PATH)
+ path = tempfile.mkdtemp(prefix='awx_isolated_ssh', dir=settings.AWX_ISOLATION_BASE_PATH)
ssh_key = None
if all([getattr(settings, 'AWX_ISOLATED_KEY_GENERATION', False) is True, getattr(settings, 'AWX_ISOLATED_PRIVATE_KEY', None)]):
ssh_key = settings.AWX_ISOLATED_PRIVATE_KEY
diff --git a/awx/main/tasks.py b/awx/main/tasks.py
index 36c0350259..de1b15377b 100644
--- a/awx/main/tasks.py
+++ b/awx/main/tasks.py
@@ -841,7 +841,6 @@ class BaseTask(object):
model = None
event_model = None
abstract = True
- proot_show_paths = []
def __init__(self):
self.cleanup_paths = []
@@ -908,9 +907,9 @@ class BaseTask(object):
if pull:
params['container_options'].append(f'--pull={pull}')
- if settings.AWX_PROOT_SHOW_PATHS:
+ if settings.AWX_ISOLATION_SHOW_PATHS:
params['container_volume_mounts'] = []
- for this_path in settings.AWX_PROOT_SHOW_PATHS:
+ for this_path in settings.AWX_ISOLATION_SHOW_PATHS:
params['container_volume_mounts'].append(f'{this_path}:{this_path}:Z')
return params
@@ -924,7 +923,7 @@ class BaseTask(object):
"""
Create a temporary directory for job-related files.
"""
- pdd_wrapper_path = tempfile.mkdtemp(prefix=f'pdd_wrapper_{instance.pk}_', dir=settings.AWX_PROOT_BASE_PATH)
+ pdd_wrapper_path = tempfile.mkdtemp(prefix=f'pdd_wrapper_{instance.pk}_', dir=settings.AWX_ISOLATION_BASE_PATH)
os.chmod(pdd_wrapper_path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
if settings.AWX_CLEANUP_PATHS:
self.cleanup_paths.append(pdd_wrapper_path)
@@ -1090,12 +1089,6 @@ class BaseTask(object):
"""
return False
- def should_use_proot(self, instance):
- """
- Return whether this task should use proot.
- """
- return False
-
def build_inventory(self, instance, private_data_dir):
script_params = dict(hostvars=True, towervars=True)
if hasattr(instance, 'job_slice_number'):
@@ -1371,8 +1364,8 @@ class BaseTask(object):
status = self.instance.status
raise RuntimeError('not starting %s task' % self.instance.status)
- if not os.path.exists(settings.AWX_PROOT_BASE_PATH):
- raise RuntimeError('AWX_PROOT_BASE_PATH=%s does not exist' % settings.AWX_PROOT_BASE_PATH)
+ if not os.path.exists(settings.AWX_ISOLATION_BASE_PATH):
+ raise RuntimeError('AWX_ISOLATION_BASE_PATH=%s does not exist' % settings.AWX_ISOLATION_BASE_PATH)
# store a record of the venv used at runtime
if hasattr(self.instance, 'custom_virtualenv'):
@@ -1598,8 +1591,7 @@ class RunJob(BaseTask):
env['ANSIBLE_CALLBACK_PLUGINS'] = ':'.join(settings.AWX_ANSIBLE_CALLBACK_PLUGINS)
env['AWX_HOST'] = settings.TOWER_URL_BASE
- # Create a directory for ControlPath sockets that is unique to each
- # job and visible inside the proot environment (when enabled).
+ # Create a directory for ControlPath sockets that is unique to each job
cp_dir = os.path.join(private_data_dir, 'cp')
if not os.path.exists(cp_dir):
os.mkdir(cp_dir, 0o700)
@@ -1768,14 +1760,6 @@ class RunJob(BaseTask):
"""
return settings.AWX_RESOURCE_PROFILING_ENABLED
- def should_use_proot(self, job):
- """
- Return whether this task should use proot.
- """
- if job.is_container_group_task:
- return False
- return getattr(settings, 'AWX_PROOT_ENABLED', False)
-
def build_execution_environment_params(self, instance):
if settings.IS_K8S:
return {}
@@ -1929,10 +1913,6 @@ class RunProjectUpdate(BaseTask):
event_model = ProjectUpdateEvent
event_data_key = 'project_update_id'
- @property
- def proot_show_paths(self):
- return [settings.PROJECTS_ROOT]
-
def __init__(self, *args, job_private_data_dir=None, **kwargs):
super(RunProjectUpdate, self).__init__(*args, **kwargs)
self.playbook_new_revision = None
@@ -1990,7 +1970,7 @@ class RunProjectUpdate(BaseTask):
env['DISPLAY'] = '' # Prevent stupid password popup when running tests.
# give ansible a hint about the intended tmpdir to work around issues
# like https://github.com/ansible/ansible/issues/30064
- env['TMP'] = settings.AWX_PROOT_BASE_PATH
+ env['TMP'] = settings.AWX_ISOLATION_BASE_PATH
env['PROJECT_UPDATE_ID'] = str(project_update.pk)
if settings.GALAXY_IGNORE_CERTS:
env['ANSIBLE_GALAXY_IGNORE'] = True
@@ -2394,12 +2374,6 @@ class RunProjectUpdate(BaseTask):
if status == 'successful' and instance.launch_type != 'sync':
self._update_dependent_inventories(instance, dependent_inventory_sources)
- def should_use_proot(self, project_update):
- """
- Return whether this task should use proot.
- """
- return getattr(settings, 'AWX_PROOT_ENABLED', False)
-
def build_execution_environment_params(self, instance):
if settings.IS_K8S:
return {}
@@ -2790,7 +2764,7 @@ class RunAdHocCommand(BaseTask):
env['ANSIBLE_SFTP_BATCH_MODE'] = 'False'
# Create a directory for ControlPath sockets that is unique to each
- # ad hoc command and visible inside the proot environment (when enabled).
+ # ad hoc command
cp_dir = os.path.join(private_data_dir, 'cp')
if not os.path.exists(cp_dir):
os.mkdir(cp_dir, 0o700)
@@ -2894,14 +2868,6 @@ class RunAdHocCommand(BaseTask):
d[r'Password:\s*?$'] = 'ssh_password'
return d
- def should_use_proot(self, ad_hoc_command):
- """
- Return whether this task should use proot.
- """
- if ad_hoc_command.is_container_group_task:
- return False
- return getattr(settings, 'AWX_PROOT_ENABLED', False)
-
def final_run_hook(self, adhoc_job, status, private_data_dir, fact_modification_times, isolated_manager_instance=None):
super(RunAdHocCommand, self).final_run_hook(adhoc_job, status, private_data_dir, fact_modification_times)
if isolated_manager_instance:
diff --git a/awx/main/tests/functional/api/test_settings.py b/awx/main/tests/functional/api/test_settings.py
index fa53c65aa9..84bfff2d18 100644
--- a/awx/main/tests/functional/api/test_settings.py
+++ b/awx/main/tests/functional/api/test_settings.py
@@ -33,16 +33,14 @@ def test_jobs_settings(get, put, patch, delete, admin):
response = get(url, user=admin, expect=200)
data = dict(response.data.items())
put(url, user=admin, data=data, expect=200)
- patch(url, user=admin, data={'AWX_PROOT_HIDE_PATHS': ['/home']}, expect=200)
+ patch(url, user=admin, data={'AWX_ISOLATION_SHOW_PATHS': ['/home']}, expect=200)
response = get(url, user=admin, expect=200)
- assert response.data['AWX_PROOT_HIDE_PATHS'] == ['/home']
- data.pop('AWX_PROOT_HIDE_PATHS')
- data.pop('AWX_PROOT_SHOW_PATHS')
+ assert response.data['AWX_ISOLATION_SHOW_PATHS'] == ['/home']
+ data.pop('AWX_ISOLATION_SHOW_PATHS')
data.pop('AWX_ANSIBLE_CALLBACK_PLUGINS')
put(url, user=admin, data=data, expect=200)
response = get(url, user=admin, expect=200)
- assert response.data['AWX_PROOT_HIDE_PATHS'] == []
- assert response.data['AWX_PROOT_SHOW_PATHS'] == []
+ assert response.data['AWX_ISOLATION_SHOW_PATHS'] == []
assert response.data['AWX_ANSIBLE_CALLBACK_PLUGINS'] == []
diff --git a/awx/main/tests/unit/test_tasks.py b/awx/main/tests/unit/test_tasks.py
index 01e02b67d7..26df22c4f2 100644
--- a/awx/main/tests/unit/test_tasks.py
+++ b/awx/main/tests/unit/test_tasks.py
@@ -725,7 +725,6 @@ class TestIsolatedExecution(TestJobExecution):
extra_vars = json.loads(extra_vars)
assert extra_vars['dest'] == '/tmp'
assert extra_vars['src'] == private_data
- assert extra_vars['proot_temp_dir'].startswith('/tmp/awx_proot_')
def test_systemctl_failure(self):
# If systemctl fails, read the contents of `artifacts/systemctl_logs`
diff --git a/awx/main/utils/common.py b/awx/main/utils/common.py
index 9ad45d68c6..b40f7fb270 100644
--- a/awx/main/utils/common.py
+++ b/awx/main/utils/common.py
@@ -69,9 +69,6 @@ __all__ = [
'get_system_task_capacity',
'get_cpu_capacity',
'get_mem_capacity',
- 'wrap_args_with_proot',
- 'build_proot_temp_dir',
- 'check_proot_installed',
'model_to_dict',
'NullablePromptPseudoField',
'model_instance_diff',
@@ -842,94 +839,6 @@ def set_environ(**environ):
os.environ.update(old_environ)
-@memoize()
-def check_proot_installed():
- """
- Check that proot is installed.
- """
- from django.conf import settings
-
- cmd = [getattr(settings, 'AWX_PROOT_CMD', 'bwrap'), '--version']
- try:
- proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- proc.communicate()
- return bool(proc.returncode == 0)
- except (OSError, ValueError) as e:
- if isinstance(e, ValueError) or getattr(e, 'errno', 1) != 2: # ENOENT, no such file or directory
- logger.exception('bwrap unavailable for unexpected reason.')
- return False
-
-
-def build_proot_temp_dir():
- """
- Create a temporary directory for proot to use.
- """
- from django.conf import settings
-
- path = tempfile.mkdtemp(prefix='awx_proot_', dir=settings.AWX_PROOT_BASE_PATH)
- os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
- return path
-
-
-def wrap_args_with_proot(args, cwd, **kwargs):
- """
- Wrap existing command line with proot to restrict access to:
- - AWX_PROOT_BASE_PATH (generally, /tmp) (except for own /tmp files)
- For non-isolated nodes:
- - /etc/tower (to prevent obtaining db info or secret key)
- - /var/lib/awx (except for current project)
- - /var/log/tower
- - /var/log/supervisor
- """
- from django.conf import settings
-
- cwd = os.path.realpath(cwd)
- new_args = [getattr(settings, 'AWX_PROOT_CMD', 'bwrap'), '--unshare-pid', '--dev-bind', '/', '/', '--proc', '/proc']
- hide_paths = [settings.AWX_PROOT_BASE_PATH]
- if not kwargs.get('isolated'):
- hide_paths.extend(['/etc/tower', '/var/lib/awx', '/var/log', '/etc/ssh', settings.PROJECTS_ROOT, settings.JOBOUTPUT_ROOT])
- hide_paths.extend(getattr(settings, 'AWX_PROOT_HIDE_PATHS', None) or [])
- for path in sorted(set(hide_paths)):
- if not os.path.exists(path):
- continue
- path = os.path.realpath(path)
- if os.path.isdir(path):
- new_path = tempfile.mkdtemp(dir=kwargs['proot_temp_dir'])
- os.chmod(new_path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
- else:
- 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(['--bind', '%s' % (new_path,), '%s' % (path,)])
- if kwargs.get('isolated'):
- show_paths = [kwargs['private_data_dir']]
- elif 'private_data_dir' in kwargs:
- show_paths = [cwd, kwargs['private_data_dir']]
- else:
- show_paths = [cwd]
- for venv in (settings.ANSIBLE_VENV_PATH, settings.AWX_VENV_PATH, kwargs.get('proot_custom_virtualenv')):
- if venv:
- new_args.extend(['--ro-bind', venv, venv])
- show_paths.extend(getattr(settings, 'AWX_PROOT_SHOW_PATHS', None) or [])
- show_paths.extend(kwargs.get('proot_show_paths', []))
- for path in sorted(set(show_paths)):
- if not os.path.exists(path):
- continue
- path = os.path.realpath(path)
- new_args.extend(['--bind', '%s' % (path,), '%s' % (path,)])
- if kwargs.get('isolated'):
- if '/bin/ansible-playbook' in ' '.join(args):
- # playbook runs should cwd to the SCM checkout dir
- new_args.extend(['--chdir', os.path.join(kwargs['private_data_dir'], 'project')])
- else:
- # ad-hoc runs should cwd to the root of the private data dir
- new_args.extend(['--chdir', kwargs['private_data_dir']])
- else:
- new_args.extend(['--chdir', cwd])
- new_args.extend(args)
- return new_args
-
-
def get_pk_from_dict(_dict, key):
"""
Helper for obtaining a pk from user data dict or None if not present.
diff --git a/awx/settings/defaults.py b/awx/settings/defaults.py
index 194d363a6d..e51f66007d 100644
--- a/awx/settings/defaults.py
+++ b/awx/settings/defaults.py
@@ -569,26 +569,15 @@ AWX_SHOW_PLAYBOOK_LINKS = False
# Applies to any galaxy server
GALAXY_IGNORE_CERTS = False
-# Enable bubblewrap support for running jobs (playbook runs only).
+# Additional paths to show for jobs using process isolation.
# Note: This setting may be overridden by database settings.
-AWX_PROOT_ENABLED = True
-
-# Command/path to bubblewrap.
-AWX_PROOT_CMD = 'bwrap'
-
-# 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 bubbelwrap.
-# Note: This setting may be overridden by database settings.
-AWX_PROOT_SHOW_PATHS = []
+AWX_ISOLATION_SHOW_PATHS = []
# The directory in which Tower will create new temporary directories for job
# execution and isolation (such as credential files and custom
# inventory scripts).
# Note: This setting may be overridden by database settings.
-AWX_PROOT_BASE_PATH = "/tmp"
+AWX_ISOLATION_BASE_PATH = "/tmp"
# Disable resource profiling by default
AWX_RESOURCE_PROFILING_ENABLED = False
diff --git a/awx/settings/development.py b/awx/settings/development.py
index e2a42fef67..66dc12f50f 100644
--- a/awx/settings/development.py
+++ b/awx/settings/development.py
@@ -67,10 +67,6 @@ CALLBACK_QUEUE = "callback_tasks"
# Note: This setting may be overridden by database settings.
AWX_ROLES_ENABLED = True
-# Enable PROOT for tower-qa integration tests.
-# Note: This setting may be overridden by database settings.
-AWX_PROOT_ENABLED = True
-
AWX_ISOLATED_USERNAME = 'root'
AWX_ISOLATED_CHECK_INTERVAL = 1
AWX_ISOLATED_PERIODIC_CHECK = 30
diff --git a/awx/ui_next/src/screens/Host/data.hostFacts.json b/awx/ui_next/src/screens/Host/data.hostFacts.json
index 2507d267e3..526d83b344 100644
--- a/awx/ui_next/src/screens/Host/data.hostFacts.json
+++ b/awx/ui_next/src/screens/Host/data.hostFacts.json
@@ -101,7 +101,6 @@
"VIRTUAL_ENV": "/var/lib/awx/venv/ansible",
"INVENTORY_ID": "1",
"MAX_EVENT_RES": "700000",
- "PROOT_TMP_DIR": "/tmp",
"ANSIBLE_LIBRARY": "/awx_devel/awx/plugins/library",
"SDB_NOTIFY_HOST": "docker.for.mac.host.internal",
"AWX_GROUP_QUEUES": "tower",
diff --git a/awx/ui_next/src/screens/Inventory/shared/data.hostFacts.json b/awx/ui_next/src/screens/Inventory/shared/data.hostFacts.json
index 2507d267e3..526d83b344 100644
--- a/awx/ui_next/src/screens/Inventory/shared/data.hostFacts.json
+++ b/awx/ui_next/src/screens/Inventory/shared/data.hostFacts.json
@@ -101,7 +101,6 @@
"VIRTUAL_ENV": "/var/lib/awx/venv/ansible",
"INVENTORY_ID": "1",
"MAX_EVENT_RES": "700000",
- "PROOT_TMP_DIR": "/tmp",
"ANSIBLE_LIBRARY": "/awx_devel/awx/plugins/library",
"SDB_NOTIFY_HOST": "docker.for.mac.host.internal",
"AWX_GROUP_QUEUES": "tower",
diff --git a/awx/ui_next/src/screens/Job/shared/data.job.json b/awx/ui_next/src/screens/Job/shared/data.job.json
index 614e7d6aad..8b2d31a197 100644
--- a/awx/ui_next/src/screens/Job/shared/data.job.json
+++ b/awx/ui_next/src/screens/Job/shared/data.job.json
@@ -154,7 +154,6 @@
"ANSIBLE_INVENTORY_UNPARSED_FAILED": "True",
"ANSIBLE_PARAMIKO_RECORD_HOST_KEYS": "False",
"ANSIBLE_VENV_PATH": "/var/lib/awx/venv/ansible",
- "PROOT_TMP_DIR": "/tmp",
"AWX_PRIVATE_DATA_DIR": "/tmp/awx_2_a4b1afiw",
"ANSIBLE_COLLECTIONS_PATHS": "/tmp/collections",
"PYTHONPATH": "/var/lib/awx/venv/ansible/lib/python2.7/site-packages:/awx_devel/awx/lib:",
diff --git a/awx/ui_next/src/screens/Setting/Jobs/JobsDetail/JobsDetail.test.jsx b/awx/ui_next/src/screens/Setting/Jobs/JobsDetail/JobsDetail.test.jsx
index 02ec0b8118..715bd649e3 100644
--- a/awx/ui_next/src/screens/Setting/Jobs/JobsDetail/JobsDetail.test.jsx
+++ b/awx/ui_next/src/screens/Setting/Jobs/JobsDetail/JobsDetail.test.jsx
@@ -50,7 +50,6 @@ describe('