diff --git a/lemur/certificates/models.py b/lemur/certificates/models.py index add8cfc49..c191329ba 100644 --- a/lemur/certificates/models.py +++ b/lemur/certificates/models.py @@ -229,7 +229,7 @@ def __init__(self, **kwargs): self.roles = list(set(kwargs.get("roles", []))) self.replaces = kwargs.get("replaces", []) self.rotation = kwargs.get("rotation") - self.rotation_policy = kwargs.get("rotation_policy") + self.rotation_policy = kwargs.get("rotation_policy") or RotationPolicy.query.filter_by(name="default").first() self.key_type = kwargs.get("key_type") self.signing_algorithm = defaults.signing_algorithm(cert) self.bits = defaults.bitstrength(cert) diff --git a/lemur/factory.py b/lemur/factory.py index bdef4c653..d7d3689a2 100644 --- a/lemur/factory.py +++ b/lemur/factory.py @@ -68,6 +68,7 @@ def create_app(app_name=None, blueprints=None, config=None): configure_logging(app) configure_database(app) install_plugins(app) + configure_default_rotation_policy(app) @app.teardown_appcontext def teardown(exception=None): @@ -77,6 +78,28 @@ def teardown(exception=None): return app +def configure_default_rotation_policy(app): + """ + Ensures the named "default" RotationPolicy exists and its days are in sync + with LEMUR_DEFAULT_ROTATION_INTERVAL. Called once at boot via create_app() + so every process (web, celery worker, celery beat) starts with the policy + matching the configured value. + """ + from lemur.policies import service as policy_service + from sqlalchemy.exc import OperationalError, ProgrammingError + + with app.app_context(): + try: + policy_service.update_default_rotation_policy() + except (OperationalError, ProgrammingError): + # rotation_policies table doesn't exist yet (fresh DB / migrations + # not yet run, or test DB before create_all). Safe to skip — the + # policy will be synced on the next boot after migrations complete. + app.logger.debug( + "Skipping default rotation policy sync: table not ready" + ) + + def from_file(file_path, silent=False): """ Updates the values in the config from a Python file. This function diff --git a/lemur/manage.py b/lemur/manage.py index bc49fa101..2691c5a19 100755 --- a/lemur/manage.py +++ b/lemur/manage.py @@ -282,24 +282,7 @@ def run(self, password): "DEFAULT_SECURITY", recipients=recipients ) - _DEFAULT_ROTATION_INTERVAL = "default" - default_rotation_interval = policy_service.get_by_name( - _DEFAULT_ROTATION_INTERVAL - ) - - if default_rotation_interval: - sys.stdout.write( - "[-] Default rotation interval policy already created, skipping...!\n" - ) - else: - days = current_app.config.get("LEMUR_DEFAULT_ROTATION_INTERVAL", 30) - sys.stdout.write( - "[+] Creating default certificate rotation policy of {days} days before issuance.\n".format( - days=days - ) - ) - policy_service.create(days=days, name=_DEFAULT_ROTATION_INTERVAL) - + policy_service.update_default_rotation_policy() sys.stdout.write("[/] Done!\n") diff --git a/lemur/policies/service.py b/lemur/policies/service.py index aa7339295..6aa657bfc 100644 --- a/lemur/policies/service.py +++ b/lemur/policies/service.py @@ -6,10 +6,37 @@ .. moduleauthor:: Kevin Glisson """ +from flask import current_app + from lemur import database from lemur.policies.models import RotationPolicy +def update_default_rotation_policy(): + """ + Return the named "default" RotationPolicy, keeping it in sync with + LEMUR_DEFAULT_ROTATION_INTERVAL: creates it if missing, updates its days + if the config has changed. This policy is the NULL-policy fallback in + Certificate.__init__. + The default rotation policy is refreshed as a part of the pre-query sync + in get_all_pending_reissue. + """ + days = current_app.config.get("LEMUR_DEFAULT_ROTATION_INTERVAL", 60) + policies = get_by_name("default") + if not policies: + current_app.logger.info( + "[+] Creating default rotation policy: days=%d", days + ) + return create(days=days, name="default") + policy = policies[0] + if policy.days != days: + current_app.logger.info( + "[~] Updating default rotation policy: days %d -> %d", policy.days, days + ) + update(policy.id, days=days) + return policy + + def get(policy_id): """ Retrieves policy by its ID. diff --git a/lemur/tests/conf.py b/lemur/tests/conf.py index 26f2f3937..31064106c 100644 --- a/lemur/tests/conf.py +++ b/lemur/tests/conf.py @@ -76,6 +76,7 @@ def get_random_secret(length): LEMUR_DEFAULT_LOCATION = "Los Gatos" LEMUR_DEFAULT_ORGANIZATION = "Example, Inc." LEMUR_DEFAULT_ORGANIZATIONAL_UNIT = "Example" +LEMUR_DEFAULT_ROTATION_INTERVAL = 60 LEMUR_ALLOW_WEEKEND_EXPIRATION = False diff --git a/local/src/lemur.conf.py b/local/src/lemur.conf.py index 048789769..f79bd55ba 100644 --- a/local/src/lemur.conf.py +++ b/local/src/lemur.conf.py @@ -220,6 +220,9 @@ def get_random_secret(length): LEMUR_DEFAULT_ORGANIZATIONAL_UNIT = str( os.environ.get("LEMUR_DEFAULT_ORGANIZATIONAL_UNIT", "") ) +LEMUR_DEFAULT_ROTATION_INTERVAL = int( + os.environ.get("LEMUR_DEFAULT_ROTATION_INTERVAL", 60) +) LEMUR_DEFAULT_AUTHORITY = str(os.environ.get("LEMUR_DEFAULT_AUTHORITY", "ExampleCa"))