Compare commits

...

4 Commits

Author SHA1 Message Date
Ryan Petrello
c1ab815c80 Bump version to 17.1.0 2021-03-10 08:53:09 -05:00
Chris Meyers
20e77c0092 fix iso when private_data_dir is more than 1 subdir
* ISO job runs will now correctly mirror the control node
private_data_dir structure even when/if the private_data_dir is multiple
directories deep.
* The filesystem jail for bubblewrap now lives in
/tmp/bwrap_<job_id>_xxx along side private_data_dir
/tmp/bwrap_<job_id>_xxx/awx_<job_id>>_xxx This allows for the cleanup
job to remove all dirs for a job.
* Modified cleanup job to work with new /tmp/bwrap_<job_id>_xxx schema
2021-03-10 08:45:09 -05:00
Chris Meyers
de4d73d656 jailed tasks can not share files
* Permission changes in bubblewrap shared directories persist when the
jailed tasks finish execution. Effectively, this allows playbooks
executing as awx to share files with lower privileged users on the
system.
* To prevent this, we wrap the directory that we intend to share with
bubblewrap in another directory that is owned by awx with permissions
700. The wrapped directory permissions can be changed by the jailed task
while the wrapper directory can not.
* Given `/tmp/bwrap_3_abcd/awx_3_1234/` `bwrap_3_abcd` is the wrapper
directory and `awx_3_1234` is the wrapped directory.
2021-03-10 08:45:06 -05:00
Ryan Petrello
3358e568b5 resolve a permissions error related to redis
see: https://github.com/ansible/awx/issues/9401
2021-03-10 08:44:59 -05:00
9 changed files with 59 additions and 43 deletions

View File

@@ -2,6 +2,10 @@
This is a list of high-level changes for each release of AWX. A full list of commits can be found at `https://github.com/ansible/awx/releases/tag/<version>`. This is a list of high-level changes for each release of AWX. A full list of commits can be found at `https://github.com/ansible/awx/releases/tag/<version>`.
# 17.1.0 (March 9th, 2021)
- Addressed a security issue in AWX (CVE-2021-20253)
- Fixed a bug permissions error related to redis in K8S-based deployments: https://github.com/ansible/awx/issues/9401
# 17.0.1 (January 26, 2021) # 17.0.1 (January 26, 2021)
- Fixed pgdocker directory permissions issue with Local Docker installer: https://github.com/ansible/awx/pull/9152 - Fixed pgdocker directory permissions issue with Local Docker installer: https://github.com/ansible/awx/pull/9152
- Fixed a bug in the UI which caused toggle settings to not be changed when clicked: https://github.com/ansible/awx/pull/9093 - Fixed a bug in the UI which caused toggle settings to not be changed when clicked: https://github.com/ansible/awx/pull/9093

View File

@@ -1 +1 @@
17.0.1 17.1.0

View File

@@ -169,7 +169,7 @@ class IsolatedManager(object):
extravars = { extravars = {
'src': self.private_data_dir, 'src': self.private_data_dir,
'dest': settings.AWX_PROOT_BASE_PATH, 'dest': os.path.split(self.private_data_dir)[0],
'ident': self.ident, 'ident': self.ident,
'job_id': self.instance.id, 'job_id': self.instance.id,
} }

View File

