nixos-config/modules/secrets.nix

163 lines
4.6 KiB
Nix
Raw Normal View History

2020-04-27 05:39:00 +04:00
{ pkgs, config, lib, inputs, ... }:
2020-02-17 17:00:59 +04:00
with lib;
with types;
let
secret = { name, ... }: {
options = {
encrypted = mkOption {
type = path;
default = inputs.secrets + "/${name}.gpg";
};
decrypted = mkOption {
type = path;
default = "/var/secrets/${name}";
};
decrypt = mkOption {
default = pkgs.writeShellScript "gpg-decrypt" ''
set -euo pipefail
export GPG_TTY="$(tty)"
${pkgs.gnupg}/bin/gpg-connect-agent updatestartuptty /bye 1>&2
${pkgs.gnupg}/bin/gpg --batch --no-tty --decrypt
'';
};
user = mkOption {
type = str;
default = "balsoft";
};
owner = mkOption {
type = str;
default = "root:root";
};
permissions = mkOption {
type = lib.types.addCheck lib.types.str
(perm: !isNull (builtins.match "[0-7]{3}" perm));
default = "400";
};
services = mkOption {
type = listOf str;
default = [ "${name}.service" ];
};
__toString = mkOption {
readOnly = true;
default = s: s.decrypted;
};
2020-04-29 03:18:36 +04:00
};
};
decrypt = name: cfg:
with cfg; {
"${name}-secrets" = rec {
wantedBy = [ "multi-user.target" ];
requires = [ "user@1000.service" "gpg-setup.service" ];
after = requires;
preStart = ''
[[ -r '${encrypted}' ]]
mkdir -p '${builtins.dirOf decrypted}'
'';
script = ''
${optionalString (pkgs.gnupg.version == "2.2.24")
"/run/wrappers/bin/sudo -u ${user} ${pkgs.gnupg}/bin/gpg --card-status"
# 2.2.24 is broken and needs this hack for yubi to work
}
if cat '${encrypted}' | /run/wrappers/bin/sudo -u ${user} ${cfg.decrypt} > '${decrypted}.tmp'; then
mv -f '${decrypted}.tmp' '${decrypted}'
chown '${owner}' '${decrypted}'
chmod '${permissions}' '${decrypted}'
else
echo "Failed to decrypt the secret"
rm '${decrypted}.tmp'
fi
'';
serviceConfig = {
Type = "oneshot";
RemainAfterExit = "yes";
2020-04-29 03:18:36 +04:00
};
unitConfig = {
ConditionPathExists = [
"/run/user/${
toString config.users.users.${user}.uid
}/gnupg/S.gpg-agent"
];
2020-04-29 03:18:36 +04:00
};
2020-02-17 17:00:59 +04:00
};
};
addDependencies = name: cfg:
with cfg;
genAttrs services (service: rec {
requires = [ "${name}-secrets" ];
after = requires;
});
gpg-setup = rec {
wantedBy = [ "multi-user.target" ];
requires = [ "user@1000.service" ];
after = requires;
path = [ pkgs.gnupg ];
script = "echo fetch | gpg --card-edit --no-tty --command-fd=0";
serviceConfig = {
Type = "oneshot";
RemainAfterExit = "yes";
User = "balsoft";
2020-02-17 17:00:59 +04:00
};
};
mkServices = name: cfg: [ (decrypt name cfg) (addDependencies name cfg) ];
in {
options.secrets = lib.mkOption { type = attrsOf (submodule secret); };
config.systemd.services = mkMerge ([{ inherit gpg-setup; }]
++ concatLists (mapAttrsToList mkServices config.secrets));
config.home-manager.users.balsoft = {
systemd.user.services.pass-sync = {
Install.WantedBy =
[ "sway-session.target" ]; # Start when the gpg agent is ready
Service = {
ExecStartPre = toString (pkgs.writeShellScript "clone-pass-repo" ''
set -euo pipefail
'');
ExecStart = toString (pkgs.writeShellScript "pass-sync" ''
set -euo pipefail
cd $HOME/.password-store
while ${pkgs.inotifyTools}/bin/inotifywait "$HOME/.password-store/.git" -r -e modify -e close_write -e move -e create -e delete; do
sleep 0.5
${pkgs.git}/bin/git push
done
'');
2020-02-17 17:00:59 +04:00
};
};
wayland.windowManager.sway = {
config.startup = [{
command = toString (pkgs.writeShellScript "activate-secrets" ''
set -euo pipefail
# Make sure card is available and unlocked
${pkgs.gnupg}/bin/gpg --card-status
cat ${inputs.secrets}/email/balsoft@balsoft.ru.gpg | ${pkgs.gnupg}/bin/gpg --decrypt
systemctl restart '*-secrets.service' '*-envsubst.service'
if [ -d "$HOME/.password-store" ]; then
cd "$HOME/.password-store"; ${pkgs.git}/bin/git pull
else
${pkgs.git}/bin/git clone ssh://git@github.com/balsoft/pass "$HOME/.password-store"
fi
ln -sf ${pkgs.writeShellScript "push" "${pkgs.git}/bin/git push origin master"} "$HOME/.password-store/.git/hooks/post-commit"
'');
}];
2020-02-17 17:00:59 +04:00
};
};
}