Ejemplo n.º 1
0
def get_soft_from_docker_image(docker_driver, image_name):
    # Start container
    try:
        # Try to start the docker container with the next entrypoint: 'sleep 30'
        container_id = docker_driver.create_container(image_name, entrypoint='sleep 30')
        docker_driver.docker_start(container_id)
    except docker.errors.ImageNotFound:
        raise DagdaError('No such image: ' + image_name + ':latest')
    except docker.errors.NotFound:
        docker_driver.docker_remove_container(container_id)
        # 'sleep' is not in the $PATH, so try to start the docker container with its default entrypoint
        try:
            container_id = docker_driver.create_container(image_name)
            docker_driver.docker_start(container_id)
        except:
            docker_driver.docker_remove_container(container_id)
            raise DagdaError('The docker container with the <' + image_name + '> image name can not be started.')

    # Get all installed packages
    try:
        products = get_soft_from_docker_container_id(docker_driver, container_id)
    except DagdaError:
        # Stop container
        docker_driver.docker_stop(container_id)
        # Clean up
        docker_driver.docker_remove_container(container_id)
        # Re-raise exception
        raise

    # Stop container
    docker_driver.docker_stop(container_id)
    # Clean up
    docker_driver.docker_remove_container(container_id)
    # Return packages
    return products
Ejemplo n.º 2
0
    def pre_check(self):
        # Init
        linux_distro = platform.linux_distribution()[0]
        uname_r = os.uname().release

        # Check requirements
        if not os.path.isfile('/.dockerenv'):  # I'm living in real world!
            if 'Red Hat' == linux_distro or 'CentOS' == linux_distro or 'Fedora' == linux_distro \
                    or 'openSUSE' == linux_distro:
                # Red Hat/CentOS/Fedora/openSUSE
                return_code = subprocess.call(
                    ["rpm", "-q", "kernel-devel-" + uname_r],
                    stdout=subprocess.DEVNULL,
                    stderr=subprocess.DEVNULL)
            elif 'Debian' == linux_distro or 'Ubuntu' == linux_distro:
                # Debian/Ubuntu
                return_code = subprocess.call(
                    ["dpkg", "-l", "linux-headers-" + uname_r],
                    stdout=subprocess.DEVNULL,
                    stderr=subprocess.DEVNULL)
            else:
                raise DagdaError('Linux distribution not supported yet.')

            if return_code != 0:
                raise DagdaError(
                    'The kernel headers are not installed in the host operating system.'
                )
        else:  # I'm running inside a docker container
            DagdaLogger.get_logger().warning(
                "I'm running inside a docker container, so I can't check if the kernel "
                "headers are installed in the host operating system. Please, review it!!"
            )

        # Docker pull for ensuring the sysdig/falco image
        self.docker_driver.docker_pull('sysdig/falco')

        # Stops sysdig/falco containers if there are any
        container_ids = self.docker_driver.get_docker_container_ids_by_image_name(
            'sysdig/falco')
        if len(container_ids) > 0:
            for container_id in container_ids:
                self.docker_driver.docker_stop(container_id)

        # Cleans mongodb falco_events collection
        self.mongodb_driver.delete_falco_events_collection()

        # Starts sysdig running container without custom entrypoint for avoiding:
        # --> Runtime error: error opening device /host/dev/sysdig0
        self.running_container_id = self._start_container()
        time.sleep(30)
        logs = self.docker_driver.docker_logs(self.running_container_id, True,
                                              True, False)
        if "Runtime error: error opening device /host/dev/sysdig0" not in logs:
            self.docker_driver.docker_stop(self.running_container_id)
        else:
            raise DagdaError('Runtime error opening device /host/dev/sysdig0.')
