def images_check_impl(request_inputs, image_records): user_auth = request_inputs['auth'] method = request_inputs['method'] bodycontent = request_inputs['bodycontent'] params = request_inputs['params'] return_object = [] httpcode = 500 userId, pw = user_auth try: if 'policyId' in params and params['policyId']: bundle_records = catalog.get_policy(user_auth, policyId=params['policyId']) policyId = params['policyId'] else: bundle_records = catalog.get_active_policy(user_auth) policyId = None if not bundle_records: httpcode = 404 raise Exception("user has no active policy to evalute: " + str(user_auth)) # this is to check that we got at least one evaluation in the response, otherwise routine should throw a 404 atleastone = False if image_records: for image_record in image_records: imageDigest = image_record['imageDigest'] return_object_el = {} return_object_el[imageDigest] = {} tags = [] if params and 'tag' in params and params['tag']: image_info = anchore_engine.services.common.get_image_info(userId, "docker", params['tag'], registry_lookup=False, registry_creds=[]) if 'fulltag' in image_info and image_info['fulltag']: params['tag'] = image_info['fulltag'] tags.append(params['tag']) else: for image_detail in image_record['image_detail']: fulltag = image_detail['registry'] + "/" + image_detail['repo'] + ":" + image_detail['tag'] tags.append(fulltag) for tag in tags: if tag not in return_object_el[imageDigest]: return_object_el[imageDigest][tag] = [] try: if params and 'history' in params and params['history']: results = catalog.get_eval(user_auth, imageDigest=imageDigest, tag=tag, policyId=policyId) else: results = [catalog.get_eval_latest(user_auth, imageDigest=imageDigest, tag=tag, policyId=policyId)] except Exception as err: results = [] httpcode = 200 for result in results: fresult = make_response_policyeval(user_auth, result, params) return_object_el[imageDigest][tag].append(fresult[tag]) atleastone = True if return_object_el: return_object.append(return_object_el) else: httpcode = 404 raise Exception("could not find image record(s) input imageDigest(s)") if not atleastone: httpcode = 404 raise Exception("could not find any evaluations for input images") except Exception as err: logger.debug("operation exception: " + str(err)) return_object = anchore_engine.services.common.make_response_error(err, in_httpcode=httpcode) httpcode = return_object['httpcode'] return (return_object, httpcode)
def imagepolicywebhook(bodycontent): # TODO - while the image policy webhook feature is in k8s beta, we've decided to make any errors that occur during check still respond with 'allowed: True'. This should be reverted to default to 'False' on any error, once the k8s feature is further along return_object = { "apiVersion": "imagepolicy.k8s.io/v1alpha1", "kind": "ImageReview", "status": { "allowed": True, "reason": "all images passed anchore policy evaluation" } } httpcode = 200 try: request_inputs = anchore_engine.services.common.do_request_prep( connexion.request, default_params={}) user_auth = request_inputs['auth'] method = request_inputs['method'] params = request_inputs['params'] userId = request_inputs['userId'] try: final_allowed = True reason = "unset" try: try: #incoming = json.loads(bodycontent) incoming = bodycontent logger.debug("incoming post data: " + json.dumps(incoming, indent=4)) except Exception as err: raise Exception("could not load post data as json: " + str(err)) try: requestUserId = None requestPolicyId = None # see if the request from k8s contains an anchore policy and/or whitelist name if 'annotations' in incoming['spec']: logger.debug( "incoming request contains annotations: " + json.dumps(incoming['spec']['annotations'], indent=4)) requestUserId = incoming['spec']['annotations'].pop( "anchore.image-policy.k8s.io/userId", None) requestPolicyId = incoming['spec']['annotations'].pop( "anchore.image-policy.k8s.io/policyBundleId", None) except Exception as err: raise Exception("could not parse out annotations: " + str(err)) if not requestUserId: raise Exception( "need to specify an anchore.image-policy.k8s.io/userId annotation with a valid anchore service username as a value" ) # TODO - get anchore system uber cred to access # this data on behalf of user? tough...maybe see # if kuber can make request as anchore-system so # that we can switch roles? localconfig = anchore_engine.configuration.localconfig.get_config( ) system_user_auth = localconfig['system_user_auth'] user_record = catalog.get_user(system_user_auth, requestUserId) request_user_auth = (user_record['userId'], user_record['password']) reason = "all images passed anchore policy checks" final_action = False for el in incoming['spec']['containers']: image = el['image'] logger.debug("found image in request: " + str(image)) image_records = catalog.get_image(request_user_auth, tag=image) if not image_records: raise Exception("could not find requested image (" + str(image) + ") in anchore service DB") for image_record in image_records: imageDigest = image_record['imageDigest'] for image_detail in image_record['image_detail']: fulltag = image_detail[ 'registry'] + "/" + image_detail[ 'repo'] + ':' + image_detail['tag'] result = catalog.get_eval_latest( request_user_auth, tag=fulltag, imageDigest=imageDigest, policyId=requestPolicyId) if result: httpcode = 200 if result['final_action'].upper() not in [ 'GO', 'WARN' ]: final_action = False raise Exception( "image failed anchore policy check: " + json.dumps(result, indent=4)) else: final_action = True else: httpcode = 404 final_action = False raise Exception( "no anchore evaluation available for image: " + str(image)) final_allowed = final_action except Exception as err: reason = str(err) final_allowed = False httpcode = 200 return_object['status']['allowed'] = final_allowed return_object['status']['reason'] = reason anchore_engine.subsys.metrics.counter_inc( "anchore_image_policy_webhooks_evaluation_total", allowed=final_allowed) #logger.debug("final return: " + json.dumps(return_object, indent=4)) httpcode = 200 except Exception as err: return_object['reason'] = str(err) httpcode = 500 except Exception as err: return_object['reason'] = str(err) httpcode = 500 return (return_object, httpcode)