tiny fixes to securityworker
This commit is contained in:
parent
6415a3d070
commit
37ce84f6af
2 changed files with 31 additions and 20 deletions
|
@ -134,13 +134,11 @@ class SecurityConfigValidator(object):
|
||||||
return self._keys
|
return self._keys
|
||||||
|
|
||||||
def valid(self):
|
def valid(self):
|
||||||
config = self._security_config
|
|
||||||
|
|
||||||
if (not features.SECURITY_SCANNER
|
if (not features.SECURITY_SCANNER
|
||||||
or not config
|
or not self._security_config
|
||||||
or not 'ENDPOINT' in config
|
or not 'ENDPOINT' in self._security_config
|
||||||
or not 'ENGINE_VERSION_TARGET' in config
|
or not 'ENGINE_VERSION_TARGET' in self._security_config
|
||||||
or not 'DISTRIBUTED_STORAGE_PREFERENCE' in config
|
or not 'DISTRIBUTED_STORAGE_PREFERENCE' in self._security_config
|
||||||
or (self._certificate is False and self._keys is None)):
|
or (self._certificate is False and self._keys is None)):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -155,10 +153,12 @@ class SecurityScannerAPI(object):
|
||||||
|
|
||||||
config_validator = SecurityConfigValidator(app, config_provider)
|
config_validator = SecurityConfigValidator(app, config_provider)
|
||||||
if not config_validator.valid():
|
if not config_validator.valid():
|
||||||
|
logger.warning('Invalid config provided to SecurityScannerAPI')
|
||||||
return
|
return
|
||||||
|
|
||||||
self.certificate = config_validator.cert()
|
self._security_config = app.config.get('SECURITY_SCANNER')
|
||||||
self.keys = config_validator.keypair()
|
self._certificate = config_validator.cert()
|
||||||
|
self._keys = config_validator.keypair()
|
||||||
|
|
||||||
def check_layer_vulnerable(self, layer_id, cve_id):
|
def check_layer_vulnerable(self, layer_id, cve_id):
|
||||||
""" Checks with Clair whether the given layer is vulnerable to the given CVE. """
|
""" Checks with Clair whether the given layer is vulnerable to the given CVE. """
|
||||||
|
@ -191,7 +191,7 @@ class SecurityScannerAPI(object):
|
||||||
This function disconnects from the database while awaiting a response
|
This function disconnects from the database while awaiting a response
|
||||||
from the API server.
|
from the API server.
|
||||||
"""
|
"""
|
||||||
security_config = self.security_config
|
security_config = self._security_config
|
||||||
api_url = urljoin(security_config['ENDPOINT'], '/' + security_config['API_VERSION']) + '/'
|
api_url = urljoin(security_config['ENDPOINT'], '/' + security_config['API_VERSION']) + '/'
|
||||||
url = urljoin(api_url, relative_url % args)
|
url = urljoin(api_url, relative_url % args)
|
||||||
|
|
||||||
|
@ -201,8 +201,8 @@ class SecurityScannerAPI(object):
|
||||||
|
|
||||||
with CloseForLongOperation(self.app.config):
|
with CloseForLongOperation(self.app.config):
|
||||||
if body is not None:
|
if body is not None:
|
||||||
return client.post(url, json=body, params=kwargs, timeout=timeout, cert=self.keys,
|
return client.post(url, json=body, params=kwargs, timeout=timeout, cert=self._keys,
|
||||||
verify=self.certificate)
|
verify=self._certificate)
|
||||||
else:
|
else:
|
||||||
return client.get(url, params=kwargs, timeout=timeout, cert=self.keys,
|
return client.get(url, params=kwargs, timeout=timeout, cert=self._keys,
|
||||||
verify=self.certificate)
|
verify=self._certificate)
|
||||||
|
|
|
@ -129,6 +129,7 @@ class SecurityWorker(Worker):
|
||||||
self._keys = validator.keypair()
|
self._keys = validator.keypair()
|
||||||
|
|
||||||
self.add_operation(self._index_images, INDEXING_INTERVAL)
|
self.add_operation(self._index_images, INDEXING_INTERVAL)
|
||||||
|
logger.warning('Failed to validate security scan configuration')
|
||||||
|
|
||||||
def _get_image_url(self, image):
|
def _get_image_url(self, image):
|
||||||
""" Gets the download URL for an image and if the storage doesn't exist,
|
""" Gets the download URL for an image and if the storage doesn't exist,
|
||||||
|
@ -149,9 +150,18 @@ class SecurityWorker(Worker):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
uri = storage.get_direct_download_url(locations, path)
|
uri = storage.get_direct_download_url(locations, path)
|
||||||
# Local storage hack
|
|
||||||
if uri is None:
|
if uri is None:
|
||||||
uri = path
|
# Handle local storage
|
||||||
|
local_storage_enabled = False
|
||||||
|
for storage_type, _ in app.config.get('DISTRIBUTED_STORAGE_CONFIG', {}).values():
|
||||||
|
if storage_type == 'LocalStorage':
|
||||||
|
local_storage_enabled = True
|
||||||
|
|
||||||
|
if local_storage_enabled:
|
||||||
|
uri = path
|
||||||
|
else:
|
||||||
|
logger.warning('Could not get image URL and local storage was not enabled')
|
||||||
|
return None
|
||||||
|
|
||||||
return uri
|
return uri
|
||||||
|
|
||||||
|
@ -161,12 +171,13 @@ class SecurityWorker(Worker):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
request = {
|
request = {
|
||||||
'ID': image['docker_image_id']+'.'+image['storage_uuid'],
|
'ID': '%s.%s' % (image['docker_image_id'], image['storage_uuid']),
|
||||||
'Path': url,
|
'Path': url,
|
||||||
}
|
}
|
||||||
|
|
||||||
if image['parent_docker_image_id'] is not None and image['parent_storage_uuid'] is not None:
|
if image['parent_docker_image_id'] is not None and image['parent_storage_uuid'] is not None:
|
||||||
request['ParentID'] = image['parent_docker_image_id']+'.'+image['parent_storage_uuid']
|
request['ParentID'] = '%s.%s' % (image['parent_docker_image_id'],
|
||||||
|
image['parent_storage_uuid'])
|
||||||
|
|
||||||
return request
|
return request
|
||||||
|
|
||||||
|
@ -182,7 +193,7 @@ class SecurityWorker(Worker):
|
||||||
httpResponse = requests.post(self._api + API_METHOD_INSERT, json=request,
|
httpResponse = requests.post(self._api + API_METHOD_INSERT, json=request,
|
||||||
cert=self._keys, verify=self._cert)
|
cert=self._keys, verify=self._cert)
|
||||||
jsonResponse = httpResponse.json()
|
jsonResponse = httpResponse.json()
|
||||||
except:
|
except (requests.exceptions.RequestException, ValueError):
|
||||||
logger.exception('An exception occurred when analyzing layer ID %s', request['ID'])
|
logger.exception('An exception occurred when analyzing layer ID %s', request['ID'])
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -245,18 +256,18 @@ class SecurityWorker(Worker):
|
||||||
if not images:
|
if not images:
|
||||||
logger.debug('No more images left to analyze')
|
logger.debug('No more images left to analyze')
|
||||||
return
|
return
|
||||||
logger.debug('Found %d images to index' % len(images))
|
logger.debug('Found %d images to index', len(images))
|
||||||
|
|
||||||
for image in images:
|
for image in images:
|
||||||
sec_data = self._analyze_image(image)
|
sec_data = self._analyze_image(image)
|
||||||
if sec_data is None:
|
if sec_data is None:
|
||||||
continue
|
continue
|
||||||
logger.debug('Got response vulnerabilities for layer %s: %s', image['image_id'], sec_data)
|
|
||||||
|
|
||||||
if not sec_data['Vulnerabilities']:
|
if not sec_data['Vulnerabilities']:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Dispatch events for any detected vulnerabilities
|
# Dispatch events for any detected vulnerabilities
|
||||||
|
logger.debug('Got response vulnerabilities for layer %s: %s', image['image_id'], sec_data)
|
||||||
event = ExternalNotificationEvent.get(name='vulnerability_found')
|
event = ExternalNotificationEvent.get(name='vulnerability_found')
|
||||||
matching = (RepositoryTag
|
matching = (RepositoryTag
|
||||||
.select(RepositoryTag, Repository)
|
.select(RepositoryTag, Repository)
|
||||||
|
|
Reference in a new issue