@@ -893,10 +893,19 @@ class BaseTask(object):
''' '''
Create a temporary directory for job-related files. Create a temporary directory for job-related files.
''' '''
path = tempfile.mkdtemp(prefix='awx_%s_' % instance.pk, dir=settings.AWX_PROOT_BASE_PATH) bwrap_path = tempfile.mkdtemp(
os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR) prefix=f'bwrap_{instance.pk}_',
dir=settings.AWX_PROOT_BASE_PATH
)
os.chmod(bwrap_path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
if settings.AWX_CLEANUP_PATHS: if settings.AWX_CLEANUP_PATHS:
self.cleanup_paths.append(path) self.cleanup_paths.append(bwrap_path)
path = tempfile.mkdtemp(
prefix='awx_%s_' % instance.pk,
dir=bwrap_path,
)
os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
runner_project_folder = os.path.join(path, 'project') runner_project_folder = os.path.join(path, 'project')
if not os.path.exists(runner_project_folder): if not os.path.exists(runner_project_folder):
# Ansible Runner requires that this directory exists. # Ansible Runner requires that this directory exists.
@@ -989,14 +998,7 @@ class BaseTask(object):
show_paths = self.proot_show_paths + local_paths + \ show_paths = self.proot_show_paths + local_paths + \
settings.AWX_PROOT_SHOW_PATHS settings.AWX_PROOT_SHOW_PATHS
pi_path = settings.AWX_PROOT_BASE_PATH pi_path = os.path.split(private_data_dir)[0]
if not self.instance.is_isolated() and not self.instance.is_containerized:
pi_path = tempfile.mkdtemp(
prefix='ansible_runner_pi_',
dir=settings.AWX_PROOT_BASE_PATH
)
os.chmod(pi_path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
self.cleanup_paths.append(pi_path)
process_isolation_params = { process_isolation_params = {
'process_isolation': True, 'process_isolation': True,
@@ -1008,6 +1010,8 @@ class BaseTask(object):
'/etc/ssh', '/etc/ssh',
'/var/lib/awx', '/var/lib/awx',
'/var/log', '/var/log',
'/home',
'/var/tmp',
settings.PROJECTS_ROOT, settings.PROJECTS_ROOT,
settings.JOBOUTPUT_ROOT, settings.JOBOUTPUT_ROOT,
] + getattr(settings, 'AWX_PROOT_HIDE_PATHS', None) or [], ] + getattr(settings, 'AWX_PROOT_HIDE_PATHS', None) or [],

View File

@@ -552,8 +552,8 @@ class TestGenericRun():
task.should_use_proot = lambda instance: True task.should_use_proot = lambda instance: True
task.instance = job task.instance = job
private_data_dir = '/foo' private_data_dir = os.path.join(settings.AWX_PROOT_BASE_PATH, 'foo')
cwd = '/bar' cwd = '/the/bar'
settings.AWX_PROOT_HIDE_PATHS = ['/AWX_PROOT_HIDE_PATHS1', '/AWX_PROOT_HIDE_PATHS2'] settings.AWX_PROOT_HIDE_PATHS = ['/AWX_PROOT_HIDE_PATHS1', '/AWX_PROOT_HIDE_PATHS2']
settings.ANSIBLE_VENV_PATH = '/ANSIBLE_VENV_PATH' settings.ANSIBLE_VENV_PATH = '/ANSIBLE_VENV_PATH'
@@ -578,7 +578,7 @@ class TestGenericRun():
'/AWX_PROOT_HIDE_PATHS1', '/AWX_PROOT_HIDE_PATHS1',
'/AWX_PROOT_HIDE_PATHS2']: '/AWX_PROOT_HIDE_PATHS2']:
assert p in process_isolation_params['process_isolation_hide_paths'] assert p in process_isolation_params['process_isolation_hide_paths']
assert 9 == len(process_isolation_params['process_isolation_hide_paths']) assert 11 == len(process_isolation_params['process_isolation_hide_paths'])
assert '/ANSIBLE_VENV_PATH' in process_isolation_params['process_isolation_ro_paths'] assert '/ANSIBLE_VENV_PATH' in process_isolation_params['process_isolation_ro_paths']
assert '/AWX_VENV_PATH' in process_isolation_params['process_isolation_ro_paths'] assert '/AWX_VENV_PATH' in process_isolation_params['process_isolation_ro_paths']
assert 2 == len(process_isolation_params['process_isolation_ro_paths']) assert 2 == len(process_isolation_params['process_isolation_ro_paths'])

View File

@@ -863,7 +863,7 @@ def wrap_args_with_proot(args, cwd, **kwargs):
new_args = [getattr(settings, 'AWX_PROOT_CMD', 'bwrap'), '--unshare-pid', '--dev-bind', '/', '/', '--proc', '/proc'] new_args = [getattr(settings, 'AWX_PROOT_CMD', 'bwrap'), '--unshare-pid', '--dev-bind', '/', '/', '--proc', '/proc']
hide_paths = [settings.AWX_PROOT_BASE_PATH] hide_paths = [settings.AWX_PROOT_BASE_PATH]
if not kwargs.get('isolated'): if not kwargs.get('isolated'):
hide_paths.extend(['/etc/tower', '/var/lib/awx', '/var/log', '/etc/ssh', hide_paths.extend(['/etc/tower', '/var/lib/awx', '/var/log', '/etc/ssh', '/var/tmp', '/home',
settings.PROJECTS_ROOT, settings.JOBOUTPUT_ROOT]) settings.PROJECTS_ROOT, settings.JOBOUTPUT_ROOT])
hide_paths.extend(getattr(settings, 'AWX_PROOT_HIDE_PATHS', None) or []) hide_paths.extend(getattr(settings, 'AWX_PROOT_HIDE_PATHS', None) or [])
for path in sorted(set(hide_paths)): for path in sorted(set(hide_paths)):

