adding some mount handling. primarily focused on listing for now.
This commit is contained in:
		
							parent
							
								
									731e0b4ce8
								
							
						
					
					
						commit
						dc187c92c7
					
				| @ -41,8 +41,9 @@ class PassMan(object): | |||||||
|         return(None) |         return(None) | ||||||
| 
 | 
 | ||||||
|     def _getMount(self): |     def _getMount(self): | ||||||
|         # TODO: mounts xml? |         mounts_xml = self.xml.find('.//mounts') | ||||||
|         self.mount = mounts.MountHandler(self.client) |         self.mount = mounts.MountHandler(self.client, mounts_xml = mounts_xml) | ||||||
|  |         return(None) | ||||||
| 
 | 
 | ||||||
|     def _getURI(self): |     def _getURI(self): | ||||||
|         uri = self.cfg.xml.find('.//uri') |         uri = self.cfg.xml.find('.//uri') | ||||||
|  | |||||||
| @ -2,11 +2,31 @@ import logging | |||||||
| import re | import re | ||||||
| import warnings | import warnings | ||||||
| ## | ## | ||||||
|  | import dpath  # https://pypi.org/project/dpath/ | ||||||
| import hvac.exceptions | import hvac.exceptions | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| _logger = logging.getLogger() | _logger = logging.getLogger() | ||||||
| _mount_re = re.compile(r'^(?P<mount>.*)/') | _mount_re = re.compile(r'^(?P<mount>.*)/$') | ||||||
|  | _subpath_re = re.compile(r'^/?(?P<path>.*)/$') | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class CubbyHandler(object): | ||||||
|  |     # There is no upstream support for directly reading cubby. So we do it ourselves. | ||||||
|  |     # TODO: custom class/handler? https://hvac.readthedocs.io/en/stable/advanced_usage.html#custom-requests-http-adapter | ||||||
|  |     def __init__(self, client): | ||||||
|  |         self.client = client | ||||||
|  | 
 | ||||||
|  |     def list_secrets(self, path, mount_point = 'cubbyhole'): | ||||||
|  |         path = path.lstrip('/') | ||||||
|  |         uri = '/v1/{0}/{1}'.format(mount_point, path) | ||||||
|  |         resp = self.client._adapter.list(url = uri) | ||||||
|  |         return(resp.json()) | ||||||
|  | 
 | ||||||
|  |     def read_secret(self, *args, **kwargs): | ||||||
|  |         # https://github.com/hashicorp/vault/issues/8644 | ||||||
|  |         _logger.warning('Cannot get path info from a cubbyhole') | ||||||
|  |         return({'data': {}}) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class MountHandler(object): | class MountHandler(object): | ||||||
| @ -14,8 +34,11 @@ class MountHandler(object): | |||||||
| 
 | 
 | ||||||
|     def __init__(self, client, mounts_xml = None): |     def __init__(self, client, mounts_xml = None): | ||||||
|         self.client = client |         self.client = client | ||||||
|  |         self.cubbyhandler = CubbyHandler(self.client) | ||||||
|         self.xml = mounts_xml |         self.xml = mounts_xml | ||||||
|         self.mounts = [] |         self.mounts = {} | ||||||
|  |         self.paths = {} | ||||||
|  |         self.getSysMounts() | ||||||
| 
 | 
 | ||||||
|     def getSysMounts(self): |     def getSysMounts(self): | ||||||
|         try: |         try: | ||||||
| @ -25,16 +48,81 @@ class MountHandler(object): | |||||||
|                     mount = r.group('mount') |                     mount = r.group('mount') | ||||||
|                 if mount in self.internal_mounts: |                 if mount in self.internal_mounts: | ||||||
|                     continue |                     continue | ||||||
|                 self.mounts.append(mount) |                 # Get the mount type. | ||||||
|                 _logger.debug('Added mountpoint to mounts list: {0}'.format(mount)) |                 mtype = mount_info['type'] | ||||||
|  |                 if mtype == 'kv': | ||||||
|  |                     mntopts = mount_info['options'] | ||||||
|  |                     if mntopts and isinstance(mntopts, dict): | ||||||
|  |                         mver = mntopts.get('version') | ||||||
|  |                         if mver == '2': | ||||||
|  |                             mtype = 'kv2' | ||||||
|  |                         elif mver == '1': | ||||||
|  |                             mtype = 'kv1' | ||||||
|  |                 self.mounts[mount] = mtype | ||||||
|  |                 _logger.debug('Added mountpoint {0} to mounts list with type {1}'.format(mount, mtype)) | ||||||
|         except hvac.exceptions.Forbidden: |         except hvac.exceptions.Forbidden: | ||||||
|             _logger.warning('Client does not have permission to read /sys/mounts.') |             _logger.warning('Client does not have permission to read /sys/mounts.') | ||||||
|         # TODO: xml parsing |         # TODO: should I blindly merge in instead or no? | ||||||
| 
 |         if self.xml: | ||||||
