Beispiel #1
0
 def allcontainers(self):
     if len(self.cs.cons) == 0:
         error = "There are no containers on this system"
         raise ImageScannerClientError(error)
     else:
         con_list = []
         for con in self.cs.cons:
             con_list.append(con['Id'])
         try:
             self._do_work(con_list)
         except Exception as error:
             raise ImageScannerClientError(str(error))
Beispiel #2
0
    def _check_result(result):
        '''
        Examines a json object looking for a key of 'Error'
        which indicates the previous call did not work.  Raises
        an exception upon finding the key
        '''
        result_json = json.loads(result.text)
        if 'Error' in result_json:
            raise ImageScannerClientError(result_json['Error'])

        if 'results' in result_json.keys() and 'Error' \
                in result_json['results']:
            raise ImageScannerClientError(result_json['results']['Error'])
Beispiel #3
0
 def allimages(self):
     if len(self.cs.imagelist) == 0:
         error = "There are no images on this system"
         raise ImageScannerClientError(error)
     if self.args.allimages:
         try:
             self._do_work(self.cs.allimagelist)
         except Exception as error:
             raise ImageScannerClientError(str(error))
     else:
         try:
             self._do_work(self.cs.imagelist)
         except Exception as error:
             raise ImageScannerClientError(str(error))
    def ValidateHost(self, host):
        ''' Validates if the defined docker host is running'''
        try:
            import docker
        except ImportError:
            error = "Can't import 'docker' package. Has docker been installed?"
            raise ImageScannerClientError(error)

        client = docker.Client(base_url=host, timeout=11)
        if not client.ping():
            error = "Cannot connect to the Docker daemon. Is it running " \
                "on this host?"
            raise ImageScannerClientError(error)
        return client
Beispiel #5
0
 def onlyactive(self):
     ''' This function sorts of out only the active containers'''
     con_list = []
     # Rid ourselves of 0 size containers
     for container in self.cs.active_containers:
         con_list.append(container['Id'])
     if len(con_list) == 0:
         error = "There are no active containers on this system"
         raise ImageScannerClientError(error)
     else:
         try:
             self._do_work(con_list)
         except Exception as error:
             raise ImageScannerClientError(str(error))
Beispiel #6
0
    def _get_results(self, url, data=None, headers=None):
        '''Wrapper functoin for calling the request.session.get'''
        headers = self.request_headers if headers is None else headers
        try:
            if data is not None:
                results = self.get(url, data=data, headers=headers)
            else:
                results = self.get(url, headers=headers, timeout=9)
        except requests.exceptions.ConnectionError:
            raise ImageScannerClientError("Unable to connect to REST server "
                                          "at {0}".format(url))
        except requests.exceptions.Timeout:
            raise ImageScannerClientError("Timeout reached with REST server "
                                          "at {0}".format(url))

        return results
 def _docker_ping():
     d_conn = docker.Client()
     try:
         d_conn.ping()
     except Exception:
         raise ImageScannerClientError("The docker daemon does not appear"
                                       "to be running")
Beispiel #8
0
    def _do_work(self, image_list):
        from oscap_docker_python.get_cve_input import getInputCVE

        self.scan_list = image_list
        cve_get = getInputCVE(self.image_tmp)
        if self.ac.fetch_cve_url != "":
            cve_get.url = self.ac.fetch_cve_url
        if self.ac.fetch_cve:
            cve_get.fetch_dist_data()
        threads = []
        mnt_dir = tempfile.mkdtemp()
        for image in image_list:
            if image in self.cs.dead_cids:
                raise ImageScannerClientError("Scan not completed. Cannot "
                                              "scan the dead "
                                              "container {0}".format(image))
            cids = self._get_cids_for_image(self.cs, image)
            t = threading.Thread(target=self.search_containers,
                                 name=image,
                                 args=(
                                     image,
                                     cids,
                                     self.output,
                                     mnt_dir,
                                 ))
            threads.append(t)

        logging.info("Number of containers to scan: {0}".format(len(threads)))
        if isinstance(threading.current_thread(), threading._MainThread):
            signal.signal(signal.SIGINT, self.signal_handler)
        self.threads_complete = 0
        self.cur_scan_threads = 0
        while len(threads) > 0:
            if self.cur_scan_threads < self.procs:
                new_thread = threads.pop()
                new_thread.start()
                self.cur_scan_threads += 1

        while self.cur_scan_threads > 0:
            time.sleep(1)
            pass
        os.rmdir(mnt_dir)
        if self.failed_scan is not None:
            raise ImageScannerClientError(self.failed_scan)
        self.output.report_summary()
