def evaluate(self, image_obj, context): if not context.data.get('prepared_dockerfile'): return # Prep step blocked this due to condition on the dockerfile, so skip allowed_ports = delim_parser(self.eval_params.get('ALLOWEDPORTS', '')) denied_ports = delim_parser(self.eval_params.get('DENIEDPORTS', '')) expose_lines = context.data.get('prepared_dockerfile', {}).get('EXPOSE', []) for line in expose_lines: matchstr = None line = line.strip() if re.match("^\s*(EXPOSE|" + 'EXPOSE'.lower() + ")\s+(.*)", line): matchstr = re.match("^\s*(EXPOSE|" + 'EXPOSE'.lower() + ")\s+(.*)", line).group(2) if matchstr: iexpose = matchstr.split() if denied_ports: if 'ALL' in denied_ports and len(iexpose) > 0: self._fire(msg="Dockerfile exposes network ports but policy sets DENIEDPORTS=ALL: " + str(iexpose)) else: for p in denied_ports: if p in iexpose: self._fire(msg="Dockerfile exposes port (" + p + ") which is in policy file DENIEDPORTS list") elif p + '/tcp' in iexpose: self._fire(msg="Dockerfile exposes port (" + p + "/tcp) which is in policy file DENIEDPORTS list") elif p + '/udp' in iexpose: self._fire(msg="Dockerfile exposes port (" + p + "/udp) which is in policy file DENIEDPORTS list") if allowed_ports: if 'NONE' in allowed_ports and len(iexpose) > 0: self._fire(msg="Dockerfile exposes network ports but policy sets ALLOWEDPORTS=NONE: " + str(iexpose)) else: for p in allowed_ports: done = False while not done: try: iexpose.remove(p) done = False except: done = True try: iexpose.remove(p + '/tcp') done = False except: done = True try: iexpose.remove(p + '/udp') done = False except: done = True for ip in iexpose: self._fire(msg="Dockerfile exposes port (" + ip + ") which is not in policy file ALLOWEDPORTS list") # Replaecable by: # for port in filter(lambda x: x.split('/')[0] not in allowed_ports, iexpose): # self._fire(...) return
def evaluate(self, image_obj, context): if not context.data.get('prepared_dockerfile'): return # Prep step blocked this eval due to condition on the dockerfile, so skip allowed_users = delim_parser(self.eval_params.get('ALLOWED', '')) denied_users = delim_parser(self.eval_params.get('DENIED', '')) user_lines = context.data.get('prepared_dockerfile').get('USER', []) # If not overt, make it so if not user_lines: user_lines = ['USER root'] user = user_lines[-1].strip( ) # The last USER line is the determining entry match = re.search(self._sanitize_regex, user) if match and match.groups(): user = match.groups()[0] else: log.warn( 'Found USER line in dockerfile that does not match expected regex: {}, Line: {}' .format(self._sanitize_regex, user)) return if allowed_users and user not in allowed_users: self._fire( msg= 'User {} found as effective user, which is not on the allowed list' .format(user)) if denied_users and user in denied_users: self._fire( msg= 'User {} found as effective user, which is on the denied list'. format(user))
def evaluate(self, image_obj, context): if not context.data.get('prepared_dockerfile'): return # Prep step blocked this eval due to condition on the dockerfile, so skip directives = set( map(lambda x: x.upper(), delim_parser(self.eval_params.get('DIRECTIVES', '')))) condition = self.eval_params.get('CHECK') check_value = self.eval_params.get('CHECK_VALUE') operation = self.ops[condition] if not condition or not directives: return df = context.data.get('prepared_dockerfile') for directive, lines in filter(lambda x: x[0] in directives, df.items()): for l in lines: l = l[len(directive):].strip() if operation(l, check_value): self._fire( msg= "Dockerfile directive '{}' check '{}' matched against '{}' for line '{}'" .format(directive, condition, check_value if check_value else '', l)) if condition == 'not_exists': for match in directives.difference( directives.intersection( set(map(lambda x: x.upper(), df.keys())))): self._fire( msg= "Dockerfile directive '{}' not found, matching condition '{}' check" .format(match, condition))
def evaluate(self, image_obj, context): for pval in delim_parser(self.eval_params.get('BLACKLIST_NAMEMATCH','')): try: for pkg in image_obj.packages.filter(ImagePackage.name == pval): self._fire(msg='PKGNAMEMATCH Package is blacklisted: ' + pkg.name) except Exception as e: log.exception('Error searching packages for blacklisted names') pass
def evaluate(self, image_obj, context): if not context.data.get('prepared_dockerfile'): return # Prep step blocked this eval due to condition on the dockerfile, so skip allowed_users = delim_parser(self.eval_params.get('ALLOWED', '')) denied_users = delim_parser(self.eval_params.get('DENIED', '')) user_lines = context.data.get('prepared_dockerfile').get('USER', []) # If not overt, make it so if not user_lines: user_lines = ['USER root'] user = user_lines[-1].strip() # The last USER line is the determining entry user = user[len('USER'):].strip() if allowed_users and user not in allowed_users: self._fire(msg='User {} found as effective user, which is not on the allowed list'.format(user)) if denied_users and user in denied_users: self._fire(msg='User {} found as effective user, which is on the denied list'.format(user))
def evaluate(self, image_obj, context): pkg_names = delim_parser(self.eval_params.get('PKGS', '')) pkg_dirs = delim_parser(self.eval_params.get('DIRS', '')) checks = map(lambda x: x.lower(), delim_parser(self.eval_params.get('CHECK_ONLY', ''))) outlist = list() imageId = image_obj.id modified = {} if image_obj.fs: extracted_files_json = image_obj.fs.files else: extracted_files_json = [] if pkg_names: pkgs = image_obj.packages.filter( ImagePackage.name.in_(pkg_names)).all() else: pkgs = image_obj.packages.all() for pkg in pkgs: pkg_name = pkg.name records = [] if pkg_dirs: # Filter the specified dirs for d in pkg_dirs: records += pkg.pkg_db_entries.filter( ImagePackageManifestEntry.file_path.startswith(d)) else: records = [x for x in pkg.pkg_db_entries.all()] for pkg_db_record in records: status = self._diff_pkg_meta_and_file( pkg_db_record, extracted_files_json.get(pkg_db_record.file_path)) if status and (not checks or status.value in checks): self._fire( msg= "VERIFY check against package db for package '{}' failed on entry '{}' with status: '{}'" .format(pkg_name, pkg_db_record.file_path, status.value))
def evaluate(self, image_obj, context): match_vals = [] fullmatchpkgs = [] for match_val in delim_parser(self.eval_params.get('LICBLACKLIST_FULLMATCH', '')): match_vals.append(match_val) for pkg, license in context.data.get('licenses', []): if license in match_vals: fullmatchpkgs.append(pkg + "(" + license + ")") if fullmatchpkgs: self._fire(msg='LICFULLMATCH Packages are installed that have blacklisted licenses: ' + ', '.join(fullmatchpkgs))
def evaluate(self, image_obj, context): gems = image_obj.gems if not gems: return pkgs = context.data.get(GEM_LIST_KEY) if not pkgs: return for match_val in delim_parser(self.eval_params.get('BLACKLIST_GEMNAMEMATCH', '')): if match_val and match_val in pkgs: self._fire(msg='GEMPKGNAMEMATCH Package is blacklisted: ' + match_val)
def evaluate(self, image_obj, context): match_vals = [] matchpkgs = [] for match_val in delim_parser(self.eval_params.get('LICBLACKLIST_SUBMATCH', '')): match_vals.append(match_val) for pkg, license in context.data.get('licenses', []): for l in match_vals: if re.match(".*" + re.escape(l) + ".*", license): matchpkgs.append(pkg + "(" + license + ")") if matchpkgs: self._fire( msg='LICSUBMATCH Packages are installed that have blacklisted licenses: ' + ', '.join(matchpkgs))
def evaluate(self, image_obj, context): attrs = delim_parser(self.eval_params.get('ATTRIBUTES', '')) check = self.eval_params.get('CHECK') rval = self.eval_params.get('CHECK_VALUE') if not attrs or not check: return if self.__checks__.get_op(check).requires_rvalue and not rval: # Raise exception or fall thru return for attr in attrs: img_val = self.__valid_attributes__[attr](image_obj) # Make consistent types (specifically for int/float/str) if type(img_val) in [str, int, float, unicode]: rval = type(img_val)(rval) if self.__checks__.get_op(check).eval_function(img_val, rval): self._fire( msg= "Attribute check for attribute: '{}' check: '{}' check_value: '{}' matched image value: '{}'" .format(attr, check, ( str(rval) if rval is not None else ''), img_val))
def evaluate(self, image_obj, context): fullmatch = barsplit_comma_delim_parser( self.eval_params.get('PKGFULLMATCH')) namematch = delim_parser(self.eval_params.get('PKGNAMEMATCH')) vermatch = barsplit_comma_delim_parser( self.eval_params.get('PKGVERSMATCH')) outlist = list() imageId = image_obj.id names = set(fullmatch.keys()).union(set(namematch)).union( set(vermatch.keys())) if not names: return # Filter is possible since the lazy='dynamic' is set on the packages relationship in Image. for img_pkg in image_obj.packages.filter( ImagePackage.name.in_(names)).all(): if img_pkg.name in fullmatch: if img_pkg.fullversion != fullmatch.get(img_pkg.name): # Found but not right version self._fire( msg="PKGNOTPRESENT input package (" + str(img_pkg.name) + ") is present (" + str(img_pkg.fullversion) + "), but not at the version specified in policy (" + str(fullmatch[img_pkg.name]) + ")") fullmatch.pop( img_pkg.name ) # Assume only one version of a given package name is installed else: # Remove it from the list fullmatch.pop(img_pkg.name) # Name match is sufficient if img_pkg.name in namematch: namematch.remove(img_pkg.name) if img_pkg.name in vermatch: if img_pkg.fullversion != vermatch[img_pkg.name]: # Check if version is less than param value if compare_package_versions( img_pkg.distro_namespace_meta.flavor, img_pkg.name, img_pkg.version, img_pkg.name, vermatch[img_pkg.name]) < 0: self._fire( msg="PKGNOTPRESENT input package (" + str(img_pkg.name) + ") is present (" + str(img_pkg.fullversion) + "), but is lower version than what is specified in policy (" + str(vermatch[img_pkg.name]) + ")") vermatch.pop(img_pkg.name) # Any remaining for pkg, version in fullmatch.items(): self._fire(msg="PKGNOTPRESENT input package (" + str(pkg) + "-" + str(version) + ") is not present in container image") for pkg, version in vermatch.items(): self._fire(msg="PKGNOTPRESENT input package (" + str(pkg) + "-" + str(version) + ") is not present in container image") for pkg in namematch: self._fire(msg="PKGNOTPRESENT input package (" + str(pkg) + ") is not present in container image")