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)
return False
- def revoke(self):
+ async def revoke(self):
"""
Revokes this key
"""
#!/usr/bin/python
import asyncio
+import datetime
import logging
import os.path
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)
if key:
repo.key = key
+ # Rotate keys for the first time
+ await repo.rotate_keys()
+
return repo
def _make_slug(self, name, owner=None):
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"
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"]