]> git.ipfire.org Git - thirdparty/mkosi.git/commitdiff
Add ToolsTreeCertificates= option
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Sat, 13 Apr 2024 14:18:03 +0000 (16:18 +0200)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Sun, 14 Apr 2024 13:47:25 +0000 (15:47 +0200)
When building an image using internal repositories, often various
internal certificates are required to be able to access these. These
are of course not going to be available in any default tools tree, so
let's add an option to use certificates and keys from the host with a
tools tree.

mkosi/__init__.py
mkosi/config.py
mkosi/distributions/opensuse.py
mkosi/installer/__init__.py
mkosi/installer/rpm.py
mkosi/mounts.py
mkosi/resources/mkosi.md
mkosi/sandbox.py
tests/test_json.py

index 0c6cb4c3806c87f296b6d6952b076a165b79b0b9..b41e1f1ae1e0e1e2384bd2d981c3ccf45b1f8e7b 100644 (file)
@@ -58,7 +58,7 @@ from mkosi.installer import clean_package_manager_metadata
 from mkosi.kmod import gen_required_kernel_modules, process_kernel_modules
 from mkosi.log import ARG_DEBUG, complete_step, die, log_notice, log_step
 from mkosi.manifest import Manifest
-from mkosi.mounts import finalize_source_mounts, mount_overlay
+from mkosi.mounts import finalize_crypto_mounts, finalize_source_mounts, mount_overlay
 from mkosi.pager import page
 from mkosi.partition import Partition, finalize_root, finalize_roothash
 from mkosi.qemu import KernelType, copy_ephemeral, run_qemu, run_ssh, start_journal_remote
@@ -67,7 +67,7 @@ from mkosi.run import (
     fork_and_wait,
     run,
 )
-from mkosi.sandbox import Mount, chroot_cmd, finalize_crypto_mounts, finalize_passwd_mounts
+from mkosi.sandbox import Mount, chroot_cmd, finalize_passwd_mounts
 from mkosi.tree import copy_tree, move_tree, rmtree
 from mkosi.types import PathString
 from mkosi.user import CLONE_NEWNS, INVOKING_USER, become_root, unshare
@@ -494,7 +494,7 @@ def run_sync_scripts(context: Context) -> None:
         for script in context.config.sync_scripts:
             mounts = [
                 *sources,
-                *finalize_crypto_mounts(context.config.tools()),
+                *finalize_crypto_mounts(context.config),
                 Mount(script, "/work/sync", ro=True),
                 Mount(json, "/work/config.json", ro=True),
             ]
index e91bdd32d9cc8de94eb13d4170da04cc8819e88e..9491dc7501b51719cd744dc71c80160e6e55ea23 100644 (file)
@@ -1477,6 +1477,7 @@ class Config:
     tools_tree_repositories: list[str]
     tools_tree_package_manager_trees: list[ConfigTree]
     tools_tree_packages: list[str]
+    tools_tree_certificates: bool
     runtime_trees: list[ConfigTree]
     runtime_size: Optional[int]
     runtime_scratch: ConfigFeature
@@ -2775,6 +2776,14 @@ SETTINGS = (
         parse=config_make_list_parser(delimiter=","),
         help="Add additional packages to the default tools tree",
     ),
+    ConfigSetting(
+        dest="tools_tree_certificates",
+        metavar="BOOL",
+        section="Host",
+        parse=config_parse_boolean,
+        help="Use certificates from the tools tree",
+        default=True,
+    ),
     ConfigSetting(
         dest="runtime_trees",
         long="--runtime-tree",
@@ -3982,6 +3991,7 @@ def summary(config: Config) -> str:
             Tools Tree Repositories: {line_join_list(config.tools_tree_repositories)}
    Tools Tree Package Manager Trees: {line_join_list(config.tools_tree_package_manager_trees)}
                 Tools Tree Packages: {line_join_list(config.tools_tree_packages)}
+            Tools Tree Certificates: {yes_no(config.tools_tree_certificates)}
                       Runtime Trees: {line_join_list(config.runtime_trees)}
                        Runtime Size: {format_bytes_or_none(config.runtime_size)}
                     Runtime Scratch: {config.runtime_scratch}
index 6d0a6b66b24785c690e3ad8a9db9489e1c95781c..f652271b10061ff261c85efd4fa052b358600f3e 100644 (file)
@@ -13,8 +13,9 @@ from mkosi.installer.dnf import Dnf
 from mkosi.installer.rpm import RpmRepository, find_rpm_gpgkey, setup_rpm
 from mkosi.installer.zypper import Zypper
 from mkosi.log import die
+from mkosi.mounts import finalize_crypto_mounts
 from mkosi.run import find_binary, run
-from mkosi.sandbox import Mount, finalize_crypto_mounts
+from mkosi.sandbox import Mount
 from mkosi.util import listify, sort_packages
 
 
@@ -172,7 +173,7 @@ def fetch_gpgurls(context: Context, repourl: str) -> tuple[str, ...]:
             ],
             sandbox=context.sandbox(
                 network=True,
-                mounts=[Mount(d, d), *finalize_crypto_mounts(context.config.tools())],
+                mounts=[Mount(d, d), *finalize_crypto_mounts(context.config)],
             ),
         )
         xml = (Path(d) / "repomd.xml").read_text()
index 77ab30eb2dd7714098fe67a34631c527695a3eb3..ca4043098390bd9195f3af74c49689c4ef74e583 100644 (file)
@@ -4,8 +4,9 @@ from pathlib import Path
 
 from mkosi.config import Config, ConfigFeature, OutputFormat
 from mkosi.context import Context
+from mkosi.mounts import finalize_crypto_mounts
 from mkosi.run import find_binary
