mirror of
https://github.com/ansible/awx.git
synced 2026-03-09 05:29:26 -02:30
Merge pull request #9670 from ryanpetrello/burst-your-bubble
remove unnecessary references to bwrap, bubblewrap, and proot Reviewed-by: Jake McDermott <yo@jakemcdermott.me> Reviewed-by: Ryan Petrello <None> Reviewed-by: Bill Nottingham <None> Reviewed-by: Shane McDonald <me@shanemcd.com>
This commit is contained in:
16
awx/conf/migrations/0009_rename_proot_settings.py
Normal file
16
awx/conf/migrations/0009_rename_proot_settings.py
Normal file
@@ -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)]
|
||||||
@@ -233,16 +233,7 @@ register(
|
|||||||
)
|
)
|
||||||
|
|
||||||
register(
|
register(
|
||||||
'AWX_PROOT_ENABLED',
|
'AWX_ISOLATION_BASE_PATH',
|
||||||
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',
|
|
||||||
field_class=fields.CharField,
|
field_class=fields.CharField,
|
||||||
label=_('Job execution path'),
|
label=_('Job execution path'),
|
||||||
help_text=_(
|
help_text=_(
|
||||||
@@ -255,17 +246,7 @@ register(
|
|||||||
)
|
)
|
||||||
|
|
||||||
register(
|
register(
|
||||||
'AWX_PROOT_HIDE_PATHS',
|
'AWX_ISOLATION_SHOW_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',
|
|
||||||
field_class=fields.StringListField,
|
field_class=fields.StringListField,
|
||||||
required=False,
|
required=False,
|
||||||
label=_('Paths to expose to isolated jobs'),
|
label=_('Paths to expose to isolated jobs'),
|
||||||
|
|||||||
@@ -52,7 +52,6 @@ ENV_BLOCKLIST = frozenset(
|
|||||||
'VIRTUAL_ENV',
|
'VIRTUAL_ENV',
|
||||||
'PATH',
|
'PATH',
|
||||||
'PYTHONPATH',
|
'PYTHONPATH',
|
||||||
'PROOT_TMP_DIR',
|
|
||||||
'JOB_ID',
|
'JOB_ID',
|
||||||
'INVENTORY_ID',
|
'INVENTORY_ID',
|
||||||
'INVENTORY_SOURCE_ID',
|
'INVENTORY_SOURCE_ID',
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ class IsolatedManager(object):
|
|||||||
|
|
||||||
extravars = {
|
extravars = {
|
||||||
'src': self.private_data_dir,
|
'src': self.private_data_dir,
|
||||||
'dest': settings.AWX_PROOT_BASE_PATH,
|
'dest': settings.AWX_ISOLATION_BASE_PATH,
|
||||||
'ident': self.ident,
|
'ident': self.ident,
|
||||||
'job_id': self.instance.id,
|
'job_id': self.instance.id,
|
||||||
}
|
}
|
||||||
@@ -304,7 +304,7 @@ class IsolatedManager(object):
|
|||||||
if not len(instance_qs):
|
if not len(instance_qs):
|
||||||
return
|
return
|
||||||
try:
|
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 = self.build_runner_params([instance.hostname for instance in instance_qs])
|
||||||
self.runner_params['private_data_dir'] = private_data_dir
|
self.runner_params['private_data_dir'] = private_data_dir
|
||||||
self.runner_params['forks'] = len(instance_qs)
|
self.runner_params['forks'] = len(instance_qs)
|
||||||
|
|||||||
@@ -69,8 +69,6 @@ class AnsibleInventoryLoader(object):
|
|||||||
def __init__(self, source, venv_path=None, verbosity=0):
|
def __init__(self, source, venv_path=None, verbosity=0):
|
||||||
self.source = source
|
self.source = source
|
||||||
self.verbosity = verbosity
|
self.verbosity = verbosity
|
||||||
# TODO: remove once proot has been removed
|
|
||||||
self.tmp_private_dir = None
|
|
||||||
if venv_path:
|
if venv_path:
|
||||||
self.venv_path = venv_path
|
self.venv_path = venv_path
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class Command(BaseCommand):
|
|||||||
raise CommandError("--hostname is a required argument")
|
raise CommandError("--hostname is a required argument")
|
||||||
|
|
||||||
try:
|
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
|
ssh_key = None
|
||||||
if all([getattr(settings, 'AWX_ISOLATED_KEY_GENERATION', False) is True, getattr(settings, 'AWX_ISOLATED_PRIVATE_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
|
ssh_key = settings.AWX_ISOLATED_PRIVATE_KEY
|
||||||
|
|||||||
@@ -841,7 +841,6 @@ class BaseTask(object):
|
|||||||
model = None
|
model = None
|
||||||
event_model = None
|
event_model = None
|
||||||
abstract = True
|
abstract = True
|
||||||
proot_show_paths = []
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.cleanup_paths = []
|
self.cleanup_paths = []
|
||||||
@@ -908,9 +907,9 @@ class BaseTask(object):
|
|||||||
if pull:
|
if pull:
|
||||||
params['container_options'].append(f'--pull={pull}')
|
params['container_options'].append(f'--pull={pull}')
|
||||||
|
|
||||||
if settings.AWX_PROOT_SHOW_PATHS:
|
if settings.AWX_ISOLATION_SHOW_PATHS:
|
||||||
params['container_volume_mounts'] = []
|
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')
|
params['container_volume_mounts'].append(f'{this_path}:{this_path}:Z')
|
||||||
return params
|
return params
|
||||||
|
|
||||||
@@ -924,7 +923,7 @@ class BaseTask(object):
|
|||||||
"""
|
"""
|
||||||
Create a temporary directory for job-related files.
|
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)
|
os.chmod(pdd_wrapper_path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
|
||||||
if settings.AWX_CLEANUP_PATHS:
|
if settings.AWX_CLEANUP_PATHS:
|
||||||
self.cleanup_paths.append(pdd_wrapper_path)
|
self.cleanup_paths.append(pdd_wrapper_path)
|
||||||
@@ -1090,12 +1089,6 @@ class BaseTask(object):
|
|||||||
"""
|
"""
|
||||||
return False
|
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):
|
def build_inventory(self, instance, private_data_dir):
|
||||||
script_params = dict(hostvars=True, towervars=True)
|
script_params = dict(hostvars=True, towervars=True)
|
||||||
if hasattr(instance, 'job_slice_number'):
|
if hasattr(instance, 'job_slice_number'):
|
||||||
@@ -1371,8 +1364,8 @@ class BaseTask(object):
|
|||||||
status = self.instance.status
|
status = self.instance.status
|
||||||
raise RuntimeError('not starting %s task' % self.instance.status)
|
raise RuntimeError('not starting %s task' % self.instance.status)
|
||||||
|
|
||||||
if not os.path.exists(settings.AWX_PROOT_BASE_PATH):
|
if not os.path.exists(settings.AWX_ISOLATION_BASE_PATH):
|
||||||
raise RuntimeError('AWX_PROOT_BASE_PATH=%s does not exist' % settings.AWX_PROOT_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
|
# store a record of the venv used at runtime
|
||||||
if hasattr(self.instance, 'custom_virtualenv'):
|
if hasattr(self.instance, 'custom_virtualenv'):
|
||||||
@@ -1598,8 +1591,7 @@ class RunJob(BaseTask):
|
|||||||
env['ANSIBLE_CALLBACK_PLUGINS'] = ':'.join(settings.AWX_ANSIBLE_CALLBACK_PLUGINS)
|
env['ANSIBLE_CALLBACK_PLUGINS'] = ':'.join(settings.AWX_ANSIBLE_CALLBACK_PLUGINS)
|
||||||
env['AWX_HOST'] = settings.TOWER_URL_BASE
|
env['AWX_HOST'] = settings.TOWER_URL_BASE
|
||||||
|
|
||||||
# Create a directory for ControlPath sockets that is unique to each
|
# Create a directory for ControlPath sockets that is unique to each job
|
||||||
# job and visible inside the proot environment (when enabled).
|
|
||||||
cp_dir = os.path.join(private_data_dir, 'cp')
|
cp_dir = os.path.join(private_data_dir, 'cp')
|
||||||
if not os.path.exists(cp_dir):
|
if not os.path.exists(cp_dir):
|
||||||
os.mkdir(cp_dir, 0o700)
|
os.mkdir(cp_dir, 0o700)
|
||||||
@@ -1768,14 +1760,6 @@ class RunJob(BaseTask):
|
|||||||
"""
|
"""
|
||||||
return settings.AWX_RESOURCE_PROFILING_ENABLED
|
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):
|
def build_execution_environment_params(self, instance):
|
||||||
if settings.IS_K8S:
|
if settings.IS_K8S:
|
||||||
return {}
|
return {}
|
||||||
@@ -1929,10 +1913,6 @@ class RunProjectUpdate(BaseTask):
|
|||||||
event_model = ProjectUpdateEvent
|
event_model = ProjectUpdateEvent
|
||||||
event_data_key = 'project_update_id'
|
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):
|
def __init__(self, *args, job_private_data_dir=None, **kwargs):
|
||||||
super(RunProjectUpdate, self).__init__(*args, **kwargs)
|
super(RunProjectUpdate, self).__init__(*args, **kwargs)
|
||||||
self.playbook_new_revision = None
|
self.playbook_new_revision = None
|
||||||
@@ -1990,7 +1970,7 @@ class RunProjectUpdate(BaseTask):
|
|||||||
env['DISPLAY'] = '' # Prevent stupid password popup when running tests.
|
env['DISPLAY'] = '' # Prevent stupid password popup when running tests.
|
||||||
# give ansible a hint about the intended tmpdir to work around issues
|
# give ansible a hint about the intended tmpdir to work around issues
|
||||||
# like https://github.com/ansible/ansible/issues/30064
|
# 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)
|
env['PROJECT_UPDATE_ID'] = str(project_update.pk)
|
||||||
if settings.GALAXY_IGNORE_CERTS:
|
if settings.GALAXY_IGNORE_CERTS:
|
||||||
env['ANSIBLE_GALAXY_IGNORE'] = True
|
env['ANSIBLE_GALAXY_IGNORE'] = True
|
||||||
@@ -2394,12 +2374,6 @@ class RunProjectUpdate(BaseTask):
|
|||||||
if status == 'successful' and instance.launch_type != 'sync':
|
if status == 'successful' and instance.launch_type != 'sync':
|
||||||
self._update_dependent_inventories(instance, dependent_inventory_sources)
|
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):
|
def build_execution_environment_params(self, instance):
|
||||||
if settings.IS_K8S:
|
if settings.IS_K8S:
|
||||||
return {}
|
return {}
|
||||||
@@ -2790,7 +2764,7 @@ class RunAdHocCommand(BaseTask):
|
|||||||
env['ANSIBLE_SFTP_BATCH_MODE'] = 'False'
|
env['ANSIBLE_SFTP_BATCH_MODE'] = 'False'
|
||||||
|
|
||||||
# Create a directory for ControlPath sockets that is unique to each
|
# 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')
|
cp_dir = os.path.join(private_data_dir, 'cp')
|
||||||
if not os.path.exists(cp_dir):
|
if not os.path.exists(cp_dir):
|
||||||
os.mkdir(cp_dir, 0o700)
|
os.mkdir(cp_dir, 0o700)
|
||||||
@@ -2894,14 +2868,6 @@ class RunAdHocCommand(BaseTask):
|
|||||||
d[r'Password:\s*?$'] = 'ssh_password'
|
d[r'Password:\s*?$'] = 'ssh_password'
|
||||||
return d
|
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):
|
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)
|
super(RunAdHocCommand, self).final_run_hook(adhoc_job, status, private_data_dir, fact_modification_times)
|
||||||
if isolated_manager_instance:
|
if isolated_manager_instance:
|
||||||
|
|||||||
@@ -33,16 +33,14 @@ def test_jobs_settings(get, put, patch, delete, admin):
|
|||||||
response = get(url, user=admin, expect=200)
|
response = get(url, user=admin, expect=200)
|
||||||
data = dict(response.data.items())
|
data = dict(response.data.items())
|
||||||
put(url, user=admin, data=data, expect=200)
|
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)
|
response = get(url, user=admin, expect=200)
|
||||||
assert response.data['AWX_PROOT_HIDE_PATHS'] == ['/home']
|
assert response.data['AWX_ISOLATION_SHOW_PATHS'] == ['/home']
|
||||||
data.pop('AWX_PROOT_HIDE_PATHS')
|
data.pop('AWX_ISOLATION_SHOW_PATHS')
|
||||||
data.pop('AWX_PROOT_SHOW_PATHS')
|
|
||||||
data.pop('AWX_ANSIBLE_CALLBACK_PLUGINS')
|
data.pop('AWX_ANSIBLE_CALLBACK_PLUGINS')
|
||||||
put(url, user=admin, data=data, expect=200)
|
put(url, user=admin, data=data, expect=200)
|
||||||
response = get(url, user=admin, expect=200)
|
response = get(url, user=admin, expect=200)
|
||||||
assert response.data['AWX_PROOT_HIDE_PATHS'] == []
|
assert response.data['AWX_ISOLATION_SHOW_PATHS'] == []
|
||||||
assert response.data['AWX_PROOT_SHOW_PATHS'] == []
|
|
||||||
assert response.data['AWX_ANSIBLE_CALLBACK_PLUGINS'] == []
|
assert response.data['AWX_ANSIBLE_CALLBACK_PLUGINS'] == []
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -725,7 +725,6 @@ class TestIsolatedExecution(TestJobExecution):
|
|||||||
extra_vars = json.loads(extra_vars)
|
extra_vars = json.loads(extra_vars)
|
||||||
assert extra_vars['dest'] == '/tmp'
|
assert extra_vars['dest'] == '/tmp'
|
||||||
assert extra_vars['src'] == private_data
|
assert extra_vars['src'] == private_data
|
||||||
assert extra_vars['proot_temp_dir'].startswith('/tmp/awx_proot_')
|
|
||||||
|
|
||||||
def test_systemctl_failure(self):
|
def test_systemctl_failure(self):
|
||||||
# If systemctl fails, read the contents of `artifacts/systemctl_logs`
|
# If systemctl fails, read the contents of `artifacts/systemctl_logs`
|
||||||
|
|||||||
@@ -69,9 +69,6 @@ __all__ = [
|
|||||||
'get_system_task_capacity',
|
'get_system_task_capacity',
|
||||||
'get_cpu_capacity',
|
'get_cpu_capacity',
|
||||||
'get_mem_capacity',
|
'get_mem_capacity',
|
||||||
'wrap_args_with_proot',
|
|
||||||
'build_proot_temp_dir',
|
|
||||||
'check_proot_installed',
|
|
||||||
'model_to_dict',
|
'model_to_dict',
|
||||||
'NullablePromptPseudoField',
|
'NullablePromptPseudoField',
|
||||||
'model_instance_diff',
|
'model_instance_diff',
|
||||||
@@ -842,94 +839,6 @@ def set_environ(**environ):
|
|||||||
os.environ.update(old_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):
|
def get_pk_from_dict(_dict, key):
|
||||||
"""
|
"""
|
||||||
Helper for obtaining a pk from user data dict or None if not present.
|
Helper for obtaining a pk from user data dict or None if not present.
|
||||||
|
|||||||
@@ -569,26 +569,15 @@ AWX_SHOW_PLAYBOOK_LINKS = False
|
|||||||
# Applies to any galaxy server
|
# Applies to any galaxy server
|
||||||
GALAXY_IGNORE_CERTS = False
|
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.
|
# Note: This setting may be overridden by database settings.
|
||||||
AWX_PROOT_ENABLED = True
|
AWX_ISOLATION_SHOW_PATHS = []
|
||||||
|
|
||||||
# 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 = []
|
|
||||||
|
|
||||||
# The directory in which Tower will create new temporary directories for job
|
# The directory in which Tower will create new temporary directories for job
|
||||||
# execution and isolation (such as credential files and custom
|
# execution and isolation (such as credential files and custom
|
||||||
# inventory scripts).
|
# inventory scripts).
|
||||||
# Note: This setting may be overridden by database settings.
|
# Note: This setting may be overridden by database settings.
|
||||||
AWX_PROOT_BASE_PATH = "/tmp"
|
AWX_ISOLATION_BASE_PATH = "/tmp"
|
||||||
|
|
||||||
# Disable resource profiling by default
|
# Disable resource profiling by default
|
||||||
AWX_RESOURCE_PROFILING_ENABLED = False
|
AWX_RESOURCE_PROFILING_ENABLED = False
|
||||||
|
|||||||
@@ -67,10 +67,6 @@ CALLBACK_QUEUE = "callback_tasks"
|
|||||||
# Note: This setting may be overridden by database settings.
|
# Note: This setting may be overridden by database settings.
|
||||||
AWX_ROLES_ENABLED = True
|
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_USERNAME = 'root'
|
||||||
AWX_ISOLATED_CHECK_INTERVAL = 1
|
AWX_ISOLATED_CHECK_INTERVAL = 1
|
||||||
AWX_ISOLATED_PERIODIC_CHECK = 30
|
AWX_ISOLATED_PERIODIC_CHECK = 30
|
||||||
|
|||||||
@@ -101,7 +101,6 @@
|
|||||||
"VIRTUAL_ENV": "/var/lib/awx/venv/ansible",
|
"VIRTUAL_ENV": "/var/lib/awx/venv/ansible",
|
||||||
"INVENTORY_ID": "1",
|
"INVENTORY_ID": "1",
|
||||||
"MAX_EVENT_RES": "700000",
|
"MAX_EVENT_RES": "700000",
|
||||||
"PROOT_TMP_DIR": "/tmp",
|
|
||||||
"ANSIBLE_LIBRARY": "/awx_devel/awx/plugins/library",
|
"ANSIBLE_LIBRARY": "/awx_devel/awx/plugins/library",
|
||||||
"SDB_NOTIFY_HOST": "docker.for.mac.host.internal",
|
"SDB_NOTIFY_HOST": "docker.for.mac.host.internal",
|
||||||
"AWX_GROUP_QUEUES": "tower",
|
"AWX_GROUP_QUEUES": "tower",
|
||||||
|
|||||||
@@ -101,7 +101,6 @@
|
|||||||
"VIRTUAL_ENV": "/var/lib/awx/venv/ansible",
|
"VIRTUAL_ENV": "/var/lib/awx/venv/ansible",
|
||||||
"INVENTORY_ID": "1",
|
"INVENTORY_ID": "1",
|
||||||
"MAX_EVENT_RES": "700000",
|
"MAX_EVENT_RES": "700000",
|
||||||
"PROOT_TMP_DIR": "/tmp",
|
|
||||||
"ANSIBLE_LIBRARY": "/awx_devel/awx/plugins/library",
|
"ANSIBLE_LIBRARY": "/awx_devel/awx/plugins/library",
|
||||||
"SDB_NOTIFY_HOST": "docker.for.mac.host.internal",
|
"SDB_NOTIFY_HOST": "docker.for.mac.host.internal",
|
||||||
"AWX_GROUP_QUEUES": "tower",
|
"AWX_GROUP_QUEUES": "tower",
|
||||||
|
|||||||
@@ -154,7 +154,6 @@
|
|||||||
"ANSIBLE_INVENTORY_UNPARSED_FAILED": "True",
|
"ANSIBLE_INVENTORY_UNPARSED_FAILED": "True",
|
||||||
"ANSIBLE_PARAMIKO_RECORD_HOST_KEYS": "False",
|
"ANSIBLE_PARAMIKO_RECORD_HOST_KEYS": "False",
|
||||||
"ANSIBLE_VENV_PATH": "/var/lib/awx/venv/ansible",
|
"ANSIBLE_VENV_PATH": "/var/lib/awx/venv/ansible",
|
||||||
"PROOT_TMP_DIR": "/tmp",
|
|
||||||
"AWX_PRIVATE_DATA_DIR": "/tmp/awx_2_a4b1afiw",
|
"AWX_PRIVATE_DATA_DIR": "/tmp/awx_2_a4b1afiw",
|
||||||
"ANSIBLE_COLLECTIONS_PATHS": "/tmp/collections",
|
"ANSIBLE_COLLECTIONS_PATHS": "/tmp/collections",
|
||||||
"PYTHONPATH": "/var/lib/awx/venv/ansible/lib/python2.7/site-packages:/awx_devel/awx/lib:",
|
"PYTHONPATH": "/var/lib/awx/venv/ansible/lib/python2.7/site-packages:/awx_devel/awx/lib:",
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ describe('<JobsDetail />', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should render expected details', () => {
|
test('should render expected details', () => {
|
||||||
assertDetail(wrapper, 'Enable job isolation', 'On');
|
|
||||||
assertDetail(wrapper, 'Job execution path', '/tmp');
|
assertDetail(wrapper, 'Job execution path', '/tmp');
|
||||||
assertDetail(wrapper, 'Isolated status check interval', '1 seconds');
|
assertDetail(wrapper, 'Isolated status check interval', '1 seconds');
|
||||||
assertDetail(wrapper, 'Isolated launch timeout', '600 seconds');
|
assertDetail(wrapper, 'Isolated launch timeout', '600 seconds');
|
||||||
@@ -81,7 +80,6 @@ describe('<JobsDetail />', () => {
|
|||||||
'Ansible Modules Allowed for Ad Hoc Jobs',
|
'Ansible Modules Allowed for Ad Hoc Jobs',
|
||||||
'[\n "command"\n]'
|
'[\n "command"\n]'
|
||||||
);
|
);
|
||||||
assertVariableDetail(wrapper, 'Paths to hide from isolated jobs', '[]');
|
|
||||||
assertVariableDetail(wrapper, 'Paths to expose to isolated jobs', '[]');
|
assertVariableDetail(wrapper, 'Paths to expose to isolated jobs', '[]');
|
||||||
assertVariableDetail(wrapper, 'Extra Environment Variables', '{}');
|
assertVariableDetail(wrapper, 'Extra Environment Variables', '{}');
|
||||||
assertVariableDetail(wrapper, 'Ansible Callback Plugins', '[]');
|
assertVariableDetail(wrapper, 'Ansible Callback Plugins', '[]');
|
||||||
|
|||||||
@@ -70,8 +70,7 @@ function JobsEdit() {
|
|||||||
await submitForm({
|
await submitForm({
|
||||||
...form,
|
...form,
|
||||||
AD_HOC_COMMANDS: formatJson(form.AD_HOC_COMMANDS),
|
AD_HOC_COMMANDS: formatJson(form.AD_HOC_COMMANDS),
|
||||||
AWX_PROOT_SHOW_PATHS: formatJson(form.AWX_PROOT_SHOW_PATHS),
|
AWX_ISOLATION_SHOW_PATHS: formatJson(form.AWX_ISOLATION_SHOW_PATHS),
|
||||||
AWX_PROOT_HIDE_PATHS: formatJson(form.AWX_PROOT_HIDE_PATHS),
|
|
||||||
AWX_ANSIBLE_CALLBACK_PLUGINS: formatJson(
|
AWX_ANSIBLE_CALLBACK_PLUGINS: formatJson(
|
||||||
form.AWX_ANSIBLE_CALLBACK_PLUGINS
|
form.AWX_ANSIBLE_CALLBACK_PLUGINS
|
||||||
),
|
),
|
||||||
@@ -116,8 +115,8 @@ function JobsEdit() {
|
|||||||
<Form autoComplete="off" onSubmit={formik.handleSubmit}>
|
<Form autoComplete="off" onSubmit={formik.handleSubmit}>
|
||||||
<FormColumnLayout>
|
<FormColumnLayout>
|
||||||
<InputField
|
<InputField
|
||||||
name="AWX_PROOT_BASE_PATH"
|
name="AWX_ISOLATION_BASE_PATH"
|
||||||
config={jobs.AWX_PROOT_BASE_PATH}
|
config={jobs.AWX_ISOLATION_BASE_PATH}
|
||||||
isRequired
|
isRequired
|
||||||
/>
|
/>
|
||||||
<InputField
|
<InputField
|
||||||
@@ -151,10 +150,6 @@ function JobsEdit() {
|
|||||||
config={jobs.MAX_FORKS}
|
config={jobs.MAX_FORKS}
|
||||||
type="number"
|
type="number"
|
||||||
/>
|
/>
|
||||||
<BooleanField
|
|
||||||
name="AWX_PROOT_ENABLED"
|
|
||||||
config={jobs.AWX_PROOT_ENABLED}
|
|
||||||
/>
|
|
||||||
<BooleanField
|
<BooleanField
|
||||||
name="PROJECT_UPDATE_VVV"
|
name="PROJECT_UPDATE_VVV"
|
||||||
config={jobs.PROJECT_UPDATE_VVV}
|
config={jobs.PROJECT_UPDATE_VVV}
|
||||||
@@ -209,12 +204,8 @@ function JobsEdit() {
|
|||||||
config={jobs.AWX_ANSIBLE_CALLBACK_PLUGINS}
|
config={jobs.AWX_ANSIBLE_CALLBACK_PLUGINS}
|
||||||
/>
|
/>
|
||||||
<ObjectField
|
<ObjectField
|
||||||
name="AWX_PROOT_SHOW_PATHS"
|
name="AWX_ISOLATION_SHOW_PATHS"
|
||||||
config={jobs.AWX_PROOT_SHOW_PATHS}
|
config={jobs.AWX_ISOLATION_SHOW_PATHS}
|
||||||
/>
|
|
||||||
<ObjectField
|
|
||||||
name="AWX_PROOT_HIDE_PATHS"
|
|
||||||
config={jobs.AWX_PROOT_HIDE_PATHS}
|
|
||||||
/>
|
/>
|
||||||
<ObjectField name="AWX_TASK_ENV" config={jobs.AWX_TASK_ENV} />
|
<ObjectField name="AWX_TASK_ENV" config={jobs.AWX_TASK_ENV} />
|
||||||
{submitError && <FormSubmitError error={submitError} />}
|
{submitError && <FormSubmitError error={submitError} />}
|
||||||
|
|||||||
@@ -27,10 +27,8 @@
|
|||||||
"AWX_ISOLATED_CONNECTION_TIMEOUT": 10,
|
"AWX_ISOLATED_CONNECTION_TIMEOUT": 10,
|
||||||
"AWX_ISOLATED_HOST_KEY_CHECKING": false,
|
"AWX_ISOLATED_HOST_KEY_CHECKING": false,
|
||||||
"AWX_ISOLATED_LAUNCH_TIMEOUT": 600,
|
"AWX_ISOLATED_LAUNCH_TIMEOUT": 600,
|
||||||
"AWX_PROOT_BASE_PATH": "/tmp",
|
"AWX_ISOLATION_BASE_PATH": "/tmp",
|
||||||
"AWX_PROOT_ENABLED": true,
|
"AWX_ISOLATION_SHOW_PATHS": [],
|
||||||
"AWX_PROOT_HIDE_PATHS": [],
|
|
||||||
"AWX_PROOT_SHOW_PATHS": [],
|
|
||||||
"AWX_RESOURCE_PROFILING_CPU_POLL_INTERVAL": 0.25,
|
"AWX_RESOURCE_PROFILING_CPU_POLL_INTERVAL": 0.25,
|
||||||
"AWX_RESOURCE_PROFILING_ENABLED": false,
|
"AWX_RESOURCE_PROFILING_ENABLED": false,
|
||||||
"AWX_RESOURCE_PROFILING_MEMORY_POLL_INTERVAL": 0.25,
|
"AWX_RESOURCE_PROFILING_MEMORY_POLL_INTERVAL": 0.25,
|
||||||
|
|||||||
@@ -166,15 +166,7 @@
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"AWX_PROOT_ENABLED": {
|
"AWX_ISOLATION_BASE_PATH": {
|
||||||
"type": "boolean",
|
|
||||||
"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",
|
|
||||||
"defined_in_file": false
|
|
||||||
},
|
|
||||||
"AWX_PROOT_BASE_PATH": {
|
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"label": "Job execution path",
|
"label": "Job execution path",
|
||||||
"help_text": "The directory in which Tower will create new temporary directories for job execution and isolation (such as credential files and custom inventory scripts).",
|
"help_text": "The directory in which Tower will create new temporary directories for job execution and isolation (such as credential files and custom inventory scripts).",
|
||||||
@@ -182,18 +174,7 @@
|
|||||||
"category_slug": "jobs",
|
"category_slug": "jobs",
|
||||||
"defined_in_file": false
|
"defined_in_file": false
|
||||||
},
|
},
|
||||||
"AWX_PROOT_HIDE_PATHS": {
|
"AWX_ISOLATION_SHOW_PATHS": {
|
||||||
"type": "list",
|
|
||||||
"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",
|
|
||||||
"defined_in_file": false,
|
|
||||||
"child": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AWX_PROOT_SHOW_PATHS": {
|
|
||||||
"type": "list",
|
"type": "list",
|
||||||
"label": "Paths to expose to isolated jobs",
|
"label": "Paths to expose to isolated jobs",
|
||||||
"help_text": "List of paths that would otherwise be hidden to expose to isolated jobs. Enter one path per line.",
|
"help_text": "List of paths that would otherwise be hidden to expose to isolated jobs. Enter one path per line.",
|
||||||
@@ -3158,16 +3139,7 @@
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"AWX_PROOT_ENABLED": {
|
"AWX_ISOLATION_BASE_PATH": {
|
||||||
"type": "boolean",
|
|
||||||
"required": true,
|
|
||||||
"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",
|
|
||||||
"default": true
|
|
||||||
},
|
|
||||||
"AWX_PROOT_BASE_PATH": {
|
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"required": true,
|
"required": true,
|
||||||
"label": "Job execution path",
|
"label": "Job execution path",
|
||||||
@@ -3176,21 +3148,7 @@
|
|||||||
"category_slug": "jobs",
|
"category_slug": "jobs",
|
||||||
"default": "/tmp"
|
"default": "/tmp"
|
||||||
},
|
},
|
||||||
"AWX_PROOT_HIDE_PATHS": {
|
"AWX_ISOLATION_SHOW_PATHS": {
|
||||||
"type": "list",
|
|
||||||
"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",
|
|
||||||
"default": [],
|
|
||||||
"child": {
|
|
||||||
"type": "string",
|
|
||||||
"required": true,
|
|
||||||
"read_only": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AWX_PROOT_SHOW_PATHS": {
|
|
||||||
"type": "list",
|
"type": "list",
|
||||||
"required": false,
|
"required": false,
|
||||||
"label": "Paths to expose to isolated jobs",
|
"label": "Paths to expose to isolated jobs",
|
||||||
|
|||||||
@@ -34,10 +34,8 @@
|
|||||||
"win_user"
|
"win_user"
|
||||||
],
|
],
|
||||||
"ALLOW_JINJA_IN_EXTRA_VARS":"template",
|
"ALLOW_JINJA_IN_EXTRA_VARS":"template",
|
||||||
"AWX_PROOT_ENABLED":true,
|
"AWX_ISOLATION_BASE_PATH":"/tmp",
|
||||||
"AWX_PROOT_BASE_PATH":"/tmp",
|
"AWX_ISOLATION_SHOW_PATHS":[],
|
||||||
"AWX_PROOT_HIDE_PATHS":[],
|
|
||||||
"AWX_PROOT_SHOW_PATHS":[],
|
|
||||||
"AWX_ISOLATED_CHECK_INTERVAL":1,
|
"AWX_ISOLATED_CHECK_INTERVAL":1,
|
||||||
"AWX_ISOLATED_LAUNCH_TIMEOUT":600,
|
"AWX_ISOLATED_LAUNCH_TIMEOUT":600,
|
||||||
"AWX_ISOLATED_CONNECTION_TIMEOUT":10,
|
"AWX_ISOLATED_CONNECTION_TIMEOUT":10,
|
||||||
|
|||||||
@@ -4,10 +4,8 @@
|
|||||||
"command"
|
"command"
|
||||||
],
|
],
|
||||||
"ALLOW_JINJA_IN_EXTRA_VARS": "template",
|
"ALLOW_JINJA_IN_EXTRA_VARS": "template",
|
||||||
"AWX_PROOT_ENABLED": true,
|
"AWX_ISOLATION_BASE_PATH": "/tmp",
|
||||||
"AWX_PROOT_BASE_PATH": "/tmp",
|
"AWX_ISOLATION_SHOW_PATHS": [],
|
||||||
"AWX_PROOT_HIDE_PATHS": [],
|
|
||||||
"AWX_PROOT_SHOW_PATHS": [],
|
|
||||||
"AWX_ISOLATED_CHECK_INTERVAL": 1,
|
"AWX_ISOLATED_CHECK_INTERVAL": 1,
|
||||||
"AWX_ISOLATED_LAUNCH_TIMEOUT": 600,
|
"AWX_ISOLATED_LAUNCH_TIMEOUT": 600,
|
||||||
"AWX_ISOLATED_CONNECTION_TIMEOUT": 10,
|
"AWX_ISOLATED_CONNECTION_TIMEOUT": 10,
|
||||||
|
|||||||
@@ -41,15 +41,15 @@ extends_documentation_fragment: awx.awx.auth
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
EXAMPLES = '''
|
EXAMPLES = '''
|
||||||
- name: Set the value of AWX_PROOT_BASE_PATH
|
- name: Set the value of AWX_ISOLATION_BASE_PATH
|
||||||
tower_settings:
|
tower_settings:
|
||||||
name: AWX_PROOT_BASE_PATH
|
name: AWX_ISOLATION_BASE_PATH
|
||||||
value: "/tmp"
|
value: "/tmp"
|
||||||
register: testing_settings
|
register: testing_settings
|
||||||
|
|
||||||
- name: Set the value of AWX_PROOT_SHOW_PATHS
|
- name: Set the value of AWX_ISOLATION_SHOW_PATHS
|
||||||
tower_settings:
|
tower_settings:
|
||||||
name: "AWX_PROOT_SHOW_PATHS"
|
name: "AWX_ISOLATION_SHOW_PATHS"
|
||||||
value: "'/var/lib/awx/projects/', '/tmp'"
|
value: "'/var/lib/awx/projects/', '/tmp'"
|
||||||
register: testing_settings
|
register: testing_settings
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
-----END EC PRIVATE KEY-----
|
-----END EC PRIVATE KEY-----
|
||||||
organization: Default
|
organization: Default
|
||||||
|
|
||||||
- name: Disable bubblewrap
|
- name: Disable process isolation
|
||||||
command: tower-cli setting modify AWX_PROOT_ENABLED false
|
command: tower-cli setting modify AWX_PROOT_ENABLED false
|
||||||
|
|
||||||
- block:
|
- block:
|
||||||
@@ -54,5 +54,5 @@
|
|||||||
--credential dummy --module-name command
|
--credential dummy --module-name command
|
||||||
--module-args "mkdir -p {{ project_base_dir }}/{{ project_dir_name }}"
|
--module-args "mkdir -p {{ project_base_dir }}/{{ project_dir_name }}"
|
||||||
always:
|
always:
|
||||||
- name: enable bubblewrap
|
- name: enable process isolation
|
||||||
command: tower-cli setting modify AWX_PROOT_ENABLED true
|
command: tower-cli setting modify AWX_PROOT_ENABLED true
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
---
|
---
|
||||||
- name: Set the value of AWX_PROOT_SHOW_PATHS to a baseline
|
- name: Set the value of AWX_ISOLATION_SHOW_PATHS to a baseline
|
||||||
tower_settings:
|
tower_settings:
|
||||||
name: AWX_PROOT_SHOW_PATHS
|
name: AWX_ISOLATION_SHOW_PATHS
|
||||||
value: '["/var/lib/awx/projects/"]'
|
value: '["/var/lib/awx/projects/"]'
|
||||||
|
|
||||||
- name: Set the value of AWX_PROOT_SHOW_PATHS to get an error back from Tower
|
- name: Set the value of AWX_ISOLATION_SHOW_PATHS to get an error back from Tower
|
||||||
tower_settings:
|
tower_settings:
|
||||||
settings:
|
settings:
|
||||||
AWX_PROOT_SHOW_PATHS:
|
AWX_ISOLATION_SHOW_PATHS:
|
||||||
'not': 'a valid'
|
'not': 'a valid'
|
||||||
'tower': 'setting'
|
'tower': 'setting'
|
||||||
register: result
|
register: result
|
||||||
@@ -17,9 +17,9 @@
|
|||||||
that:
|
that:
|
||||||
- "result is failed"
|
- "result is failed"
|
||||||
|
|
||||||
- name: Set the value of AWX_PROOT_SHOW_PATHS
|
- name: Set the value of AWX_ISOLATION_SHOW_PATHS
|
||||||
tower_settings:
|
tower_settings:
|
||||||
name: AWX_PROOT_SHOW_PATHS
|
name: AWX_ISOLATION_SHOW_PATHS
|
||||||
value: '["/var/lib/awx/projects/", "/tmp"]'
|
value: '["/var/lib/awx/projects/", "/tmp"]'
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
@@ -27,9 +27,9 @@
|
|||||||
that:
|
that:
|
||||||
- "result is changed"
|
- "result is changed"
|
||||||
|
|
||||||
- name: Attempt to set the value of AWX_PROOT_BASE_PATH to what it already is
|
- name: Attempt to set the value of AWX_ISOLATION_BASE_PATH to what it already is
|
||||||
tower_settings:
|
tower_settings:
|
||||||
name: AWX_PROOT_BASE_PATH
|
name: AWX_ISOLATION_BASE_PATH
|
||||||
value: /tmp
|
value: /tmp
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@
|
|||||||
|
|
||||||
- name: Apply a single setting via settings
|
- name: Apply a single setting via settings
|
||||||
tower_settings:
|
tower_settings:
|
||||||
name: AWX_PROOT_SHOW_PATHS
|
name: AWX_ISOLATION_SHOW_PATHS
|
||||||
value: '["/var/lib/awx/projects/", "/var/tmp"]'
|
value: '["/var/lib/awx/projects/", "/var/tmp"]'
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
@@ -53,8 +53,8 @@
|
|||||||
- name: Apply multiple setting via settings with no change
|
- name: Apply multiple setting via settings with no change
|
||||||
tower_settings:
|
tower_settings:
|
||||||
settings:
|
settings:
|
||||||
AWX_PROOT_BASE_PATH: /tmp
|
AWX_ISOLATION_BASE_PATH: /tmp
|
||||||
AWX_PROOT_SHOW_PATHS: ["/var/lib/awx/projects/", "/var/tmp"]
|
AWX_ISOLATION_SHOW_PATHS: ["/var/lib/awx/projects/", "/var/tmp"]
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
- debug:
|
- debug:
|
||||||
@@ -67,8 +67,8 @@
|
|||||||
- name: Apply multiple setting via settings with change
|
- name: Apply multiple setting via settings with change
|
||||||
tower_settings:
|
tower_settings:
|
||||||
settings:
|
settings:
|
||||||
AWX_PROOT_BASE_PATH: /tmp
|
AWX_ISOLATION_BASE_PATH: /tmp
|
||||||
AWX_PROOT_SHOW_PATHS: []
|
AWX_ISOLATION_SHOW_PATHS: []
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
- assert:
|
- assert:
|
||||||
@@ -77,7 +77,7 @@
|
|||||||
|
|
||||||
- name: Handle an omit value
|
- name: Handle an omit value
|
||||||
tower_settings:
|
tower_settings:
|
||||||
name: AWX_PROOT_BASE_PATH
|
name: AWX_ISOLATION_BASE_PATH
|
||||||
value: '{{ junk_var | default(omit) }}'
|
value: '{{ junk_var | default(omit) }}'
|
||||||
register: result
|
register: result
|
||||||
ignore_errors: true
|
ignore_errors: true
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ When a job is scheduled to run on an "isolated" instance:
|
|||||||
- a static inventory file
|
- a static inventory file
|
||||||
- pexpect passwords
|
- pexpect passwords
|
||||||
- environment variables
|
- environment variables
|
||||||
- the `ansible`/`ansible-playbook` command invocation, _i.e._, `bwrap ... ansible-playbook -i /path/to/inventory /path/to/playbook.yml -e ...`
|
- the `ansible`/`ansible-playbook` command invocation, _i.e._, `ansible-playbook -i /path/to/inventory /path/to/playbook.yml -e ...`
|
||||||
|
|
||||||
* Once the metadata has been `rsync`ed to the isolated host, the "controller instance" starts a process on the "isolated" instance which consumes the metadata and starts running `ansible`/`ansible-playbook`. As the playbook runs, job artifacts (such as `stdout` and job events) are written to disk on the "isolated" instance.
|
* Once the metadata has been `rsync`ed to the isolated host, the "controller instance" starts a process on the "isolated" instance which consumes the metadata and starts running `ansible`/`ansible-playbook`. As the playbook runs, job artifacts (such as `stdout` and job events) are written to disk on the "isolated" instance.
|
||||||
|
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
## Process Isolation Overview
|
|
||||||
|
|
||||||
In older versions of Ansible Tower, we used a system called `proot` to isolate Tower job processes from the rest of the system.
|
|
||||||
|
|
||||||
Tower version 3.1 and later switched to using `bubblewrap`, which is a much lighter-weight and maintained process isolation system.
|
|
||||||
|
|
||||||
Tower 3.5 and later uses the process isolation feature in Ansible runner to achieve process isolation.
|
|
||||||
|
|
||||||
|
|
||||||
### Activating Process Isolation
|
|
||||||
|
|
||||||
`bubblewrap` is enabled by default; it can be turned off via Tower Config or from a Tower settings file:
|
|
||||||
|
|
||||||
AWX_PROOT_ENABLED = False
|
|
||||||
|
|
||||||
Process isolation, when enabled, will be used for the following Job Types:
|
|
||||||
|
|
||||||
* Job Templates - Launching jobs from regular job templates
|
|
||||||
* Ad-hoc Commands - Launching ad-hoc commands against one or more hosts in inventory
|
|
||||||
|
|
||||||
|
|
||||||
### Tunables
|
|
||||||
|
|
||||||
Process Isolation will, by default, hide the following directories from the tasks mentioned above:
|
|
||||||
|
|
||||||
* `/etc/tower` - To prevent exposing Tower configuration
|
|
||||||
* `/var/lib/awx` - With the exception of the current project being used (for regular job templates)
|
|
||||||
* `/var/log`
|
|
||||||
* `/tmp` (or whatever the system `temp dir` is) - With the exception of the processes's own temp files
|
|
||||||
|
|
||||||
If there is other information on the system that is sensitive and should be hidden, it can be added via the Tower Configuration Screen
|
|
||||||
or by updating the following entry in a tower settings file:
|
|
||||||
|
|
||||||
AWX_PROOT_HIDE_PATHS = ['/list/of/', '/paths']
|
|
||||||
|
|
||||||
If there are any directories that should specifically be exposed that can be set in a similar way:
|
|
||||||
|
|
||||||
AWX_PROOT_SHOW_PATHS = ['/list/of/', '/paths']
|
|
||||||
|
|
||||||
By default, the system will use the system's `tmp dir` (`/tmp` by default) as its staging area. This can be changed via the following setting:
|
|
||||||
|
|
||||||
AWX_PROOT_BASE_PATH = "/opt/tmp"
|
|
||||||
|
|
||||||
|
|
||||||
### Project Folder Isolation
|
|
||||||
|
|
||||||
Starting in AWX versions above 6.0.0, the project folder will be copied for each job run.
|
|
||||||
This allows playbooks to make local changes to the source tree for convenience,
|
|
||||||
such as creating temporary files, without the possibility of interference with
|
|
||||||
other jobs.
|
|
||||||
@@ -187,7 +187,7 @@ This task spawns an `ansible` process, which then runs a command using Ansible.
|
|||||||
- Build a dictionary of passwords for the SSH private key, SSH user and sudo/su.
|
- Build a dictionary of passwords for the SSH private key, SSH user and sudo/su.
|
||||||
- Build an environment dictionary for Ansible.
|
- Build an environment dictionary for Ansible.
|
||||||
- Build a command line argument list for running Ansible, optionally using `ssh-agent` for public/private key authentication.
|
- Build a command line argument list for running Ansible, optionally using `ssh-agent` for public/private key authentication.
|
||||||
- Return whether the task should use `bwrap`.
|
- Return whether the task should use process isolation.
|
||||||
|
|
||||||
For more information on ad hoc commands, read the [Running Ad Hoc Commands section](https://docs.ansible.com/ansible-tower/latest/html/userguide/inventories.html#running-ad-hoc-commands) of the Inventories page of the Ansible Tower User Guide.
|
For more information on ad hoc commands, read the [Running Ad Hoc Commands section](https://docs.ansible.com/ansible-tower/latest/html/userguide/inventories.html#running-ad-hoc-commands) of the Inventories page of the Ansible Tower User Guide.
|
||||||
|
|
||||||
|
|||||||
@@ -22,10 +22,6 @@ SECRET_KEY = get_secret()
|
|||||||
|
|
||||||
ALLOWED_HOSTS = ['*']
|
ALLOWED_HOSTS = ['*']
|
||||||
|
|
||||||
# Container environments don't like chroots
|
|
||||||
AWX_PROOT_ENABLED = False
|
|
||||||
|
|
||||||
|
|
||||||
CLUSTER_HOST_ID = "awx"
|
CLUSTER_HOST_ID = "awx"
|
||||||
SYSTEM_UUID = '00000000-0000-0000-0000-000000000000'
|
SYSTEM_UUID = '00000000-0000-0000-0000-000000000000'
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user