def perform_analyze_nodocker(userId, manifest, image_record, registry_creds): ret_analyze = {} ret_query = {} localconfig = anchore_engine.configuration.localconfig.get_config() try: tmpdir = localconfig['tmp_dir'] except Exception as err: logger.warn("could not get tmp_dir from localconfig - exception: " + str(err)) tmpdir = "/tmp" # choose the first TODO possible more complex selection here try: image_detail = image_record['image_detail'][0] registry_manifest = manifest pullstring = image_detail['registry'] + "/" + image_detail['repo'] + "@" + image_detail['imageDigest'] fulltag = image_detail['registry'] + "/" + image_detail['repo'] + ":" + image_detail['tag'] logger.debug("using pullstring ("+str(pullstring)+") and fulltag ("+str(fulltag)+") to pull image data") except Exception as err: image_detail = pullstring = fulltag = None raise Exception("failed to extract requisite information from image_record - exception: " + str(err)) timer = int(time.time()) logger.spew("TIMING MARK0: " + str(int(time.time()) - timer)) logger.info("performing analysis on image: " + str([userId, pullstring, fulltag])) logger.debug("obtaining anchorelock..." + str(pullstring)) with localanchore.get_anchorelock(lockId=pullstring): logger.debug("obtaining anchorelock successful: " + str(pullstring)) analyzed_image_report = localanchore_standalone.analyze_image(userId, registry_manifest, image_record, tmpdir, registry_creds=registry_creds) ret_analyze = analyzed_image_report logger.info("performing analysis on image complete: " + str(pullstring)) return (ret_analyze)
def analyze(registry, manifest, repo, digest, tag, work_dir): userId = None # Not used at all in analyze_image image_record = { 'dockerfile_mode': 'actual', # XXX no idea 'image_detail': [{ # always picks the first one 'registry': registry, 'repo': repo, 'imageDigest': digest, 'tag': tag, 'imageId': 'XXX', # XXX no idea 'dockerfile': None, }], 'imageDigest': 'some sha256 - this seems repeated?', # XXX } localconfig = {'service_dir': join(work_dir, 'service_dir')} click.echo('Starting the analyze process...') image_report, manifest = analyze_image(userId, manifest, image_record, work_dir, localconfig, use_cache_dir=join( work_dir, 'cache_dir')) click.echo('Completed analyze process. Saving results...') result_python = join(work_dir, 'result.py') with open(result_python, 'w') as python_file: python_file.write('result = ') python_file.write(pprint.pformat(image_report)) click.echo('Saved the results of the analyzer to %s' % result_python)
def perform_analyze( account, manifest, image_record, registry_creds, layer_cache_enable=False, parent_manifest=None, ): ret_analyze = {} loaded_config = get_config() tmpdir = get_tempdir(loaded_config) use_cache_dir = None if layer_cache_enable: use_cache_dir = os.path.join(tmpdir, "anchore_layercache") # choose the first TODO possible more complex selection here try: image_detail = image_record["image_detail"][0] registry_manifest = manifest registry_parent_manifest = parent_manifest pullstring = (image_detail["registry"] + "/" + image_detail["repo"] + "@" + image_detail["imageDigest"]) fulltag = (image_detail["registry"] + "/" + image_detail["repo"] + ":" + image_detail["tag"]) logger.debug("using pullstring (" + str(pullstring) + ") and fulltag (" + str(fulltag) + ") to pull image data") except Exception as err: image_detail = pullstring = fulltag = None raise Exception( "failed to extract requisite information from image_record - exception: " + str(err)) timer = int(time.time()) logger.spew("timing: analyze start: " + str(int(time.time()) - timer)) logger.info("performing analysis on image: " + str([account, pullstring, fulltag])) logger.debug("obtaining anchorelock..." + str(pullstring)) with anchore_engine.clients.localanchore_standalone.get_anchorelock( lockId=pullstring, driver="nodocker"): logger.debug("obtaining anchorelock successful: " + str(pullstring)) logger.info("analyzing image: %s", pullstring) analyzed_image_report, manifest_raw = localanchore_standalone.analyze_image( account, registry_manifest, image_record, tmpdir, loaded_config, registry_creds=registry_creds, use_cache_dir=use_cache_dir, parent_manifest=registry_parent_manifest, ) ret_analyze = analyzed_image_report logger.info("performing analysis on image complete: " + str(pullstring)) return ret_analyze
def exec(tag, tmpdir): """ Run analyzer(s) against the local tagged image and write the result in a local fs :param tag: str tag name to analyze on local host (e.g. alpine:latest) :param tmpdir: valid and existing file path :return: """ global config click.echo('Getting tag manifest for: {}'.format(tag)) registry, rest = tag.split('/', 1) repo, tag = rest.split(':', 1) click.echo('Registry: {}, Repository: {}, Tag: {}'.format( registry, repo, tag)) manifest, digest, parentdigest = get_image_manifest_skopeo(None, registry, repo, intag=tag) img_record = { 'imageDigest': digest, 'parentDigest': parentdigest, 'dockerfile_mode': 'guessed', 'image_detail': [{ 'dockerfile': '', 'imageId': digest, 'imageDigest': digest, 'tag': tag, 'registry': registry, 'repo': repo }] } click.echo('Got digest: {}'.format(digest)) click.echo('Got parentdigest: {}'.format(parentdigest)) click.echo('Config: {}'.format(config)) click.echo('Running analyzers') image_report = localanchore_standalone.analyze_image( userId='cli_test', manifest=json.dumps(manifest), image_record=img_record, tmprootdir=tmpdir, localconfig=config, registry_creds=None, use_cache_dir=False) click.echo('complete!') with open(digest + '.report.json', 'w') as f: json.dump(image_report, f)
def perform_analyze_nodocker(userId, manifest, image_record, registry_creds, layer_cache_enable=False, parent_manifest=None): ret_analyze = {} ret_query = {} localconfig = anchore_engine.configuration.localconfig.get_config() try: tmpdir = localconfig['tmp_dir'] except Exception as err: logger.warn("could not get tmp_dir from localconfig - exception: " + str(err)) tmpdir = "/tmp" use_cache_dir=None if layer_cache_enable: use_cache_dir = os.path.join(tmpdir, "anchore_layercache") # choose the first TODO possible more complex selection here try: image_detail = image_record['image_detail'][0] registry_manifest = manifest registry_parent_manifest = parent_manifest pullstring = image_detail['registry'] + "/" + image_detail['repo'] + "@" + image_detail['imageDigest'] fulltag = image_detail['registry'] + "/" + image_detail['repo'] + ":" + image_detail['tag'] logger.debug("using pullstring ("+str(pullstring)+") and fulltag ("+str(fulltag)+") to pull image data") except Exception as err: image_detail = pullstring = fulltag = None raise Exception("failed to extract requisite information from image_record - exception: " + str(err)) timer = int(time.time()) logger.spew("timing: analyze start: " + str(int(time.time()) - timer)) logger.info("performing analysis on image: " + str([userId, pullstring, fulltag])) logger.debug("obtaining anchorelock..." + str(pullstring)) with anchore_engine.clients.localanchore_standalone.get_anchorelock(lockId=pullstring, driver='nodocker'): logger.debug("obtaining anchorelock successful: " + str(pullstring)) analyzed_image_report, manifest_raw = localanchore_standalone.analyze_image(userId, registry_manifest, image_record, tmpdir, localconfig, registry_creds=registry_creds, use_cache_dir=use_cache_dir, parent_manifest=registry_parent_manifest) ret_analyze = analyzed_image_report logger.info("performing analysis on image complete: " + str(pullstring)) return ret_analyze
def analyze(registry, manifest, repo, digest, tag, work_dir, localconfig): userId = None # Not used at all in analyze_image image_record = { "dockerfile_mode": "actual", # XXX no idea "image_detail": [ { # always picks the first one "registry": registry, "repo": repo, "imageDigest": digest, "tag": tag, "imageId": "XXX", # XXX no idea "dockerfile": None, } ], "imageDigest": "some sha256 - this seems repeated?", # XXX } _localconfig = {"service_dir": join(work_dir, "service_dir")} if localconfig: _localconfig.update(localconfig) localconfig = _localconfig click.echo("Starting the analyze process...") image_report, manifest = analyze_image( userId, manifest, image_record, work_dir, localconfig, use_cache_dir=join(work_dir, "cache_dir"), ) click.echo("Completed analyze process. Saving results...") result_python = join(work_dir, "result.py") with open(result_python, "w") as python_file: python_file.write("result = ") python_file.write(pprint.pformat(image_report)) click.echo("Saved the results of the analyzer to %s" % result_python)
def exec(docker_archive, anchore_archive, digest, parent_digest, image_id, tag, account_id, manifest, dockerfile, created_at, annotation): """ Analyze a local image stored as a docker archive (output result of 'docker save'), and generate an anchore image archive tarball ready for import into an anchore engine. DOCKER_ARCHIVE : Location of input docker archive tarfile to analyze ANCHORE_ARCHIVE : Location of output anchore image archive to write """ global config # this could be improved to allow use to input timestamps (created_at, analyzed_at, etc) now = int(time.time()) try: try: imageDigest = None input_manifest_data = None rawmanifest = None if (not manifest and not digest) or (manifest and digest): raise Exception( "must supply either an image digest or a valid manifest, but not both" ) if os.path.exists(anchore_archive): raise Exception( "the supplied anchore archive file ({}) already exists, please remove and try again" .format(anchore_archive)) if manifest: try: with open(manifest, 'r') as FH: # TODO implement manifest validator for anchore requirements, specifically rawmanifest = FH.read() input_manifest_data = json.loads(rawmanifest) imageDigest = manifest_to_digest(rawmanifest) except Exception as err: raise ValueError( "cannot calculate digest from supplied manifest - exception: {}" .format(err)) if digest: if re.match("^sha256:[\d|a-f]{64}$", digest): imageDigest = digest else: raise ValueError( "input digest does not validate - must be sha256:<64 hex characters>" ) if parent_digest: if re.match("^sha256:[\d|a-f]{64}$", parent_digest): parentDigest = parent_digest else: raise ValueError( "input parent_digest does not validate - must be sha256:<64 hex characters>" ) else: parentDigest = imageDigest if image_id: if re.match("^[\d|a-f]{64}$", image_id): imageId = image_id else: raise ValueError("input image_id does not validate") else: # TODO this could be improved to generate imageId from configuration hash imageId = "{}".format(''.join( [random.choice('0123456789abcdef') for x in range(0, 64)])) if account_id: userId = account_id else: userId = 'admin' if created_at: try: if int(created_at) < 0 or int(created_at) > now + 1: raise Exception() except Exception as err: raise ValueError( "created_at must by a unix timestamp between 0 and now ({})" .format(now)) else: created_at = now try: inputTag = tag image_info = parse_dockerimage_string(inputTag) fulltag = "{}/{}:{}".format(image_info['registry'], image_info['repo'], image_info['tag']) fulldigest = "{}/{}@{}".format(image_info['registry'], image_info['repo'], imageDigest) except Exception as err: raise ValueError( "input tag does not validate - exception: {}".format(err)) dockerfile_mode = "Guessed" dockerfile_contents = None if dockerfile: with open(dockerfile, 'r') as FH: dockerfile_contents = ensure_str( base64.b64encode(ensure_bytes(FH.read()))) dockerfile_mode = "Actual" annotations = {} if annotation: for a in annotation: try: (k, v) = a.split('=', 1) if k and v: annotations[k] = v else: raise Exception("found null in key or value") except Exception as err: raise ValueError( "annotation format error - annotations must be of the form (--annotation key=value), found: {}" .format(a)) workspace_root = config['tmp_dir'] except Exception as err: # input setup/validation failure raise err logger.debug( "input has been prepared: imageDigest={} parentDigest={} imageId={} inputTag={} fulltag={} fulldigest={} userId={} annotations={} created_at={}" .format(imageDigest, parentDigest, imageId, inputTag, fulltag, fulldigest, userId, annotations, created_at)) # create an image record try: image_record = make_image_record(userId, 'docker', None, image_metadata={ 'tag': fulltag, 'digest': fulldigest, 'imageId': imageId, 'parentdigest': parentDigest, 'created_at': created_at, 'dockerfile': dockerfile_contents, 'dockerfile_mode': dockerfile_mode, 'annotations': annotations }, registry_lookup=False, registry_creds=(None, None)) image_record['created_at'] = created_at image_record['last_updated'] = created_at image_record['analyzed_at'] = now image_record['analysis_status'] = 'analyzed' image_record['image_status'] = 'active' image_record['record_state_key'] = 'active' for image_detail in image_record['image_detail']: image_detail['created_at'] = created_at image_detail['last_updated'] = created_at image_detail['tag_detected_at'] = created_at image_detail['record_state_key'] = 'active' except Exception as err: # image record setup fail raise err # perform analysis try: image_data, analyzed_manifest_data = analyze_image( userId, rawmanifest, image_record, workspace_root, config, registry_creds=[], use_cache_dir=None, image_source='docker-archive', image_source_meta=docker_archive) image_content_data = {} for content_type in anchore_engine.common.image_content_types + anchore_engine.common.image_metadata_types: try: image_content_data[ content_type] = anchore_engine.common.helpers.extract_analyzer_content( image_data, content_type, manifest=input_manifest_data) except: image_content_data[content_type] = {} anchore_engine.common.helpers.update_image_record_with_analysis_data( image_record, image_data) image_record['image_size'] = int(image_record['image_size']) except Exception as err: # image analysis fail raise err # generate an output image archive tarball archive_file = anchore_archive try: with ImageArchive.for_writing(archive_file) as img_archive: img_archive.account = userId img_archive.image_digest = imageDigest img_archive.manifest.metadata = { 'versions': localconfig.get_versions(), 'image_id': imageId, 'image_record': json.dumps(image_record, sort_keys=True) } pack_data = {'document': image_data} data = ensure_bytes(json.dumps(pack_data, sort_keys=True)) img_archive.add_artifact('analysis', source=ObjectStoreLocation( bucket='analysis_data', key=imageDigest), data=data, metadata=None) pack_data = {'document': image_content_data} data = ensure_bytes(json.dumps(pack_data, sort_keys=True)) img_archive.add_artifact('image_content', source=ObjectStoreLocation( bucket='image_content_data', key=imageDigest), data=data, metadata=None) pack_data = {'document': input_manifest_data} data = ensure_bytes(json.dumps(pack_data, sort_keys=True)) img_archive.add_artifact('image_manifest', source=ObjectStoreLocation( bucket='manifest_data', key=imageDigest), data=data, metadata=None) except Exception as err: # archive tarball generate fail raise err except Exception as err: logger.error( anchore_manager.cli.utils.format_error_output( click_config, 'db', {}, err)) sys.exit(2) click.echo( "Analysis complete for image {} - archive file is located at {}". format(imageDigest, archive_file))