Ejemplo n.º 3
0
    def run(self):
        if not InternalServer.is_external_falco():
            self.running_container_id = self._start_container(
                'falco -pc -o json_output=true -o file_output.enabled=true ' +
                '-o file_output.filename=/host' +
                SysdigFalcoMonitor._falco_output_filename + self.falco_rules)

            # Wait 3 seconds for sysdig/falco start up and creates the output file
            time.sleep(3)

        # Check output file and running docker container
        if not os.path.isfile(SysdigFalcoMonitor._falco_output_filename) or \
            (not InternalServer.is_external_falco() and \
            len(self.docker_driver.get_docker_container_ids_by_image_name('falcosecurity/falco:0.18.0')) == 0):
            raise DagdaError('Falcosecurity/falco output file not found.')

        # Review sysdig/falco logs after rules parser
        if not InternalServer.is_external_falco():
            sysdig_falco_logs = self.docker_driver.docker_logs(
                self.running_container_id, True, True, False)
            if "Rule " in sysdig_falco_logs:
                SysdigFalcoMonitor._parse_log_and_show_dagda_warnings(
                    sysdig_falco_logs)

        # Read file
        with open(SysdigFalcoMonitor._falco_output_filename, 'rb') as f:
            last_file_position = 0
            fbuf = io.BufferedReader(f)
            while True:
                fbuf.seek(last_file_position)
                content = fbuf.readlines()
                sysdig_falco_events = []
                for line in content:
                    line = line.decode('utf-8').replace("\n", "")
                    json_data = json.loads(line)
                    container_id = json_data['output_fields']['container.id']
                    if container_id != 'host':
                        try:
                            json_data['container_id'] = container_id
                            json_data['image_name'] = json_data[
                                'output_fields']['container.image.repository']
                            if 'container.image.tag' in json_data[
                                    'output_fields']:
                                json_data['image_name'] += ":" + json_data[
                                    'output_fields']['container.image.tag']
                            sysdig_falco_events.append(json_data)
                        except IndexError:
                            # The /tmp/falco_output.json file had information about ancient events, so nothing to do
                            pass
                        except KeyError:
                            # The /tmp/falco_output.json file had information about ancient events, so nothing to do
                            pass
                last_file_position = fbuf.tell()
                if len(sysdig_falco_events) > 0:
                    self.mongodb_driver.bulk_insert_sysdig_falco_events(
                        sysdig_falco_events)
                time.sleep(2)
Ejemplo n.º 4
0
def check_docker_by_image_name(image_name):
    # -- Check input
    if not image_name:
        return json.dumps({
            'err': 400,
            'msg': 'Bad image name'
        },
                          sort_keys=True), 400

    # -- Docker pull from remote registry if it is necessary
    try:
        pulled = False
        if not InternalServer.get_docker_driver().is_docker_image(image_name):
            if ':' in image_name:
                tmp = image_name.split(':')[0]
                tag = image_name.split(':')[1]
                msg = 'Error: image library/' + image_name + ':' + tag + ' not found'
                output = InternalServer.get_docker_driver().docker_pull(
                    tmp, tag=tag)
            else:
                msg = 'Error: image library/' + image_name + ':latest not found'
                output = InternalServer.get_docker_driver().docker_pull(
                    image_name)
            if 'errorDetail' in output:
                DagdaLogger.get_logger().error(msg)
                raise DagdaError(msg)
            pulled = True
    except Exception as ex:
        message = "Unexpected exception of type {0} occurred while pulling the docker image: {1!r}" \
            .format(type(ex).__name__, ex.get_message() if type(ex).__name__ == 'DagdaError' else ex.args)
        DagdaLogger.get_logger().error(message)
        return json.dumps({
            'err': 404,
            'msg': 'Image name not found'
        },
                          sort_keys=True), 404

    # -- Process request
    data = {}
    data['image_name'] = image_name
    data['timestamp'] = datetime.datetime.now().timestamp()
    data['status'] = 'Analyzing'
    id = InternalServer.get_mongodb_driver(
    ).insert_docker_image_scan_result_to_history(data)
    InternalServer.get_dagda_edn().put({
        'msg': 'check_image',
        'image_name': image_name,
        '_id': str(id),
        'pulled': pulled
    })

    # -- Return
    output = {}
    output['id'] = str(id)
    output['msg'] = 'Accepted the analysis of <' + image_name + '>'
    return json.dumps(output, sort_keys=True), 202
Ejemplo n.º 5
0
def get_soft_from_docker_container_id(docker_driver, container_id):
    # Extract Linux image distribution
    response = get_os_name(docker_driver.docker_exec(container_id, 'cat /etc/os-release', True, False))
    if response is None:
        raise DagdaError('Linux image distribution has not the "/etc/os-release" file.')
    else:
        # Get all installed packages
        if 'Red Hat' in response or 'CentOS' in response or 'Fedora' in response or 'openSUSE' in response:
            # Red Hat/CentOS/Fedora/openSUSE
            packages_info = docker_driver.docker_exec(container_id, 'rpm -aqi', True, False)
            products = parse_rpm_output_list(packages_info)
        elif 'Debian' in response or 'Ubuntu' in response:
            # Debian/Ubuntu
            packages_info = docker_driver.docker_exec(container_id, 'dpkg -l', True, False)
            products = parse_dpkg_output_list(packages_info)
        elif 'Alpine' in response:
            # Alpine
            packages_info = docker_driver.docker_exec(container_id, 'apk -v info', True, False)
            products = parse_apk_output_list(packages_info)
        else:
            raise DagdaError('Linux image distribution not supported yet.')
    # Return packages
    return products