View File

@@ -19,7 +19,6 @@ from ansible.module_utils.basic import AnsibleModule
import glob import glob
import os import os
import re
import shutil import shutil
import datetime import datetime
import subprocess import subprocess
@@ -38,32 +37,35 @@ def main():
# this datetime, then it will be deleted because its job has finished # this datetime, then it will be deleted because its job has finished
job_cutoff = datetime.datetime.now() - datetime.timedelta(hours=1) job_cutoff = datetime.datetime.now() - datetime.timedelta(hours=1)
for search_pattern in [ BASE_DIR = '/tmp'
'/tmp/awx_[0-9]*_*', '/tmp/ansible_runner_pi_*',
]:
for path in glob.iglob(search_pattern):
st = os.stat(path)
modtime = datetime.datetime.fromtimestamp(st.st_mtime)
if modtime > job_cutoff: bwrap_pattern = 'bwrap_[0-9]*_*'
continue private_data_dir_pattern = 'awx_[0-9]*_*'
elif modtime > folder_cutoff:
bwrap_path_pattern = os.path.join(BASE_DIR, bwrap_pattern)
for bwrap_path in glob.iglob(bwrap_path_pattern):
st = os.stat(bwrap_path)
modtime = datetime.datetime.fromtimestamp(st.st_mtime)
if modtime > job_cutoff:
continue
elif modtime > folder_cutoff:
private_data_dir_path_pattern = os.path.join(BASE_DIR, bwrap_path, private_data_dir_pattern)
private_data_dir_path = next(glob.iglob(private_data_dir_path_pattern), None)
if private_data_dir_path:
try: try:
re_match = re.match(r'\/tmp\/awx_\d+_.+', path) if subprocess.check_call(['ansible-runner', 'is-alive', private_data_dir_path]) == 0:
if re_match is not None: continue
try: except subprocess.CalledProcessError:
if subprocess.check_call(['ansible-runner', 'is-alive', path]) == 0: # the job isn't running anymore, clean up this path
continue module.debug('Deleting path {} its job has completed.'.format(bwrap_path))
except subprocess.CalledProcessError: module.debug('Deleting path {} due to private_data_dir not being found.'.format(bwrap_path))
# the job isn't running anymore, clean up this path else:
module.debug('Deleting path {} its job has completed.'.format(path)) module.debug('Deleting path {} because modification date is too old.'.format(bwrap_path))
except (ValueError, IndexError): changed = True
continue paths_removed.add(bwrap_path)
else: shutil.rmtree(bwrap_path)
module.debug('Deleting path {} because modification date is too old.'.format(path))
changed = True
paths_removed.add(path)
shutil.rmtree(path)
module.exit_json(changed=changed, paths_removed=list(paths_removed)) module.exit_json(changed=changed, paths_removed=list(paths_removed))

View File

@@ -1 +1 @@
17.0.1 17.1.0

View File

@@ -362,6 +362,9 @@ spec:
- name: {{ kubernetes_deployment_name }}-redis-socket - name: {{ kubernetes_deployment_name }}-redis-socket
mountPath: "/var/run/redis" mountPath: "/var/run/redis"
- name: {{ kubernetes_deployment_name }}-redis-data
mountPath: "/data"
resources: resources:
requests: requests:
memory: "{{ redis_mem_request }}Gi" memory: "{{ redis_mem_request }}Gi"
@@ -472,6 +475,9 @@ spec:
- name: {{ kubernetes_deployment_name }}-redis-socket - name: {{ kubernetes_deployment_name }}-redis-socket
emptyDir: {} emptyDir: {}
- name: {{ kubernetes_deployment_name }}-redis-data
emptyDir: {}
--- ---
apiVersion: v1 apiVersion: v1
kind: Service kind: Service