Beispiel #9
0
    def _namesearch(self, input_name):
        """
        Looks to see if the input name is the name of a image
        """
        if ":" in input_name:
            image_name, tag = input_name.split(":")
        else:
            image_name = input_name
            tag = None

        name_search = self.ac.conn.images(name=image_name, all=True)
        # We found only one result, return it
        if len(name_search) == 1:
            return name_search[0]['Id']

        else:
            # We found multiple images with the input name
            # If a tag is passed, then we can return the right one
            # If not, we assume if all the image_ids are same, we
            # can use that.

            ilist = []
            for image in name_search:
                if input_name in image['RepoTags']:
                    return image['Id']
                else:
                    ilist.append(image['Id'])
            if tag is not None:
                raise ImageScannerClientError(
                    "Unable to find"
                    "to an image named {0}".format(input_name))
            # We didn't find it by name only. We check if the image_ids
            # are all the same
            if len(ilist) > 1:
                if all(ilist[0] == image for image in ilist) and (tag is None):
                    return ilist[0]
                else:
                    raise \
                        ImageScannerClientError("Found multiple images named"
                                                "{0} with different image Ids."
                                                "Try again with the image"
                                                "name and tag"
                                                .format(input_name))
        return None
 def scan_list(self, scan_list):
     if not isinstance(scan_list, list):
         raise ImageScannerClientError("Input to scan_list must be in"
                                       "the form of a list")
     ret = self.dbus_object.scan_list(
         scan_list,
         self.num_threads,
         dbus_interface=dbus_utils.DBUS_INTERFACE,
         timeout=self.db_timeout)
     return json.loads(ret)
    def ValidateHost(self, host):
        ''' Validates if the defined docker host is running'''
        try:
            import docker
        except ImportError:
            error = "Can't import 'docker' package. Has docker been installed?"
            raise ImageScannerClientError(error)

        # Class docker.Client was renamed to docker.APIClient in
        # python-docker-py 2.0.0.
        try:
            client = docker.APIClient(base_url=host, timeout=11)
        except AttributeError:
            client = docker.Client(base_url=host, timeout=11)

        if not client.ping():
            error = "Cannot connect to the Docker daemon. Is it running " \
                "on this host?"
            raise ImageScannerClientError(error)
        return client
Beispiel #12
0
 def getxml(self, url):
     '''
     Given a URL string, returns the results of an openscap XML file as
     an Element Tree
     '''
     try:
         results = self.get(url)
     except requests.exceptions.ConnectionError:
         raise ImageScannerClientError("Unable to connect to REST server "
                                       "at {0}".format(url))
     return ET.ElementTree(ET.fromstring(results.content))
Beispiel #13
0
 def get_docker_json(self, url):
     '''
     Given a URL, return the state of the docker containers and images
     when the images-scanning occurred.  Returns as JSON object.
     '''
     try:
         results = self.get(url)
     except requests.exceptions.ConnectionError:
         raise ImageScannerClientError("Unable to connect to REST server "
                                       "at {0}".format(url))
     return json.loads(results.text)
Beispiel #14
0
 def ValidateHost(self, host):
     ''' Validates if the defined docker host is running'''
     try:
         client = docker.Client(base_url=host, timeout=11)
         if not client.ping():
             raise(Exception)
     except Exception:
         error = "Cannot connect to the Docker daemon. Is it running on " \
                 "this host"
         client = None
         raise ImageScannerClientError(error)
     return client