Ejemplo n.º 6
0
 def docker_logs(self, container_id, show_stdout, show_stderr, follow):
     try:
         return (self.cli.logs(container=container_id, stdout=show_stdout, stderr=show_stderr, follow=follow))\
                .decode('utf-8')
     except docker.errors.APIError as ex:
         if "configured logging reader does not support reading" in str(ex):
             message = "Docker logging driver is not set to be 'json-file' or 'journald'"
             DagdaLogger.get_logger().error(message)
             raise DagdaError(message)
         else:
             message = "Unexpected exception of type {0} occurred: {1!r}" \
                 .format(type(ex).__name__, str(ex))
             DagdaLogger.get_logger().error(message)
             raise ex
Ejemplo n.º 7
0
def read_4depcheck_output_file(image_name):
    filename = tempfile.gettempdir() + '/4depcheck/' + image_name + '.json'

    # Check file
    if not os.path.isfile(filename):
        raise DagdaError('4depcheck output file [' + filename + '] not found.')

    # Read file
    with open(filename, 'rb') as f:
        lines = f.readlines()
        raw_data = ''
        for line in lines:
            raw_data += line.decode('utf-8')

    # Return
    return raw_data
Ejemplo n.º 8
0
def read_depcheck_output_file(image_name):
    image_name = image_name.replace("/", '_')
    filename = '/tmp/depcheck/' + image_name

    # Check file
    if not os.path.isfile(filename):
        raise DagdaError('Depcheck output file [' + filename + '] not found.')

    # Read file
    with open(filename, 'rb') as f:
        lines = f.readlines()
        raw_data = ''
        for line in lines:
            raw_data += line.decode('utf-8')

    # Return
    return raw_data
Ejemplo n.º 9
0
def check_docker_by_image_name(image_name):
    # -- Check input
    if not image_name:
        return json.dumps({
            'err': 400,
            'msg': 'Bad image name'
        },
                          sort_keys=True), 400

    # -- Docker pull from remote registry if it is necessary
    try:
        pulled = False
        if not InternalServer.get_docker_driver().is_docker_image(image_name):
            output = InternalServer.get_docker_driver().docker_pull(image_name)
            if 'errorDetail' in output:
                msg = 'Error: image library/' + image_name + ':latest not found'
                DagdaLogger.get_logger().error(msg)
                raise DagdaError(msg)
            pulled = True
    except:
        return json.dumps({
            'err': 404,
            'msg': 'Image name not found'
        },
                          sort_keys=True), 404

    # -- Process request
    data = {}
    data['image_name'] = image_name
    data['timestamp'] = datetime.datetime.now().timestamp()
    data['status'] = 'Analyzing'
    id = InternalServer.get_mongodb_driver(
    ).insert_docker_image_scan_result_to_history(data)
    InternalServer.get_dagda_edn().put({
        'msg': 'check_image',
        'image_name': image_name,
        '_id': str(id),
        'pulled': pulled
    })

    # -- Return
    output = {}
    output['id'] = str(id)
    output['msg'] = 'Accepted the analysis of <' + image_name + '>'
    return json.dumps(output, sort_keys=True), 202
Ejemplo n.º 10
0
def get_soft_from_docker_container_id(docker_driver, container_id):
    # Extract Linux image distribution
    response = get_os_name(docker_driver.docker_exec(container_id, 'cat /etc/os-release', True, False))
    if response is None:
        DagdaLogger.get_logger().info('Linux image distribution has not the "/etc/os-release" file. Starting the task '
                                      'for linux distribution identification in a blind mode ...')
        products = get_os_software_packages_blind_mode(docker_driver, container_id)
    else:
        # Get all installed packages
        if 'Red Hat' in response or 'CentOS' in response or 'Fedora' in response or 'openSUSE' in response:
            # Red Hat/CentOS/Fedora/openSUSE
            products = get_os_software_packages(docker_driver, container_id, 'rpm -aqi', parse_rpm_output_list)
        elif 'Debian' in response or 'Ubuntu' in response:
            # Debian/Ubuntu
            products = get_os_software_packages(docker_driver, container_id, 'dpkg -l', parse_dpkg_output_list)
        elif 'Alpine' in response:
            # Alpine
            products = get_os_software_packages(docker_driver, container_id, 'apk -v info', parse_apk_output_list)
        else:
            raise DagdaError('Linux image distribution not supported yet.')
    # Return packages
    return products