|  |             for mount in self.xml.findall('.//mount'): | ||||||
|  |                 mname = mount.text | ||||||
|  |                 mtype = mount.attrib.get('type', 'kv2') | ||||||
|  |                 if mname not in self.mounts.keys(): | ||||||
|  |                     self.mounts[mname] = mtype | ||||||
|  |                     _logger.debug('Added mountpoint {0} to mounts list with type {1}'.format(mount, mtype)) | ||||||
|         return(None) |         return(None) | ||||||
| 
 | 
 | ||||||
|     def print(self): |     def getSecrets(self, path = '/', mounts = None): | ||||||
|  |         if not mounts: | ||||||
|  |             mounts = self.mounts | ||||||
|  |         if isinstance(mounts, dict): | ||||||
|  |             mounts = list(mounts.keys()) | ||||||
|  |         if not isinstance(mounts, list): | ||||||
|  |             mounts = [mounts] | ||||||
|  |         for mount in mounts: | ||||||
|  |             mtype = self.mounts.get(mount) | ||||||
|  |             if not mtype: | ||||||
|  |                 _logger.error('Mount not found in defined mounts') | ||||||
|  |                 _logger.debug('The mount {0} was not found in the defined mounts.'.format(mount)) | ||||||
|  |                 raise ValueError('Mount not found in defined mounts') | ||||||
|  |             handler = None | ||||||
|  |             if mtype == 'cubbyhole': | ||||||
|  |                 handler = self.cubbyhandler | ||||||
|  |             elif mtype == 'kv': | ||||||
|  |                 handler = self.client.secrets.kv.v1 | ||||||
|  |             elif mtype == 'kv2': | ||||||
|  |                 handler = self.client.secrets.kv.v2 | ||||||
|  |             if mount not in self.paths.keys(): | ||||||
|  |                 self.paths[mount] = {} | ||||||
|  |             try: | ||||||
|  |                 paths = handler.list_secrets(path = path, mount_point = mount) | ||||||
|  |             except hvac.exceptions.InvalidPath: | ||||||
|  |                 _logger.error('Path does not exist') | ||||||
|  |                 _logger.debug('Path {0} on mount {1} does not exist.'.format(path, mount)) | ||||||
|  |                 continue | ||||||
|  |             if 'data' not in paths.keys() or 'keys' not in paths['data'].keys(): | ||||||
|  |                 _logger.warning('Mount has no secrets/subdirs') | ||||||
|  |                 _logger.debug('The mount {0} has no secrets or subdirectories'.format(mount)) | ||||||
|  |                 warnings.warn('Mount has no secrets/subdirs') | ||||||
|  |             for p2 in paths['data']['keys']: | ||||||
|  |                 is_dir = False | ||||||
|  |                 fullpath = '/'.join((path, p2)).replace('//', '/') | ||||||
|  |                 if p2.endswith('/'): | ||||||
|  |                     r = _mount_re.search(fullpath) | ||||||
|  |                     fullpath = r.group('mount') | ||||||
|  |                     is_dir = True | ||||||
|  |                     self.paths[mount][fullpath] = None | ||||||
|  |                     self.getSecrets(path = p2, mounts = mount) | ||||||
|  |                 sep_p2 = [i for i in fullpath.split('/') if i.strip() != ''] | ||||||
|  |                 if is_dir: | ||||||
|                     pass |                     pass | ||||||
|  |                 # print(mount, sep_p2) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     def print(self): | ||||||
|  |         import pprint | ||||||
|  |         pprint.pprint(self.paths) | ||||||
|  |         return(None) | ||||||
| 
 | 
 | ||||||
|     def search(self): |     def search(self): | ||||||
|         pass |         pass | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user