Beispiel #15
0
 def scan_list(self, scan_list):
     '''
     Scans a list of containers/images by name or id and returns
     results in json
     '''
     if not isinstance(scan_list, list):
         raise ImageScannerClientError("You must pass input in list form")
     url = urlparse.urljoin(self.host, self.api_path + "/scan")
     params = {'scan': scan_list, 'number': self.num_threads}
     results = self._get_results(url, data=json.dumps(params))
     self._check_result(results)
     return json.loads(results.text)
Beispiel #16
0
 def _docker_ping():
     # Class docker.Client was renamed to docker.APIClient in
     # python-docker-py 2.0.0.
     try:
         d_conn = docker.APIClient()
     except AttributeError:
         d_conn = docker.Client()
     try:
         d_conn.ping()
     except Exception:
         raise ImageScannerClientError("The docker daemon does not appear"
                                       "to be running")
Beispiel #17
0
    def report_results(self):
        if not os.path.exists(self.chroot_cve_file):
            from openscap_daemon.cve_scanner.scanner_error import ImageScannerClientError
            raise ImageScannerClientError("Unable to find {0}".format(
                self.chroot_cve_file))
            return False
        cve_tree = ET.parse(bz2.BZ2File(self.chroot_cve_file))
        self.cve_root = cve_tree.getroot()

        for line in self.result.splitlines():
            split_line = line.split(':')
            # Not in love with how I did this
            # Should find a better marked to know if it is a line
            # a parsable line.
            if (len(split_line) == 5) and ('true' in split_line[4]):
                self._return_xml_values(line.split()[1][:-1])

        sev_dict = {}
        sum_log = StringIO()
        sum_log.write("Image: {0} ({1})".format(self.image_name,
                                                self.os_release))
        cons = self.get_cons(self.ac.fcons, self.image_name)
        sum_log.write("\nContainers based on this image ({0}): {1}\n".format(
            len(cons), ", ".join(cons)))
        for sev in ['Critical', 'Important', 'Moderate', 'Low']:
            sev_counter = 0
            for cve in self.list_of_CVEs:
                if cve.severity == sev:
                    sev_counter += 1
                    sum_log.write("\n")
                    fields = list(self.CVEs._fields)
                    fields.remove('title')
                    sum_log.write("{0}{1}: {2}\n".format(
                        " " * 5, "Title", getattr(cve, "title")))

                    for field in fields:
                        sum_log.write("{0}{1}: {2}\n".format(
                            " " * 10, field.title(), getattr(cve, field)))
            sev_dict[sev] = sev_counter
        self.output.list_of_outputs.append(
            self.output.output(iid=self.image_name,
                               cid=self.con_uuids,
                               os=self.os_release,
                               sevs=sev_dict,
                               log=sum_log.getvalue(),
                               msg=None))
        sum_log.close()
Beispiel #18
0
    def ping(self):
        '''
        Throws an exception if it cannot access the REST server or
        the docker host
        '''
        url = urlparse.urljoin(self.host, self.api_path + "/ping")
        results = self._get_results(url)
        if 'results' not in json.loads(results.text):
            tmp_obj = json.loads(results.text)
            if hasattr(tmp_obj, 'error'):
                error = getattr(tmp_obj, 'error')
            else:
                error = tmp_obj['Error']

            error = error.replace('on the host ',
                                  'on the host {0} '.format(self.host))
            raise ImageScannerClientError(error)
Beispiel #19
0
    def _check_input(self, image_list):
        '''
        Takes a list of image ids, image-names, container ids, or
        container-names and returns a list of images ids and
        container ids
        '''
        work_list = []

        # verify
        try:
            for image in image_list:
                iid = self.get_iid(image)
                work_list.append(iid)
        except ImageScannerClientError:
            error = "Unable to associate {0} with any image " \
                    "or container".format(image)
            raise ImageScannerClientError(error)
        return work_list
Beispiel #20
0
    def is_id_an_image(self, docker_id, docker_obj):
        '''
        helper function that uses the docker_state_file to validate if the
        given item_id is a container or image id
        '''

        if self.containers is None or self.images is None:
            self.containers = docker_obj['host_containers']
            self.images = docker_obj['host_images']

        if docker_id in self.images:
            return True
        elif docker_id in self.containers:
            return False
        else:
            # Item was not found in the docker state file
            error_msg = 'The provided openscap xml result file was ' \
                        'not generated from the same run as the ' \
                        'docker state file '
            raise ImageScannerClientError(error_msg)
