These allow using mkosi behind a proxy that requires proxy authentication.
Only dnf seems to allow specifying these certificates as individual settings
so other package managers are not fully supported for now.
We mount the proxy certificates and keys to /proxy.xxx in the sandbox because
otherwise they might end up being mounted at the same location as the certificates
from the tools tree, which means those wouldn't be used.
*([f"--environment={k}='{v}'" for k, v in config.environment.items()]),
*(["--tools-tree", str(config.tools_tree)] if config.tools_tree else []),
*([f"--extra-search-path={p}" for p in config.extra_search_paths]),
+ *(["--proxy-url", config.proxy_url] if config.proxy_url else []),
+ *(["--proxy-peer-certificate", str(p)] if (p := config.proxy_peer_certificate) else []),
+ *(["--proxy-client-certificate", str(p)] if (p := config.proxy_client_certificate) else []),
+ *(["--proxy-client-key", str(p)] if (p := config.proxy_client_key) else []),
*(["-f"] * args.force),
]
*(["--source-date-epoch", str(config.source_date_epoch)] if config.source_date_epoch is not None else []),
*([f"--environment={k}='{v}'" for k, v in config.environment.items()]),
*([f"--extra-search-path={p}" for p in config.extra_search_paths]),
+ *(["--proxy-url", config.proxy_url] if config.proxy_url else []),
+ *(["--proxy-peer-certificate", str(p)] if (p := config.proxy_peer_certificate) else []),
+ *(["--proxy-client-certificate", str(p)] if (p := config.proxy_client_certificate) else []),
+ *(["--proxy-client-key", str(p)] if (p := config.proxy_client_key) else []),
*(["-f"] * args.force),
]
return config_parse_source_date_epoch(s, None)
+def config_default_proxy_url(namespace: argparse.Namespace) -> Optional[str]:
+ names = ("http_proxy", "https_proxy", "HTTP_PROXY", "HTTPS_PROXY")
+
+ for env in namespace.environment:
+ k, _, v = env.partition("=")
+ if k in names:
+ return cast(str, v)
+
+ for k, v in os.environ.items():
+ if k in names:
+ return cast(str, v)
+
+ return None
+
+
def config_default_kernel_command_line(namespace: argparse.Namespace) -> list[str]:
return [f"console={namespace.architecture.default_serial_tty()}"]
sign: bool
key: Optional[str]
+ proxy_url: Optional[str]
+ proxy_peer_certificate: Optional[Path]
+ proxy_client_certificate: Optional[Path]
+ proxy_client_key: Optional[Path]
incremental: bool
nspawn_settings: Optional[Path]
extra_search_paths: list[Path]
) -> list[PathString]:
mounts = [
*[Mount(d, d, ro=True) for d in self.extra_search_paths if not relaxed and not self.tools_tree],
+ *([Mount(p, "/proxy.cacert", ro=True)] if (p := self.proxy_peer_certificate) else []),
+ *([Mount(p, "/proxy.clientcert", ro=True)] if (p := self.proxy_client_certificate) else []),
+ *([Mount(p, "/proxy.clientkey", ro=True)] if (p := self.proxy_client_key) else []),
*mounts,
]
help="GPG key to use for signing",
),
+ ConfigSetting(
+ dest="proxy_url",
+ section="Host",
+ default_factory=config_default_proxy_url,
+ default_factory_depends=("environment",),
+ metavar="URL",
+ help="Set the proxy to use",
+ ),
+ ConfigSetting(
+ dest="proxy_peer_certificate",
+ section="Host",
+ parse=config_make_path_parser(),
+ paths=(
+ "/etc/pki/tls/certs/ca-bundle.crt",
+ "/etc/ssl/certs/ca-certificates.crt",
+ ),
+ help="Set the proxy peer certificate",
+ ),
+ ConfigSetting(
+ dest="proxy_client_certificate",
+ section="Host",
+ parse=config_make_path_parser(secret=True),
+ help="Set the proxy client certificate",
+ ),
+ ConfigSetting(
+ dest="proxy_client_key",
+ section="Host",
+ default_factory=lambda ns: ns.proxy_client_certificate,
+ default_factory_depends=("proxy_client_certificate",),
+ parse=config_make_path_parser(secret=True),
+ help="Set the proxy client key",
+ ),
ConfigSetting(
dest="incremental",
short="-i",
env["IMAGE_VERSION"] = args.image_version
if args.source_date_epoch is not None:
env["SOURCE_DATE_EPOCH"] = str(args.source_date_epoch)
- if proxy := os.getenv("http_proxy"):
- env["http_proxy"] = proxy
- if proxy := os.getenv("https_proxy"):
- env["https_proxy"] = proxy
+ if args.proxy_url is not None:
+ for e in ("http_proxy", "https_proxy"):
+ env[e] = args.proxy_url
+ env[e.upper()] = args.proxy_url
+ if args.proxy_peer_certificate:
+ env["GIT_PROXY_SSL_CAINFO"] = "/proxy.cacert"
+ if args.proxy_client_certificate:
+ env["GIT_PROXY_SSL_CERT"] = "/proxy.clientcert"
+ if args.proxy_client_key:
+ env["GIT_PROXY_SSL_KEY"] = "/proxy.clientkey"
if dnf := os.getenv("MKOSI_DNF"):
env["MKOSI_DNF"] = dnf
summary += f"""\
{bold("HOST CONFIGURATION")}:
+ Proxy URL: {none_to_none(config.proxy_url)}
+ Proxy Peer Certificate: {none_to_none(config.proxy_peer_certificate)}
+ Proxy Client Certificate: {none_to_none(config.proxy_client_certificate)}
+ Proxy Client Key: {none_to_none(config.proxy_client_key)}
Incremental: {yes_no(config.incremental)}
NSpawn Settings: {none_to_none(config.nspawn_settings)}
Extra Search Paths: {line_join_list(config.extra_search_paths)}
"--remote-name",
"--no-progress-meter",
"--fail",
+ *(["--proxy", context.config.proxy_url] if context.config.proxy_url else []),
+ *(["--proxy-capath", "/proxy.cacert"] if context.config.proxy_peer_certificate else []),
+ *(["--proxy-cert", "/proxy.clientcert"] if context.config.proxy_client_certificate else []),
+ *(["--proxy-key", "/proxy.clientkey"] if context.config.proxy_client_key else []),
f"{repourl}/repodata/repomd.xml",
],
sandbox=context.sandbox(
"-o", "DPkg::Options::=--path-exclude=/usr/share/info/*",
]
+ if context.config.proxy_url:
+ cmdline += [
+ "-o", f"Acquire::http::Proxy={context.config.proxy_url}",
+ "-o", f"Acquire::https::Proxy={context.config.proxy_url}",
+ ]
+
return cmdline
@classmethod
"--setopt=varsdir=/etc/dnf/vars",
]
+ if context.config.proxy_url:
+ cmdline += [f"--setopt=proxy={context.config.proxy_url}"]
+ if context.config.proxy_peer_certificate:
+ cmdline += ["--setopt=proxy_sslcacert=/proxy.cacert"]
+ if context.config.proxy_client_certificate:
+ cmdline += ["--setopt=proxy_sslclientcert=/proxy.clientcert"]
+ if context.config.proxy_client_key:
+ cmdline += ["--setopt=proxy_sslclientkey=/proxy.clientkey"]
+
return cmdline
@classmethod
### [Host] Section
+`ProxyUrl=`, `--proxy-url=`
+
+: Configure a proxy to be used for all outgoing network connections.
+ Various tools that mkosi invokes and for which the proxy can be
+ configured are configured to use this proxy. mkosi also sets various
+ well-known environment variables to specify the proxy to use for any
+ programs it invokes that may need internet access.
+
+`ProxyPeerCertificate=`, `--proxy-peer-certificate=`
+
+: Configure a file containing certificates used to verify the proxy.
+ Defaults to the system-wide certificate store. Note that not all
+ package managers that mkosi uses have support for specifying a proxy
+ peer certificate.
+
+`ProxyClientCertificate=`, `--proxy-client-certificate=`
+
+: Configure a file containing the certificate used to authenticate the
+ client with the proxy. Note that not all package managers that mkosi
+ uses have support for specifying a proxy client certificate.
+
+`ProxyClientKey=`, `--proxy-client-key=`
+
+: Configure a file containing the private key used to authenticate the
+ client with the proxy. Defaults to the proxy client certificate if one
+ is provided. Note that not all package managers that mkosi uses have
+ support for specifying a proxy client key.
+
`Incremental=`, `--incremental=`, `-i`
: Enable incremental build mode. In this mode, a copy of the OS image is
"/run/foo"
],
"Profile": "profile",
+ "ProxyClientCertificate": "/my/client/cert",
+ "ProxyClientKey": "/my/client/key",
+ "ProxyPeerCertificate": "/my/peer/cert",
+ "ProxyUrl": "https://my/proxy",
"QemuArgs": [],
"QemuCdrom": false,
"QemuDrives": [
postinst_scripts = [Path("/bar/qux")],
prepare_scripts = [Path("/run/foo")],
profile = "profile",
+ proxy_client_certificate = Path("/my/client/cert"),
+ proxy_client_key = Path("/my/client/key"),
+ proxy_peer_certificate = Path("/my/peer/cert"),
+ proxy_url = "https://my/proxy",
qemu_args = [],
qemu_cdrom = False,
qemu_drives = [QemuDrive("abc", 200, Path("/foo/bar"), "abc,qed"), QemuDrive("abc", 200, None, "")],