diff --git a/endpoints/api/sec.py b/endpoints/api/sec.py index e4e571414..e4550f488 100644 --- a/endpoints/api/sec.py +++ b/endpoints/api/sec.py @@ -2,11 +2,10 @@ import logging import features -import requests import json +import requests -from urlparse import urljoin -from app import app +from app import sec_endpoint from data import model from endpoints.api import (require_repo_read, NotFound, DownstreamIssue, path_param, RepositoryParamResource, resource, nickname, show_if, parse_args, @@ -15,17 +14,11 @@ from endpoints.api import (require_repo_read, NotFound, DownstreamIssue, path_pa logger = logging.getLogger(__name__) + def _call_security_api(relative_url, *args, **kwargs): """ Issues an HTTP call to the sec API at the given relative URL. """ - url = urljoin(app.config['SECURITY_SCANNER']['ENDPOINT'], relative_url % args) - - client = app.config['HTTPCLIENT'] - timeout = app.config['SECURITY_SCANNER'].get('API_CALL_TIMEOUT', 1) - - logger.debug('Looking up sec information: %s', url) - try: - response = client.get(url, params=kwargs, timeout=timeout) + response = sec_endpoint.call_api(relative_url, *args, **kwargs) except requests.exceptions.Timeout: raise DownstreamIssue(payload=dict(message='API call timed out')) except requests.exceptions.ConnectionError: @@ -40,8 +33,7 @@ def _call_security_api(relative_url, *args, **kwargs): raise DownstreamIssue(payload=dict(message='Non-json response from downstream service')) if response.status_code / 100 != 2: - logger.warning('Got %s status code to call %s: %s', response.status_code, url, - response.text) + logger.warning('Got %s status code to call: %s', response.status_code, response.text) raise DownstreamIssue(payload=dict(message=response_data['Message'])) return response_data @@ -73,7 +65,7 @@ class RepositoryTagVulnerabilities(RepositoryParamResource): 'security_indexed': False } - data = _call_security_api('/layers/%s/vulnerabilities', tag_image.docker_image_id, + data = _call_security_api('layers/%s/vulnerabilities', tag_image.docker_image_id, minimumPriority=args.minimumPriority) return { @@ -102,7 +94,7 @@ class RepositoryImagePackages(RepositoryParamResource): 'security_indexed': False } - data = _call_security_api('/layers/%s/packages', repo_image.docker_image_id) + data = _call_security_api('layers/%s/packages/diff', repo_image.docker_image_id) return { 'security_indexed': True, diff --git a/util/sec/__init__.py b/util/sec/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/util/sec/secendpoint.py b/util/sec/secendpoint.py new file mode 100644 index 000000000..9e9e57413 --- /dev/null +++ b/util/sec/secendpoint.py @@ -0,0 +1,51 @@ +import features +import logging +import requests +import json + +from urlparse import urljoin + +logger = logging.getLogger(__name__) + +class SecEndpoint(object): + """ Helper class for talking to the Sec API. """ + def __init__(self, app, config_provider): + self.app = app + self.config_provider = config_provider + + if not features.SECURITY_SCANNER: + return + + self.security_config = app.config['SECURITY_SCANNER'] + + self.certificate = self._getfilepath('CA_CERTIFICATE_FILENAME') or False + self.public_key = self._getfilepath('PUBLIC_KEY_FILENAME') + self.private_key = self._getfilepath('PRIVATE_KEY_FILENAME') + + if self.public_key and self.private_key: + self.keys = (self.public_key, self.private_key) + else: + self.keys = None + + def _getfilepath(self, config_key): + security_config = self.security_config + + if config_key in security_config: + with self.config_provider.get_volume_file(security_config[config_key]) as f: + return f.name + + return None + + def call_api(self, relative_url, *args, **kwargs): + """ Issues an HTTP call to the sec API at the given relative URL. """ + security_config = self.security_config + api_url = urljoin(security_config['ENDPOINT'], '/' + security_config['API_VERSION']) + '/' + url = urljoin(api_url, relative_url % args) + + client = self.app.config['HTTPCLIENT'] + timeout = security_config.get('API_CALL_TIMEOUT', 1) + logger.debug('Looking up sec information: %s', url) + + return client.get(url, params=kwargs, timeout=timeout, cert=self.keys, + verify=self.certificate) +