Beispiel #21
0
    def get_profile_info(self, profile):
        ''' Looks for host and port based on the profile provided '''

        config = ConfigParser.RawConfigParser()
        config.read(self.config_file)
        try:
            port = config.get(profile, 'port')
            host = config.get(profile, 'host')
            cert = None if not config.has_option(profile, 'cert') else \
                config.get(profile, 'cert')
            number = 2 if not config.has_option(profile, 'threads') else \
                config.get(profile, 'threads')
        except ConfigParser.NoSectionError:
            raise ImageScannerClientError("The profile {0} cannot be found "
                                          "in {1}".format(
                                              profile, self.config_file))
        except ConfigParser.NoOptionError as no_option:
            print("No option {0} found in profile "\
                  "{1} in {2}".format(no_option.option,
                                      profile,
                                      self.config_file))
        return host, port, number, cert
Beispiel #22
0
    def get_iid(self, input_name):
        '''
        Find the image id based on a input_name which can be
        an image id, image name, or an image name:tag name.
        '''

        # Check if the input name is a container
        cid = self.get_cid(input_name)

        if cid is not None:
            return cid

        # Check if the input_name was an image name or name:tag
        image_id = self._namesearch(input_name)
        if image_id is not None:
            return image_id

        # Maybe input name is an image id (or portion)
        for image in self.ac.allimages:
            if image['Id'].startswith(input_name):
                return image['Id']

        raise ImageScannerClientError(
            "Unable to associate {0} with any image".format(input_name))
Beispiel #23
0
 def _check_profile_is_valid(all_profile_names, profile_list):
     ''' Checks a list of profiles to make sure they are valid '''
     for profile in profile_list:
         if profile not in all_profile_names:
             raise ImageScannerClientError(
                 "Profile {0} is invalid".format(profile))
Beispiel #24
0
    def scan_multiple_hosts(self,
                            profile_list,
                            allimages=False,
                            images=False,
                            allcontainers=False,
                            onlyactive=False,
                            remote_threads=4,
                            threads=0):
        '''
        Scan multiple hosts and returns an uber-docker object
        which is basically an object with one or more docker
        state objects in it.
        '''

        if (threads > 0):
            self.threads = threads

        if (threads < 2 or threads > 4):
            raise ImageScannerClientError("Thread count must be between 2 "
                                          "and 4")

        scan_args = self.args_tuple(allimages=allimages,
                                    images=images,
                                    allcontainers=allcontainers,
                                    onlyactive=onlyactive)

        # Check to make sure a scan type was selected
        if not scan_args.allimages and not scan_args.images and not \
                scan_args.allcontainers and not scan_args.onlyactive:
            raise ImageScannerClientError("You must select \
                                          a scan type")

        # Check to make sure only one scan type was selected
        if len([
                x for x in [
                    scan_args.allimages, scan_args.images,
                    scan_args.allcontainers, scan_args.onlyactive
                ] if x is True
        ]) > 1:
            raise ImageScannerClientError("You may only select one \
                                           type of scan")
        # Check profile names are valid
        all_profile_names = self.get_all_profile_names()
        self._check_profile_is_valid(all_profile_names, profile_list)

        # Obtain list of profiles
        profiles = self.return_profiles(profile_list)

        self.num_total = len(profiles)

        # FIXME
        # Make this a variable based on desired number
        pool = ThreadPool(remote_threads)
        pool.map(self.thread_profile_wrapper,
                 [(x, scan_args.onlyactive, scan_args.allcontainers,
                   scan_args.allimages, scan_args.images) for x in profiles])

        with open(self.uber_file_path, 'w') as state_file:
            json.dump(self.uber_docker, state_file)

        return self.uber_docker
Beispiel #25
0
 def list_of_images(self, image_list):
     try:
         self._do_work(image_list)
     except Exception as error:
         raise ImageScannerClientError(str(error))