Skip to content

Commit

Permalink
feat: Introduce support for signing images
Browse files Browse the repository at this point in the history
If the user's current installation isn't signed, ublue-update will sign
the installation the first time updates are ran until the image is signed

Following a successful run, the updater will create a file that it checks
for when running updates to evaluate the state of the image

Image identifers are used as a fallback in the case that a user installs
from an offline ISO. Image maintainers must include the image name, vendor
(your GitHub usernmae or org), and Fedora version

For instance, for Bazzite GNOME Nvida images, this looks like:

IMAGE_NAME=bazzite-gnome-nvidia
IMAGE_VENDOR=ublue-os
FEDORA_MAJOR_VERSION=38

Existing Universal Blue images can implement this by adding...

RUN echo -e "IMAGE_NAME=${IMAGE_NAME}\nIMAGE_VENDOR=${IMAGE_VENDOR}\nFEDORA_MAJOR_VERSION=${FEDORA_MAJOR_VERSION}" \
    >> /usr/etc/default/image-info

... within their Containerfiles for each image they build

Additionally, the image flavor and base image names may be placed here
as well
  • Loading branch information
EyeCantCU committed Sep 20, 2023
1 parent 127ed90 commit d1dccf8
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 0 deletions.
17 changes: 17 additions & 0 deletions src/ublue_update/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import logging
import argparse


from ublue_update.update_checks.sign import sign_image
from ublue_update.update_checks.system import system_update_check
from ublue_update.update_checks.wait import transaction_wait
from ublue_update.update_inhibitors.hardware import check_hardware_inhibitors
Expand Down Expand Up @@ -142,6 +144,21 @@ def run_updates(args):
"System Updater",
"System passed checks, updating ...",
)

# Sign image before proceeding with updates
if not os.path.exists("/etc/ublue-update/image-signed"):
notify(
"System Updater",
"Signing your current installation...",
)
log.info("Signing image...")
sign_image()
notify(
"System Updater",
"Installation successfully signed. Please reboot.",
)
log.info("Image successfully signed.")

users = []
try:
users = get_active_sessions()
Expand Down
54 changes: 54 additions & 0 deletions src/ublue_update/update_checks/sign.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
from json import loads
from os import mknod
from re import match
from subprocess import run, PIPE


def get_image_ref():
"""Pull image identifiers"""
with open("/etc/default/image-info", "r") as image_info:
image_identifiers = {}
for identifier in image_info:
val, key = identifier.split("=")
image_identifiers[val] = str(key).rstrip()

"""Set image identifiers"""
image_name = image_identifiers.get("IMAGE_NAME")
image_vendor = image_identifiers.get("IMAGE_VENDOR")
fedora_version = image_identifiers.get("FEDORA_MAJOR_VERSION")

"""Construct image reference"""
image = "ghcr.io/" + image_vendor + "/" + image_name + ":" + fedora_version
return image


def rebase_image(image):
"""Regex in case vendor isn't ublue-os"""
if match("/var/.+/image", image):
image = get_image_ref()

"""Set protocol if unset"""
protocol = "docker://"
if protocol not in image:
image = protocol + image

"""Rebase to signed image"""
image = "ostree-image-signed:" + image
rpm_ostree_rebase = ["rpm-ostree", "rebase", image]
rebase = run(rpm_ostree_rebase, stdout=PIPE)
if rebase.returncode == 0:
mknod("/etc/ublue-update/image-signed")


def sign_image():
"""Pull ostree status"""
rpm_ostree_status = ["rpm-ostree", "status", "--json"]
status = run(rpm_ostree_status, stdout=PIPE).stdout

"""Parse current image"""
deployments = loads(status)["deployments"][0]
image_ref = deployments["container-image-reference"].split(":", 1)
image = image_ref[1]

"""Rebase"""
rebase_image(image)

0 comments on commit d1dccf8

Please sign in to comment.