def execute_step(image_obj, args): """Execution path for looking at a container image filesystem at a specific layer. This is an interactive debugging option and should not be used in production.""" print() print("*************************************************************") print(" Container Image Interactive Debug Mode ") print("*************************************************************") print() for layer in image_obj.layers: created_by = layer.created_by if layer.created_by else 'unknown' print("[{}] {}".format(image_obj.layers.index(layer), created_by)) try: while True: try: # input is safe in Python3 top_layer = int(input("\nPick a layer to debug: ")) # nosec except ValueError: print("Not an integer") continue if not 0 <= top_layer < len(image_obj.layers): print("Not a valid layer number") continue drop_into_layer(image_obj, top_layer) except KeyboardInterrupt: print("Exiting...") rootfs.clean_up() if not args.keep_wd: prep.clean_image_tars(image_obj)
def execute_image(args): """Execution path for container images""" logger.debug('Starting analysis...') image_type, image_string = extract_image(args) # If the image has been extracted, load the metadata if image_type and image_string: full_image = cimage.load_full_image( image_string, image_type, args.load_until_layer) # check if the image was loaded successfully if full_image.origins.is_empty(): # Add an image origin here full_image.origins.add_notice_origin( formats.docker_image.format(imagetag=image_string)) # Set up for analysis setup(full_image) # analyze image cimage.default_analyze(full_image, args) # report out report.report_out(args, full_image) # clean up teardown(full_image) else: # we cannot load the full image logger.error('Cannot retrieve full image metadata') if not args.keep_wd: prep.clean_image_tars(full_image)
def execute_invoke(image_obj, args): """Execution path for checking command library scripts""" # we set up the image for analysis run.setup(image_obj) # we now mount the whole container image mount_container_image(image_obj, args.driver) # invoke commands in chroot invoke_script(args) # undo the mounts if args.driver in ('fuse', 'overlay2'): rootfs.unmount_rootfs() # cleanup rootfs.clean_up() if not args.keep_wd: prep.clean_image_tars(image_obj)
def full_image_analysis(dfile, options): """This subroutine is executed when a Dockerfile is successfully built""" image_list = [] # attempt to load the built image metadata full_image = cimage.load_full_image(dfile) if full_image.origins.is_empty(): # Add an image origin here full_image.origins.add_notice_origin( formats.dockerfile_image.format(dockerfile=dfile)) image_list = analyze_full_image(full_image, options) else: # we cannot analyze the full image, but maybe we can # analyze the base image logger.error('Cannot retrieve full image metadata') # cleanup for full images if not options.keep_wd: prep.clean_image_tars(full_image) return image_list
def execute_docker_image(args): # pylint: disable=too-many-branches '''Execution path if given a Docker image''' logger.debug('Starting analysis...') image_string = '' image_digest = '' if args.docker_image: # extract the docker image image_attrs = docker_api.dump_docker_image(args.docker_image) if image_attrs: if image_attrs['RepoTags']: image_string = image_attrs['RepoTags'][0] if image_attrs['RepoDigests']: image_digest = image_attrs['RepoDigests'][0] else: logger.critical("Cannot extract Docker image") elif args.raw_image: # for now we assume that the raw image tarball is always # the product of "docker save", hence it will be in # the docker style layout if rootfs.extract_tarfile(args.raw_image, rootfs.get_working_dir()): image_string = args.raw_image else: logger.critical("Cannot extract raw image") # If the image has been extracted, load the metadata if image_string: full_image = report.load_full_image(image_string, image_digest) # check if the image was loaded successfully if full_image.origins.is_empty(): # Add an image origin here full_image.origins.add_notice_origin( formats.docker_image.format(imagetag=image_string)) # analyze image analyze(full_image, args) # report out report.report_out(args, full_image) else: # we cannot load the full image logger.error('Cannot retrieve full image metadata') # cleanup if not args.keep_wd: prep.clean_image_tars(full_image)
def base_and_run_analysis(dfile, options): """This subroutine is executed when a Dockerfile fails build. It returns a base image and any RUN commands in the Dockerfile.""" image_list = [] # Try to analyze the base image logger.debug('Analyzing base image...') # this will pull, dump and load the base image base_image = load_base_image() if base_image: if base_image.origins.is_empty(): # add a notice stating failure to build image base_image.origins.add_notice_to_origins( dfile, Notice(formats.image_build_failure, 'warning')) image_list = analyze_base_image(base_image, options) else: # we cannot load the base image logger.warning('Cannot retrieve base image metadata') # cleanup for base images if not options.keep_wd: prep.clean_image_tars(base_image) else: logger.error('Cannot analyze base image') return image_list
def execute_dockerfile(args): # noqa C901,R0912 '''Execution path if given a dockerfile''' dfile = '' dfile_lock = False if args.name == 'report': dfile = args.dockerfile else: dfile = args.lock dfile_lock = True logger.debug("Parsing Dockerfile...") dfobj = dockerfile.get_dockerfile_obj(dfile) # expand potential ARG values so base image tag is correct dockerfile.expand_arg(dfobj) dockerfile.expand_vars(dfobj) # Store dockerfile path and commands so we can access it during execution dhelper.load_docker_commands(dfobj) # attempt to build the image logger.debug('Building Docker image...') image_info = docker_api.build_and_dump(dfile) if image_info: # attempt to load the built image metadata full_image = report.load_full_image(dfile, '') if full_image.origins.is_empty(): # image loading was successful # Add an image origin here full_image.origins.add_notice_origin( formats.dockerfile_image.format(dockerfile=dfile)) # analyze image analyze(full_image, args, dfile_lock, dfobj) completed = True else: # we cannot analyze the full image, but maybe we can # analyze the base image logger.warning('Cannot retrieve full image metadata') # clean up image tarballs if not args.keep_wd: prep.clean_image_tars(full_image) else: # cannot build the image logger.warning('Cannot build image') # check if we have analyzed the full image or not if not completed: # Try to analyze the base image logger.debug('Analyzing base image...') base_image = report.load_base_image() if base_image.origins.is_empty(): # image loading was successful # add a notice stating failure to build image base_image.origins.add_notice_to_origins( dfile, Notice( formats.image_build_failure, 'warning')) # analyze image analyze(base_image, args, dfile_lock, dfobj) else: # we cannot load the base image logger.warning('Cannot retrieve base image metadata') stub_image = get_dockerfile_packages() if args.name == 'report': if not args.keep_wd: report.clean_image_tars(base_image) # generate report based on what images were created if not dfile_lock: if completed: report.report_out(args, full_image) else: report.report_out(args, base_image, stub_image) else: logger.debug('Parsing Dockerfile to generate report...') output = dockerfile.create_locked_dockerfile(dfobj) dockerfile.write_locked_dockerfile(output, args.output_file) # cleanup if not args.keep_wd: prep.clean_image_tars(full_image)