-from mkosi.sandbox import Mount, finalize_crypto_mounts
+from mkosi.sandbox import Mount
 from mkosi.tree import copy_tree, rmtree
 from mkosi.types import PathString
 from mkosi.util import startswith
@@ -52,7 +53,7 @@ class PackageManager:
     @classmethod
     def mounts(cls, context: Context) -> list[Mount]:
         mounts = [
-            *finalize_crypto_mounts(tools=context.config.tools()),
+            *finalize_crypto_mounts(context.config),
             Mount(context.packages, "/work/packages"),
         ]
 
index c0e0fe78ebffd57f7f1af31587f943894ddd6eb5..b7741c2853885adf5f87c64ba60442d9fcb660bd 100644 (file)
@@ -22,11 +22,13 @@ class RpmRepository(NamedTuple):
 
 
 def find_rpm_gpgkey(context: Context, key: str) -> Optional[str]:
-    if gpgpath := next((context.config.tools() / "usr/share/distribution-gpg-keys").rglob(key), None):
-        return ('/' / gpgpath.relative_to(context.config.tools())).as_uri()
+    root = context.config.tools() if context.config.tools_tree_certificates else Path("/")
+
+    if gpgpath := next((root / "usr/share/distribution-gpg-keys").rglob(key), None):
+        return (Path("/") / gpgpath.relative_to(root)).as_uri()
 
     if gpgpath := next(Path(context.pkgmngr / "etc/pki/rpm-gpg").rglob(key), None):
-        return ('/' / gpgpath.relative_to(context.pkgmngr)).as_uri()
+        return (Path("/") / gpgpath.relative_to(context.pkgmngr)).as_uri()
 
     return None
 
index 788120b94b0aeaab3eec71a3565c391e480cd324..8f75f1a5ec3e5386e17f7b442d68d996bbe9a964 100644 (file)
@@ -133,3 +133,27 @@ def finalize_source_mounts(config: Config, *, ephemeral: bool) -> Iterator[list[
         )
 
         yield [Mount(src, target) for src, target in sorted(sources, key=lambda s: s[1])]
+
+
+def finalize_crypto_mounts(config: Config) -> list[Mount]:
+    root = config.tools() if config.tools_tree_certificates else Path("/")
+
+    mounts = [
+        (root / subdir, Path("/") / subdir)
+        for subdir in (
+            Path("usr/share/keyrings"),
+            Path("usr/share/distribution-gpg-keys"),
+            Path("etc/pki"),
+            Path("etc/ssl"),
+            Path("etc/ca-certificates"),
+            Path("etc/pacman.d/gnupg"),
+            Path("var/lib/ca-certificates"),
+        )
+        if (root / subdir).exists()
+    ]
+
+    return [
+        Mount(src, target, ro=True)
+        for src, target
+        in sorted(set(mounts), key=lambda s: s[1])
+    ]
index 21e72ec8084e2fe252740fa8bd195b38b1405970..fad19033aac08f903c3e41426f41cefcee1f1e40 100644 (file)
@@ -1783,6 +1783,14 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`,
   separated list of package specifications. This option may be used
   multiple times in which case the specified package lists are combined.
 
+`ToolsTreeCertificates=`, `--tools-tree-certificates=`
+
+: Specify whether to use certificates and keys from the tools tree. If
+  enabled, `/usr/share/keyrings`, `/usr/share/distribution-gpg-keys`,
+  `/etc/pki`, `/etc/ssl`, `/etc/ca-certificates`, `/etc/pacman.d/gnupg`
+  and `/var/lib/ca-certificates` from the tools tree are used.
+  Otherwise, these directories are picked up from the host.
+
 `RuntimeTrees=`, `--runtime-tree=`
 
 : Takes a colon separated pair of paths. The first path refers to a
index 68fdc8f0070abae17c20ea33e2b981454e435c38..6f06d436e6b96a04931c725527fd8016a15aa50c 100644 (file)
@@ -79,26 +79,6 @@ def finalize_passwd_mounts(root: PathString) -> list[Mount]:
     ]
 
 
-def finalize_crypto_mounts(tools: Path = Path("/")) -> list[Mount]:
-    mounts = [
-        (tools / subdir, Path("/") / subdir)
-        for subdir in (
-            Path("etc/pki"),
-            Path("etc/ssl"),
-            Path("etc/ca-certificates"),
-            Path("etc/pacman.d/gnupg"),
-            Path("var/lib/ca-certificates"),
-        )
-        if (tools / subdir).exists()
-    ]
-
-    return [
-        Mount(src, target, ro=True)
-        for src, target
-        in sorted(set(mounts), key=lambda s: s[1])
-    ]
-
-
 def finalize_mounts(mounts: Sequence[Mount]) -> list[PathString]:
     mounts = list(set(mounts))
 
index 7cb5534dc512cadae1ba34ed1742fa9406a364ff..72adf3f7cb7cdd46cc76f4b72763bcc30b630aa6 100644 (file)
@@ -310,6 +310,7 @@ def test_config() -> None:
             ],
             "Timezone": null,
             "ToolsTree": null,
+            "ToolsTreeCertificates": true,
             "ToolsTreeDistribution": null,
             "ToolsTreeMirror": null,
             "ToolsTreePackageManagerTrees": [
@@ -468,6 +469,7 @@ def test_config() -> None:
         sync_scripts = [Path("/sync")],
         timezone = None,
         tools_tree = None,
+        tools_tree_certificates = True,
         tools_tree_distribution = None,
         tools_tree_mirror = None,
         tools_tree_package_manager_trees = [ConfigTree(Path("/a/b/c"), Path("/"))],