2023-09-06 14:09:43 +00:00
|
|
|
{ config, lib, pkgs, ... }:
|
|
|
|
let
|
2023-09-14 13:22:13 +00:00
|
|
|
passwordstoreDir = "\${PASSWORD_STORE_DIR:-$HOME/.password-store}";
|
2023-09-06 14:09:43 +00:00
|
|
|
in
|
|
|
|
{
|
2023-09-27 19:26:58 +00:00
|
|
|
options.clan.password-store.targetDirectory = lib.mkOption {
|
|
|
|
type = lib.types.path;
|
|
|
|
default = "/etc/secrets";
|
|
|
|
description = ''
|
|
|
|
The directory where the password store is uploaded to.
|
|
|
|
'';
|
|
|
|
};
|
2023-09-06 14:09:43 +00:00
|
|
|
config = lib.mkIf (config.clanCore.secretStore == "password-store") {
|
2023-09-27 19:26:58 +00:00
|
|
|
clanCore.secretsDirectory = config.clan.password-store.targetDirectory;
|
2023-09-29 16:30:11 +00:00
|
|
|
clanCore.secretsUploadDirectory = config.clan.password-store.targetDirectory;
|
2023-10-06 16:34:49 +00:00
|
|
|
system.clan.generateSecrets = lib.mkIf (config.clanCore.secrets != { }) (
|
|
|
|
pkgs.writeScript "generate-secrets" ''
|
|
|
|
#!/bin/sh
|
|
|
|
set -efu
|
2023-09-06 14:09:43 +00:00
|
|
|
|
2023-10-06 16:34:49 +00:00
|
|
|
test -d "$CLAN_DIR"
|
|
|
|
PATH=${lib.makeBinPath [
|
|
|
|
pkgs.pass
|
|
|
|
]}:$PATH
|
2023-09-06 14:09:43 +00:00
|
|
|
|
2023-10-06 16:34:49 +00:00
|
|
|
# TODO maybe initialize password store if it doesn't exist yet
|
2023-09-06 14:09:43 +00:00
|
|
|
|
2023-10-06 16:34:49 +00:00
|
|
|
${lib.foldlAttrs (acc: n: v: ''
|
|
|
|
${acc}
|
|
|
|
# ${n}
|
|
|
|
# if any of the secrets are missing, we regenerate all connected facts/secrets
|
|
|
|
(if ! (${lib.concatMapStringsSep " && " (x: "test -e ${passwordstoreDir}/machines/${config.clanCore.machineName}/${x.name}.gpg >/dev/null") (lib.attrValues v.secrets)}); then
|
2023-09-06 14:09:43 +00:00
|
|
|
|
2023-10-06 16:34:49 +00:00
|
|
|
tmpdir=$(mktemp -d)
|
|
|
|
trap "rm -rf $tmpdir" EXIT
|
|
|
|
cd $tmpdir
|
2023-10-05 14:24:33 +00:00
|
|
|
|
2023-10-06 16:34:49 +00:00
|
|
|
facts=$(mktemp -d)
|
|
|
|
trap "rm -rf $facts" EXIT
|
|
|
|
secrets=$(mktemp -d)
|
|
|
|
trap "rm -rf $secrets" EXIT
|
|
|
|
( ${v.generator} )
|
2023-09-06 14:09:43 +00:00
|
|
|
|
2023-10-06 16:34:49 +00:00
|
|
|
${lib.concatMapStrings (fact: ''
|
|
|
|
mkdir -p "$CLAN_DIR"/"$(dirname ${fact.path})"
|
|
|
|
cp "$facts"/${fact.name} "$CLAN_DIR"/${fact.path}
|
|
|
|
'') (lib.attrValues v.facts)}
|
2023-09-06 14:09:43 +00:00
|
|
|
|
2023-10-06 16:34:49 +00:00
|
|
|
${lib.concatMapStrings (secret: ''
|
|
|
|
cat "$secrets"/${secret.name} | pass insert -m machines/${config.clanCore.machineName}/${secret.name}
|
|
|
|
'') (lib.attrValues v.secrets)}
|
|
|
|
fi)
|
|
|
|
'') "" config.clanCore.secrets}
|
|
|
|
''
|
|
|
|
);
|
2023-09-14 11:49:20 +00:00
|
|
|
system.clan.uploadSecrets = pkgs.writeScript "upload-secrets" ''
|
2023-09-06 14:09:43 +00:00
|
|
|
#!/bin/sh
|
|
|
|
set -efu
|
|
|
|
|
|
|
|
umask 0077
|
|
|
|
|
|
|
|
PATH=${lib.makeBinPath [
|
|
|
|
pkgs.pass
|
|
|
|
pkgs.git
|
|
|
|
pkgs.findutils
|
|
|
|
pkgs.rsync
|
2023-09-14 11:49:57 +00:00
|
|
|
]}:$PATH:${lib.getBin pkgs.openssh}
|
2023-09-06 14:09:43 +00:00
|
|
|
|
|
|
|
if test -e ${passwordstoreDir}/.git; then
|
|
|
|
local_pass_info=$(
|
|
|
|
git -C ${passwordstoreDir} log -1 --format=%H machines/${config.clanCore.machineName}
|
|
|
|
# we append a hash for every symlink, otherwise we would miss updates on
|
|
|
|
# files where the symlink points to
|
|
|
|
find ${passwordstoreDir}/machines/${config.clanCore.machineName} -type l \
|
|
|
|
-exec realpath {} + |
|
|
|
|
sort |
|
|
|
|
xargs -r -n 1 git -C ${passwordstoreDir} log -1 --format=%H
|
|
|
|
)
|
2023-09-29 16:30:11 +00:00
|
|
|
remote_pass_info=$(ssh ${config.clan.networking.deploymentAddress} -- ${lib.escapeShellArg ''
|
2023-09-06 14:09:43 +00:00
|
|
|
cat ${config.clan.password-store.targetDirectory}/.pass_info || :
|
2023-10-01 21:58:31 +00:00
|
|
|
''} || :)
|
2023-09-06 14:09:43 +00:00
|
|
|
|
|
|
|
if test "$local_pass_info" = "$remote_pass_info"; then
|
|
|
|
echo secrets already match
|
2023-10-04 19:29:19 +00:00
|
|
|
exit 23
|
2023-09-06 14:09:43 +00:00
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
|
|
|
find ${passwordstoreDir}/machines/${config.clanCore.machineName} -type f -follow ! -name .gpg-id |
|
|
|
|
while read -r gpg_path; do
|
|
|
|
|
|
|
|
rel_name=''${gpg_path#${passwordstoreDir}}
|
|
|
|
rel_name=''${rel_name%.gpg}
|
|
|
|
|
|
|
|
pass_date=$(
|
|
|
|
if test -e ${passwordstoreDir}/.git; then
|
|
|
|
git -C ${passwordstoreDir} log -1 --format=%aI "$gpg_path"
|
|
|
|
fi
|
|
|
|
)
|
|
|
|
pass_name=$rel_name
|
2023-09-29 16:30:11 +00:00
|
|
|
tmp_path="$SECRETS_DIR"/$(basename $rel_name)
|
2023-09-06 14:09:43 +00:00
|
|
|
|
|
|
|
mkdir -p "$(dirname "$tmp_path")"
|
|
|
|
pass show "$pass_name" > "$tmp_path"
|
|
|
|
if [ -n "$pass_date" ]; then
|
|
|
|
touch -d "$pass_date" "$tmp_path"
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
|
|
|
|
if test -n "''${local_pass_info-}"; then
|
2023-09-29 16:30:11 +00:00
|
|
|
echo "$local_pass_info" > "$SECRETS_DIR"/.pass_info
|
2023-09-06 14:09:43 +00:00
|
|
|
fi
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|