From 273c3e2793647389e00e2509b0e0fd047aa540fe Mon Sep 17 00:00:00 2001 From: Curtis Castrapel Date: Tue, 28 Apr 2020 11:52:43 -0700 Subject: [PATCH 1/3] Celery task to enable autorotate for all certificates attached to endpoints without it enabled --- lemur/certificates/service.py | 25 ++++++++++++++++++++++--- lemur/common/celery.py | 24 ++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/lemur/certificates/service.py b/lemur/certificates/service.py index a6bbba30..b031d86b 100644 --- a/lemur/certificates/service.py +++ b/lemur/certificates/service.py @@ -118,6 +118,21 @@ def get_all_pending_cleaning_expired(source): ) +def get_all_certs_attached_to_endpoint_without_rotate(): + """ + Retrieves all certificates that are attached to an endpoint, but that do not have autorotate enabled. + + :return: list of certificates attached to an endpoint without autorotate + """ + return ( + Certificate.query.filter(Certificate.endpoints.any()) + .filter(Certificate.rotation == False) + .filter(Certificate.not_after >= arrow.now()) + .filter(not_(Certificate.replaced.any())) + .all() # noqa + ) + + def get_all_pending_cleaning_expiring_in_days(source, days_to_expire): """ Retrieves all certificates that are available for cleaning, not attached to endpoint, @@ -144,7 +159,9 @@ def get_all_pending_cleaning_issued_since_days(source, days_since_issuance): :param source: the source to search for certificates :return: list of pending certificates """ - not_in_use_window = arrow.now().shift(days=-days_since_issuance).format("YYYY-MM-DD") + not_in_use_window = ( + arrow.now().shift(days=-days_since_issuance).format("YYYY-MM-DD") + ) return ( Certificate.query.filter(Certificate.sources.any(id=source.id)) .filter(not_(Certificate.endpoints.any())) @@ -367,9 +384,11 @@ def render(args): show_expired = args.pop("showExpired") if show_expired != 1: - one_month_old = arrow.now()\ - .shift(months=current_app.config.get("HIDE_EXPIRED_CERTS_AFTER_MONTHS", -1))\ + one_month_old = ( + arrow.now() + .shift(months=current_app.config.get("HIDE_EXPIRED_CERTS_AFTER_MONTHS", -1)) .format("YYYY-MM-DD") + ) query = query.filter(Certificate.not_after > one_month_old) time_range = args.pop("time_range") diff --git a/lemur/common/celery.py b/lemur/common/celery.py index 7c183dc9..a5f608b2 100644 --- a/lemur/common/celery.py +++ b/lemur/common/celery.py @@ -17,8 +17,10 @@ from celery.signals import task_failure, task_received, task_revoked, task_succe from datetime import datetime, timezone, timedelta from flask import current_app +from lemur import database from lemur.authorities.service import get as get_authority from lemur.certificates import cli as cli_certificate +from lemur.certificates.service import get_all_certs_attached_to_endpoint_without_rotate from lemur.common.redis import RedisHandler from lemur.destinations import service as destinations_service from lemur.dns_providers import cli as cli_dns_providers @@ -812,3 +814,25 @@ def notify_expirations(): metrics.send(f"{function}.success", "counter", 1) return log_data + + +@celery.task(soft_time_limit=3600) +def enable_autorotate_for_certs_attached_to_endpoint(): + function = f"{__name__}.{sys._getframe().f_code.co_name}" + task_id = None + if celery.current_task: + task_id = celery.current_task.request.id + + log_data = { + "function": function, + "task_id": task_id, + } + + eligible_certs = get_all_certs_attached_to_endpoint_without_rotate() + for cert in eligible_certs: + log_data["certificate"] = cert.name + log_data["certificate_id"] = cert.id + log_data["message"] = "Enabling auto-rotate for certificate" + current_app.logger.info(log_data) + cert.rotation = True + database.update(cert) From 863af7a3e5f509b984ff2adba31515ebb7187624 Mon Sep 17 00:00:00 2001 From: Curtis Castrapel Date: Tue, 28 Apr 2020 12:16:46 -0700 Subject: [PATCH 2/3] Making CLI command ; Running black --- lemur/certificates/cli.py | 50 +++++++++++++++++++++++------------ lemur/certificates/service.py | 2 +- lemur/common/celery.py | 21 +++++++-------- 3 files changed, 43 insertions(+), 30 deletions(-) diff --git a/lemur/certificates/cli.py b/lemur/certificates/cli.py index b57ff175..ca6b0248 100644 --- a/lemur/certificates/cli.py +++ b/lemur/certificates/cli.py @@ -5,29 +5,18 @@ :license: Apache, see LICENSE for more details. .. moduleauthor:: Kevin Glisson """ -import sys import multiprocessing -from tabulate import tabulate -from sqlalchemy import or_ - +import sys from flask import current_app - -from flask_script import Manager from flask_principal import Identity, identity_changed - +from flask_script import Manager +from sqlalchemy import or_ +from tabulate import tabulate from lemur import database -from lemur.extensions import sentry -from lemur.extensions import metrics -from lemur.plugins.base import plugins -from lemur.constants import SUCCESS_METRIC_STATUS, FAILURE_METRIC_STATUS -from lemur.deployment import service as deployment_service -from lemur.endpoints import service as endpoint_service -from lemur.notifications.messaging import send_rotation_notification -from lemur.domains.models import Domain from lemur.authorities.models import Authority -from lemur.certificates.schemas import CertificateOutputSchema from lemur.certificates.models import Certificate +from lemur.certificates.schemas import CertificateOutputSchema from lemur.certificates.service import ( reissue_certificate, get_certificate_primitives, @@ -35,9 +24,16 @@ from lemur.certificates.service import ( get_by_name, get_all_certs, get, + get_all_certs_attached_to_endpoint_without_autorotate, ) - from lemur.certificates.verify import verify_string +from lemur.constants import SUCCESS_METRIC_STATUS, FAILURE_METRIC_STATUS +from lemur.deployment import service as deployment_service +from lemur.domains.models import Domain +from lemur.endpoints import service as endpoint_service +from lemur.extensions import sentry, metrics +from lemur.notifications.messaging import send_rotation_notification +from lemur.plugins.base import plugins manager = Manager(usage="Handles all certificate related tasks.") @@ -482,3 +478,23 @@ def check_revoked(): cert.status = "unknown" database.update(cert) + + +@manager.command +def automatically_enable_autorotate(): + """ + This function automatically enables autorotation for unexpired certificates that are + attached to an endpoint but do not have autorotate enabled. + """ + log_data = { + "function": f"{__name__}.{sys._getframe().f_code.co_name}", + } + + eligible_certs = get_all_certs_attached_to_endpoint_without_autorotate() + for cert in eligible_certs: + log_data["certificate"] = cert.name + log_data["certificate_id"] = cert.id + log_data["message"] = "Enabling auto-rotate for certificate" + current_app.logger.info(log_data) + cert.rotation = True + database.update(cert) diff --git a/lemur/certificates/service.py b/lemur/certificates/service.py index b031d86b..5d1e6e63 100644 --- a/lemur/certificates/service.py +++ b/lemur/certificates/service.py @@ -118,7 +118,7 @@ def get_all_pending_cleaning_expired(source): ) -def get_all_certs_attached_to_endpoint_without_rotate(): +def get_all_certs_attached_to_endpoint_without_autorotate(): """ Retrieves all certificates that are attached to an endpoint, but that do not have autorotate enabled. diff --git a/lemur/common/celery.py b/lemur/common/celery.py index a5f608b2..7701b82d 100644 --- a/lemur/common/celery.py +++ b/lemur/common/celery.py @@ -17,10 +17,8 @@ from celery.signals import task_failure, task_received, task_revoked, task_succe from datetime import datetime, timezone, timedelta from flask import current_app -from lemur import database from lemur.authorities.service import get as get_authority from lemur.certificates import cli as cli_certificate -from lemur.certificates.service import get_all_certs_attached_to_endpoint_without_rotate from lemur.common.redis import RedisHandler from lemur.destinations import service as destinations_service from lemur.dns_providers import cli as cli_dns_providers @@ -818,21 +816,20 @@ def notify_expirations(): @celery.task(soft_time_limit=3600) def enable_autorotate_for_certs_attached_to_endpoint(): - function = f"{__name__}.{sys._getframe().f_code.co_name}" + """ + This celery task automatically enables autorotation for unexpired certificates that are + attached to an endpoint but do not have autorotate enabled. + :return: + """ task_id = None if celery.current_task: task_id = celery.current_task.request.id log_data = { - "function": function, + "function": f"{__name__}.{sys._getframe().f_code.co_name}", "task_id": task_id, + "message": "Enabling autorotate to eligible certificates", } + current_app.logger.debug(log_data) - eligible_certs = get_all_certs_attached_to_endpoint_without_rotate() - for cert in eligible_certs: - log_data["certificate"] = cert.name - log_data["certificate_id"] = cert.id - log_data["message"] = "Enabling auto-rotate for certificate" - current_app.logger.info(log_data) - cert.rotation = True - database.update(cert) + cli_certificate.automatically_enable_autorotate() From 7e97d885dfea1b86d7274c472f106a318ddc4738 Mon Sep 17 00:00:00 2001 From: Curtis Castrapel Date: Tue, 28 Apr 2020 13:16:27 -0700 Subject: [PATCH 3/3] Address comments --- lemur/common/celery.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lemur/common/celery.py b/lemur/common/celery.py index 7701b82d..5df470ab 100644 --- a/lemur/common/celery.py +++ b/lemur/common/celery.py @@ -821,15 +821,18 @@ def enable_autorotate_for_certs_attached_to_endpoint(): attached to an endpoint but do not have autorotate enabled. :return: """ + function = f"{__name__}.{sys._getframe().f_code.co_name}" task_id = None if celery.current_task: task_id = celery.current_task.request.id log_data = { - "function": f"{__name__}.{sys._getframe().f_code.co_name}", + "function": function, "task_id": task_id, "message": "Enabling autorotate to eligible certificates", } current_app.logger.debug(log_data) cli_certificate.automatically_enable_autorotate() + metrics.send(f"{function}.success", "counter", 1) + return log_data