nix-bitcoin/modules/secrets/setup-secrets.nix

95 lines
3.0 KiB
Nix
Raw Normal View History

2019-11-27 05:04:27 -08:00
{ config, pkgs, lib, ... }:
with lib;
let
secretsDir = "/secrets/"; # TODO: make this an option
secrets = (import ./make-secrets.nix { inherit config; }).activeSecrets;
setupSecrets = concatStrings (mapAttrsToList (n: v: ''
setupSecret ${n} ${v.user} ${v.group} ${v.permissions} ${optionalString (v.keyFile != null) (baseNameOf v.keyFile)}
'') secrets);
in
{
options.nix-bitcoin.setup-secrets = mkEnableOption "Set permissions for secrets generated by 'generate-secrets.sh'";
config = mkIf config.nix-bitcoin.setup-secrets {
systemd.targets.nix-bitcoin-secrets = {
requires = [ "setup-secrets.service" ];
after = [ "setup-secrets.service" ];
};
# Operation of this service:
# - Create missing secrets that are composed of attrs from secrets.nix
# - Set owner and permissions for all used secrets
# - Make all other secrets accessible to root only
# For all steps make sure that no secrets are copied to the nix-store.
#
systemd.services.setup-secrets = {
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
} // config.nix-bitcoin-services.defaultHardening;
script = ''
setupSecret() {
file="$1"
user="$2"
group="$3"
permissions="$4"
srcFile="$5"
if [[ ! -e $file ]]; then
if [[ $srcFile ]]; then
if [[ ! -e $srcFile ]]; then
echo "Error: Secret source file '$srcFile' is missing"
exit 1
fi
mv "$srcFile" "$file"
else
createFile "$file"
fi
fi
chown "$user:$group" "$file"
chmod "$permissions" "$file"
processedFiles+=("$file")
}
createFile() {
file="$1"
# 'nix eval' requires filesystem or daemon access to a store even if nothing is built.
# Use a private store so that 'nix eval' always succeeds regardless of the
# execution environment, like a container.
# This tmp dir is automatically removed by systemd via PrivateTmp
[[ $store ]] || store="$(mktemp -d)"
secretsFile="$(realpath secrets.nix)" \
${pkgs.nix}/bin/nix eval --raw --store "$store" "(
(import ${./make-secrets.nix} {
secretsFile = builtins.getEnv \"secretsFile\";
}).allSecrets.$file.text
)" > "$file"
}
dir="${secretsDir}"
if [[ ! -e $dir ]]; then
echo "Error: Secrets dir '$dir' is missing"
exit 1
fi
chown root: "$dir"
cd "$dir"
processedFiles=()
${setupSecrets}
# Make all other files accessible to root only
unprocessedFiles=$(comm -23 <(printf '%s\n' *) <(printf '%s\n' "''${processedFiles[@]}" | sort))
IFS=$'\n'
chown root: $unprocessedFiles
chmod 0440 $unprocessedFiles
# Now make the secrets dir accessible to other users
chmod 0751 "$dir"
'';
};
};
}