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
|
2022-06-27 23:48:31 +04:00
|
|
|
password-store = config.secretsConfig.password-store;
|
2021-01-11 18:09:34 +04:00
|
|
|
secret = { name, ... }: {
|
|
|
|
options = {
|
|
|
|
encrypted = mkOption {
|
|
|
|
type = path;
|
2021-06-15 02:10:46 +04:00
|
|
|
default = "${password-store}/${name}.gpg";
|
2021-01-11 18:09:34 +04:00
|
|
|
};
|
|
|
|
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;
|
2021-03-16 22:34:46 +04:00
|
|
|
default = [ "${name}" ];
|
2021-01-11 18:09:34 +04:00
|
|
|
};
|
|
|
|
__toString = mkOption {
|
|
|
|
readOnly = true;
|
|
|
|
default = s: s.decrypted;
|
|
|
|
};
|
2020-04-29 03:18:36 +04:00
|
|
|
};
|
2021-01-11 18:09:34 +04:00
|
|
|
};
|
|
|
|
|
2021-10-23 20:48:36 +04:00
|
|
|
activate-secrets = pkgs.writeShellScriptBin "activate-secrets" ''
|
|
|
|
set -euo pipefail
|
|
|
|
# Make sure card is available and unlocked
|
|
|
|
echo fetch | gpg --card-edit --no-tty --command-fd=0
|
|
|
|
${pkgs.gnupg}/bin/gpg --card-status
|
|
|
|
export SSH_AUTH_SOCK="$(gpgconf --list-dirs agent-ssh-socket)"
|
|
|
|
if [ -d "${password-store}/.git" ]; then
|
|
|
|
cd "${password-store}"; ${pkgs.git}/bin/git pull
|
|
|
|
else
|
|
|
|
${pkgs.git}/bin/git clone ${
|
|
|
|
lib.escapeShellArg config.secretsConfig.repo
|
|
|
|
} "${password-store}"
|
|
|
|
fi
|
|
|
|
cat ${password-store}/email/balsoft@balsoft.ru.gpg | ${pkgs.gnupg}/bin/gpg --decrypt > /dev/null
|
|
|
|
sudo systemctl restart ${allServices}
|
|
|
|
'';
|
|
|
|
|
2021-01-11 18:09:34 +04:00
|
|
|
decrypt = name: cfg:
|
|
|
|
with cfg; {
|
|
|
|
"${name}-secrets" = rec {
|
|
|
|
|
2022-06-21 17:42:10 +04:00
|
|
|
wantedBy = ["multi-user.target"];
|
|
|
|
|
2021-01-11 21:51:09 +04:00
|
|
|
requires = [ "user@1000.service" ];
|
2021-01-11 18:09:34 +04:00
|
|
|
after = requires;
|
|
|
|
|
|
|
|
preStart = ''
|
2021-01-11 21:51:09 +04:00
|
|
|
stat '${encrypted}'
|
2021-01-11 18:09:34 +04:00
|
|
|
mkdir -p '${builtins.dirOf decrypted}'
|
|
|
|
'';
|
|
|
|
|
|
|
|
script = ''
|
|
|
|
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'
|
2021-09-12 21:14:11 +04:00
|
|
|
if [[ -f '${decrypted}' ]]; then
|
|
|
|
echo "The decrypted file exists anyways, not failing"
|
|
|
|
exit 0
|
|
|
|
else
|
|
|
|
exit 1
|
|
|
|
fi
|
2021-01-11 18:09:34 +04:00
|
|
|
fi
|
|
|
|
'';
|
|
|
|
|
|
|
|
serviceConfig = {
|
|
|
|
Type = "oneshot";
|
|
|
|
RemainAfterExit = "yes";
|
2020-04-29 03:18:36 +04:00
|
|
|
};
|
2020-02-17 17:00:59 +04:00
|
|
|
};
|
|
|
|
};
|
2021-01-11 18:09:34 +04:00
|
|
|
|
|
|
|
addDependencies = name: cfg:
|
|
|
|
with cfg;
|
|
|
|
genAttrs services (service: rec {
|
2021-03-16 22:34:46 +04:00
|
|
|
requires = [ "${name}-secrets.service" ];
|
2021-01-11 18:09:34 +04:00
|
|
|
after = requires;
|
2021-01-11 21:51:09 +04:00
|
|
|
bindsTo = requires;
|
2021-01-11 18:09:34 +04:00
|
|
|
});
|
|
|
|
|
|
|
|
mkServices = name: cfg: [ (decrypt name cfg) (addDependencies name cfg) ];
|
2021-01-12 16:13:03 +04:00
|
|
|
|
2021-01-23 23:21:51 +04:00
|
|
|
allServices = toString (map (name: "${name}-envsubst.service")
|
2021-01-12 16:13:03 +04:00
|
|
|
(builtins.attrNames config.secrets-envsubst)
|
|
|
|
++ map (name: "${name}-secrets.service")
|
|
|
|
(builtins.attrNames config.secrets));
|
2021-01-11 18:09:34 +04:00
|
|
|
in {
|
2021-01-23 23:21:51 +04:00
|
|
|
options.secrets = lib.mkOption {
|
|
|
|
type = attrsOf (submodule secret);
|
|
|
|
default = { };
|
|
|
|
};
|
2021-06-12 02:21:24 +04:00
|
|
|
|
|
|
|
options.secretsConfig = {
|
2022-06-27 23:48:31 +04:00
|
|
|
password-store = lib.mkOption {
|
|
|
|
type = lib.types.path;
|
|
|
|
default = "/home/balsoft/.local/share/password-store";
|
|
|
|
};
|
2021-06-12 02:21:24 +04:00
|
|
|
repo = lib.mkOption {
|
|
|
|
type = str;
|
|
|
|
default = "ssh://git@github.com/balsoft/pass";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2021-01-11 21:51:09 +04:00
|
|
|
config.systemd.services =
|
|
|
|
mkMerge (concatLists (mapAttrsToList mkServices config.secrets));
|
|
|
|
|
|
|
|
config.security.sudo.extraRules = [{
|
|
|
|
users = [ "balsoft" ];
|
|
|
|
commands = [{
|
2021-01-12 16:13:03 +04:00
|
|
|
command = "/run/current-system/sw/bin/systemctl restart ${allServices}";
|
2021-01-11 21:51:09 +04:00
|
|
|
options = [ "NOPASSWD" ];
|
|
|
|
}];
|
|
|
|
}];
|
2021-01-11 18:09:34 +04:00
|
|
|
|
2021-10-23 20:48:36 +04:00
|
|
|
config.persist.derivative.directories = [ "/var/secrets" password-store ];
|
2021-06-08 20:35:21 +04:00
|
|
|
|
2021-01-11 18:09:34 +04:00
|
|
|
config.home-manager.users.balsoft = {
|
2021-10-23 20:48:36 +04:00
|
|
|
systemd.user.services.activate-secrets = {
|
|
|
|
Service = {
|
|
|
|
ExecStart = "${activate-secrets}/bin/activate-secrets";
|
|
|
|
Type = "oneshot";
|
|
|
|
};
|
|
|
|
Unit = {
|
|
|
|
PartOf = [ "graphical-session-pre.target" ];
|
|
|
|
};
|
|
|
|
Install.WantedBy = [ "graphical-session-pre.target" ];
|
2020-02-17 17:00:59 +04:00
|
|
|
};
|
2021-10-29 20:57:57 +04:00
|
|
|
systemd.user.services.pass-store-sync = {
|
|
|
|
Service = {
|
|
|
|
Environment = [
|
|
|
|
"PASSWORD_STORE_DIR=${password-store}"
|
|
|
|
"PATH=${lib.makeBinPath [ pkgs.pass pkgs.inotify-tools pkgs.gnupg ]}"
|
|
|
|
];
|
|
|
|
ExecStart = toString (pkgs.writeShellScript "pass-store-sync" ''
|
|
|
|
export SSH_AUTH_SOCK="$(gpgconf --list-dirs agent-ssh-socket)"
|
|
|
|
while inotifywait "$PASSWORD_STORE_DIR" -r -e move -e close_write -e create -e delete --exclude .git; do
|
|
|
|
sleep 0.1
|
|
|
|
pass git add --all
|
|
|
|
pass git commit -m "Change"
|
|
|
|
pass git pull --rebase
|
|
|
|
pass git push
|
|
|
|
done
|
|
|
|
'');
|
|
|
|
};
|
|
|
|
Unit = rec {
|
|
|
|
After = [ "activate-secrets.service" ];
|
|
|
|
Wants = After;
|
|
|
|
};
|
|
|
|
Install.WantedBy = [ "graphical-session-pre.target" ];
|
|
|
|
};
|
2021-06-15 02:10:46 +04:00
|
|
|
programs.password-store = {
|
|
|
|
enable = true;
|
|
|
|
package = pkgs.pass-wayland;
|
|
|
|
settings.PASSWORD_STORE_DIR = password-store;
|
|
|
|
};
|
2020-02-17 17:00:59 +04:00
|
|
|
};
|
|
|
|
}
|