def request_reissue(certificate, notify, commit): """ Reissuing certificate and handles any exceptions. :param certificate: :param notify: :param commit: :return: """ status = FAILURE_METRIC_STATUS notify = notify and certificate.notify try: print("[+] {0} is eligible for re-issuance".format(certificate.name)) # set the lemur identity for all cli commands identity_changed.send(current_app._get_current_object(), identity=Identity(1)) details = get_certificate_primitives(certificate) print_certificate_details(details) if commit: new_cert = reissue_certificate(certificate, notify=notify, replace=True) print("[+] New certificate named: {0}".format(new_cert.name)) if notify and isinstance( new_cert, Certificate): # let celery handle PendingCertificates send_reissue_no_endpoints_notification(certificate, new_cert) status = SUCCESS_METRIC_STATUS except Exception as e: capture_exception(extra={"certificate_name": str(certificate.name)}) current_app.logger.exception( f"Error reissuing certificate: {certificate.name}", exc_info=True) print( f"[!] Failed to reissue certificate: {certificate.name}. Reason: {e}" ) if notify: send_reissue_failed_notification(certificate) metrics.send( "certificate_reissue", "counter", 1, metric_tags={ "status": status, "certificate": certificate.name }, )
def test_send_reissue_failed_notification(notification_plugin, certificate): from lemur.notifications.messaging import send_reissue_failed_notification verify_sender_email() assert send_reissue_failed_notification(certificate)
def fetch_acme_cert(id, notify_reissue_cert_id=None): """ Attempt to get the full certificate for the pending certificate listed. Args: id: an id of a PendingCertificate notify_reissue_cert_id: ID of existing Certificate to use for reissue notifications, if supplied """ task_id = None if celery.current_task: task_id = celery.current_task.request.id function = f"{__name__}.{sys._getframe().f_code.co_name}" log_data = { "function": function, "message": "Resolving pending certificate {}".format(id), "task_id": task_id, "id": id, } current_app.logger.debug(log_data) if task_id and is_task_active(log_data["function"], task_id, (id, )): log_data["message"] = "Skipping task: Task is already active" current_app.logger.debug(log_data) return pending_certs = pending_certificate_service.get_pending_certs([id]) new = 0 failed = 0 wrong_issuer = 0 acme_certs = [] # We only care about certs using the acme-issuer plugin for cert in pending_certs: cert_authority = get_authority(cert.authority_id) if cert_authority.plugin_name == "acme-issuer": acme_certs.append(cert) else: wrong_issuer += 1 authority = plugins.get("acme-issuer") resolved_certs = authority.get_ordered_certificates(acme_certs) for cert in resolved_certs: real_cert = cert.get("cert") # It's necessary to reload the pending cert due to detached instance: http://sqlalche.me/e/bhk3 pending_cert = pending_certificate_service.get( cert.get("pending_cert").id) if not pending_cert or pending_cert.resolved: # pending_cert is cleared or it was resolved by another process log_data[ "message"] = "Pending certificate doesn't exist anymore. Was it resolved by another process?" current_app.logger.error(log_data) continue if real_cert: # If a real certificate was returned from issuer, then create it in Lemur and mark # the pending certificate as resolved final_cert = pending_certificate_service.create_certificate( pending_cert, real_cert, pending_cert.user) pending_certificate_service.update(cert.get("pending_cert").id, resolved_cert_id=final_cert.id) pending_certificate_service.update(cert.get("pending_cert").id, resolved=True) if notify_reissue_cert_id is not None: notify_reissue_cert = certificate_service.get( notify_reissue_cert_id) send_reissue_no_endpoints_notification(notify_reissue_cert, final_cert) # add metrics to metrics extension new += 1 else: failed += 1 error_log = copy.deepcopy(log_data) error_log["message"] = "Pending certificate creation failure" error_log["pending_cert_id"] = pending_cert.id error_log["last_error"] = cert.get("last_error") error_log["cn"] = pending_cert.cn if pending_cert.number_attempts > ACME_ADDITIONAL_ATTEMPTS: error_log["message"] = "Deleting pending certificate" send_pending_failure_notification( pending_cert, notify_owner=pending_cert.notify) if notify_reissue_cert_id is not None: send_reissue_failed_notification(pending_cert) # Mark the pending cert as resolved pending_certificate_service.update(cert.get("pending_cert").id, resolved=True) else: pending_certificate_service.increment_attempt(pending_cert) pending_certificate_service.update(cert.get("pending_cert").id, status=str( cert.get("last_error"))) # Add failed pending cert task back to queue fetch_acme_cert.delay(id, notify_reissue_cert_id) current_app.logger.error(error_log) log_data["message"] = "Complete" log_data["new"] = new log_data["failed"] = failed log_data["wrong_issuer"] = wrong_issuer current_app.logger.debug(log_data) metrics.send(f"{function}.resolved", "gauge", new) metrics.send(f"{function}.failed", "gauge", failed) metrics.send(f"{function}.wrong_issuer", "gauge", wrong_issuer) print( "[+] Certificates: New: {new} Failed: {failed} Not using ACME: {wrong_issuer}" .format(new=new, failed=failed, wrong_issuer=wrong_issuer)) return log_data
def test_send_reissue_failed_notification(certificate): from lemur.notifications.messaging import send_reissue_failed_notification verify_sender_email() certificate.endpoints = [EndpointFactory()] assert send_reissue_failed_notification(certificate)