]> git.ipfire.org Git - pbs.git/commitdiff
repos: Automatically rotate keys
authorMichael Tremer <michael.tremer@ipfire.org>
Thu, 6 Oct 2022 18:36:16 +0000 (18:36 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Thu, 6 Oct 2022 18:36:16 +0000 (18:36 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/buildservice/keys.py
src/buildservice/repository.py
src/crontab/pakfire-build-service
src/scripts/pakfire-build-service

index c00536af9e9edc7dc38c74cf2876acc62bd119aa..0bc607822812a47c88062a98b94b31b14219da65 100644 (file)
@@ -209,10 +209,18 @@ class Key(base.DataObject):
 
                return list(subkeys)
 
-       async def generate_subkey(self, algorithm=None):
-               key = await self.backend.keys.generate(
-                       "%s - DUMMY SUBKEY <%s>" % (self.name, self.email),
-               )
+       async def generate_subkey(self, name, algorithm=None):
+               """
+                       Generates a subkey
+               """
+               # Append name to the parent key name
+               name = "%s - %s" % (self.name, name)
+
+               # XXX This is currently creating a totally new key
+               key = await self.backend.keys.generate(name, self.email)
+
+               # XXX mark this as a subkey
+               key._set_attribute("parent_key_id", self.id)
 
                # Append to existing list of subkeys
                self.subkeys.append(key)
@@ -234,7 +242,7 @@ class Key(base.DataObject):
 
                return False
 
-       def revoke(self):
+       async def revoke(self):
                """
                        Revokes this key
                """
index aa447a52d1651e255a92b807fb7784b182deecdb..5adff9743ab3e420481cc3267a79452d940a753f 100644 (file)
@@ -1,6 +1,7 @@
 #!/usr/bin/python
 
 import asyncio
+import datetime
 import logging
 import os.path
 
@@ -16,6 +17,12 @@ from . import misc
 from .constants import *
 from .decorators import *
 
+# How long should a key be in active use for?
+KEY_LIFETIME      = datetime.timedelta(days=365)
+
+# How long should rotating keys overlap?
+KEY_ROLLOVER_TIME = datetime.timedelta(days=60)
+
 class Repositories(base.Object):
        def _get_repository(self, query, *args):
                res = self.db.get(query, *args)
@@ -90,6 +97,9 @@ class Repositories(base.Object):
                if key:
                        repo.key = key
 
+               # Rotate keys for the first time
+               await repo.rotate_keys()
+
                return repo
 
        def _make_slug(self, name, owner=None):
@@ -150,6 +160,13 @@ class Repositories(base.Object):
                for repo in self:
                        await repo.write()
 
+       async def rotate_keys(self):
+               """
+                       Rotates keys for all repositories
+               """
+               for repo in self:
+                       await repo.rotate_keys()
+
 
 class Repository(base.DataObject):
        table = "repositories"
@@ -332,6 +349,67 @@ class Repository(base.DataObject):
        def key(self):
                return self.pakfire.keys.get_by_id(self.data.key_id)
 
+       async def _create_subkey(self):
+               """
+                       Creates a new subkey for this repository
+               """
+               today = datetime.date.today()
+
+               # Mark the key with the data when it has been created
+               name = today.strftime("%Y-%m-%d")
+
+               # XXX add expiration
+
+               # Generate the key
+               await self.key.generate_subkey(name)
+
+       @property
+       def signing_keys(self):
+               """
+                       Returns a list of all keys that are being used to sign this repository
+               """
+               return [key for key in self.key.subkeys \
+                       if not key.has_expired() and not key.is_revoked()]
+
+       # Key Rotation
+
+       async def rotate_keys(self):
+               """
+                       This function rotates any keys (if possible)
+               """
+               log.info("Rotating keys in repository %s" % self)
+
+               # If no keys exist, create a new key
+               if not self.signing_keys:
+                       await self._create_subkey()
+                       return
+
+               # Check the time
+               now = datetime.datetime.now()
+
+               log.debug("Current signing keys:")
+               for key in self.signing_keys:
+                       log.debug("  %s" % key)
+                       log.debug("    Created at: %s" % key.created_at)
+                       if key.expires_at:
+                               log.debug("    Expires at: %s" % key.expires_at)
+
+               # Pick the key created last
+               signing_key = max(self.signing_keys, key=lambda k: k.created_at)
+
+               # Is the key expiring soon?
+               if key.expires_at and now >= key.expires_at - KEY_ROLLOVER_TIME:
+                       await self._create_subkey()
+
+               # Is this key approaching the end of its lifetime?
+               elif now >= key.created_at + KEY_LIFETIME - KEY_ROLLOVER_TIME:
+                       await self._create_subkey()
+
+               # Check if any other keys need to be revoked
+               for key in self.signing_keys:
+                       if now >= key.created_at + KEY_LIFETIME + KEY_ROLLOVER_TIME:
+                               await key.revoke()
+
        @property
        def arches(self):
                return self.distro.arches + ["src"]
index f227a78e5ce3c8293f0f54b7e48afcb98c8bafa0..71654a5f2e3159520aeafdd00b1320b88e9b604c 100644 (file)
@@ -9,6 +9,9 @@ MAILTO=pakfire@ipfire.org
 # Cleanup
 */5 * * * *            _pakfire        pakfire-build-service --logging=warning cleanup
 
+# Repositories - Key Rotation
+@daily                 _pakfire        pakfire-build-service --logging=warning repos:rotate-keys
+
 # Pull sources
 #*/5 * * * *   _pakfire        pakfire-build-service pull-sources &>/dev/null
 
index e3ea3af8fbf75699c25613343b764c60940f4be0..7af55cda964cc2c5ae11ca328d8d341897beb72f 100644 (file)
@@ -28,6 +28,7 @@ class Cli(object):
                        "keys:generate"    : self.backend.keys.generate,
 
                        # Repositories
+                       "repos:rotate-keys": self.backend.repos.rotate_keys,
                        "repos:write"      : self.backend.repos.write,
 
                        # Sync