Merge pull request #2951 from Netflix/enable_autorotate_attached_certs

Autorotate certs attached to endpoints
This commit is contained in:
Curtis 2020-04-28 16:33:12 -04:00 committed by GitHub
commit eaaacfad3e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 79 additions and 20 deletions

View File

@ -5,29 +5,18 @@
:license: Apache, see LICENSE for more details. :license: Apache, see LICENSE for more details.
.. moduleauthor:: Kevin Glisson <kglisson@netflix.com> .. moduleauthor:: Kevin Glisson <kglisson@netflix.com>
""" """
import sys
import multiprocessing import multiprocessing
from tabulate import tabulate import sys
from sqlalchemy import or_
from flask import current_app from flask import current_app
from flask_script import Manager
from flask_principal import Identity, identity_changed 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 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.authorities.models import Authority
from lemur.certificates.schemas import CertificateOutputSchema
from lemur.certificates.models import Certificate from lemur.certificates.models import Certificate
from lemur.certificates.schemas import CertificateOutputSchema
from lemur.certificates.service import ( from lemur.certificates.service import (
reissue_certificate, reissue_certificate,
get_certificate_primitives, get_certificate_primitives,
@ -35,9 +24,16 @@ from lemur.certificates.service import (
get_by_name, get_by_name,
get_all_certs, get_all_certs,
get, get,
get_all_certs_attached_to_endpoint_without_autorotate,
) )
from lemur.certificates.verify import verify_string 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.") manager = Manager(usage="Handles all certificate related tasks.")
@ -482,3 +478,23 @@ def check_revoked():
cert.status = "unknown" cert.status = "unknown"
database.update(cert) 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)

View File

@ -118,6 +118,21 @@ def get_all_pending_cleaning_expired(source):
) )
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.
: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): def get_all_pending_cleaning_expiring_in_days(source, days_to_expire):
""" """
Retrieves all certificates that are available for cleaning, not attached to endpoint, 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 :param source: the source to search for certificates
:return: list of pending 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 ( return (
Certificate.query.filter(Certificate.sources.any(id=source.id)) Certificate.query.filter(Certificate.sources.any(id=source.id))
.filter(not_(Certificate.endpoints.any())) .filter(not_(Certificate.endpoints.any()))
@ -367,9 +384,11 @@ def render(args):
show_expired = args.pop("showExpired") show_expired = args.pop("showExpired")
if show_expired != 1: if show_expired != 1:
one_month_old = arrow.now()\ one_month_old = (
.shift(months=current_app.config.get("HIDE_EXPIRED_CERTS_AFTER_MONTHS", -1))\ arrow.now()
.shift(months=current_app.config.get("HIDE_EXPIRED_CERTS_AFTER_MONTHS", -1))
.format("YYYY-MM-DD") .format("YYYY-MM-DD")
)
query = query.filter(Certificate.not_after > one_month_old) query = query.filter(Certificate.not_after > one_month_old)
time_range = args.pop("time_range") time_range = args.pop("time_range")

View File

@ -812,3 +812,27 @@ def notify_expirations():
metrics.send(f"{function}.success", "counter", 1) metrics.send(f"{function}.success", "counter", 1)
return log_data return log_data
@celery.task(soft_time_limit=3600)
def enable_autorotate_for_certs_attached_to_endpoint():
"""
This celery task automatically enables autorotation for unexpired certificates that are
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": 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