Files
chiasson-nix/modules/system/docker-registry-auth.nix
T

80 lines
3.3 KiB
Nix

# oci-containers runs `docker login` in ExecStartPre, which stores plaintext credentials
# in /root/.docker/config.json. For any container with `login` set, use in-memory
# DOCKER_AUTH_CONFIG instead (no per-service list to maintain).
{ ... }: {
flake.nixosModules.systemDockerRegistryAuth =
{ config, lib, pkgs, ... }:
let
cfg = config.chiasson.system.docker.ephemeralRegistryAuth;
ociCfg = lib.attrByPath [ "virtualisation" "oci-containers" ] null config;
backend = if ociCfg == null then "docker" else ociCfg.backend or "docker";
containerBackend =
if backend == "podman" then
lib.attrByPath [ "virtualisation" "podman" "package" ] pkgs.podman config
else
lib.attrByPath [ "virtualisation" "docker" "package" ] pkgs.docker config;
isValidLogin =
login: login.registry != null && login.username != null && login.passwordFile != null;
mkRegistryAuthPreStart =
login: lib.mkBefore ''
export DOCKER_AUTH_CONFIG="$(${pkgs.jq}/bin/jq -cn \
--arg registry ${lib.escapeShellArg login.registry} \
--arg user ${lib.escapeShellArg login.username} \
--arg pass "$(${pkgs.coreutils}/bin/tr -d '\n\r' < ${login.passwordFile})" \
'{auths: {($registry): {username: $user, password: $pass, auth: (($user + ":" + $pass) | @base64)}}}')"
'';
mkPreStartWithoutLogin =
name: container:
pkgs.writeShellScript "oci-pre-start-${name}" ''
${containerBackend}/bin/${backend} rm -f ${lib.escapeShellArg name} || true
${
lib.optionalString (container.imageFile != null) ''
${containerBackend}/bin/${backend} load -i ${container.imageFile}
''
}
${
lib.optionalString (container.imageStream != null) ''
${container.imageStream} | ${containerBackend}/bin/${backend} load
''
}
'';
in
{
options.chiasson.system.docker.ephemeralRegistryAuth = {
enable = lib.mkOption {
type = lib.types.bool;
default = true;
description = ''
Authenticate oci-containers registry pulls via in-memory `DOCKER_AUTH_CONFIG`
instead of `docker login`. Applies automatically to every container that sets
`virtualisation.oci-containers.containers.<name>.login`.
'';
};
};
# Read merged container config only when defining systemd overrides — never write back
# to `virtualisation.oci-containers.containers` (that causes infinite recursion).
config =
let
containers =
lib.attrByPath [ "virtualisation" "oci-containers" "containers" ] { } config;
containersWithLogin = lib.filterAttrs (_: c: isValidLogin (c.login or { })) containers;
in
lib.mkIf (cfg.enable && containersWithLogin != { }) {
systemd.services = lib.mapAttrs' (
name: container:
lib.nameValuePair (container.serviceName or "${backend}-${name}") {
preStart = mkRegistryAuthPreStart container.login;
serviceConfig.ExecStartPre = lib.mkForce [
"${mkPreStartWithoutLogin name container}"
];
}
) containersWithLogin;
};
};
}