Skip to content

Commit 87d3318

Browse files
committed
modules/age: add secrets change detection
1 parent 7f6e175 commit 87d3318

File tree

1 file changed

+34
-10
lines changed

1 file changed

+34
-10
lines changed

modules/age.nix

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,20 @@ let
1515
users = config.users.users;
1616

1717
newGeneration = ''
18-
_agenix_generation="$(basename "$(readlink ${cfg.secretsDir})" || echo 0)"
19-
(( ++_agenix_generation ))
18+
_agenix_last_generation=$(basename "$(readlink ${cfg.secretsDir})" || true)
19+
if [[ $_agenix_last_generation == ${secretsHash} ]]; then
20+
_agenix_generation=
21+
else
22+
_agenix_generation="${secretsHash}"
23+
fi
24+
if [[ $_agenix_generation ]]; then
2025
echo "[agenix] creating new generation in ${cfg.secretsMountPoint}/$_agenix_generation"
2126
mkdir -p "${cfg.secretsMountPoint}"
2227
chmod 0751 "${cfg.secretsMountPoint}"
2328
grep -q "${cfg.secretsMountPoint} ramfs" /proc/mounts || mount -t ramfs none "${cfg.secretsMountPoint}" -o nodev,nosuid,mode=0751
2429
mkdir -p "${cfg.secretsMountPoint}/$_agenix_generation"
2530
chmod 0751 "${cfg.secretsMountPoint}/$_agenix_generation"
31+
fi
2632
'';
2733

2834
identities = builtins.concatStringsSep " " (map (path: "-i ${path}") cfg.identityPaths);
@@ -60,18 +66,16 @@ let
6066
'') cfg.identityPaths;
6167

6268
cleanupAndLink = ''
63-
_agenix_generation="$(basename "$(readlink ${cfg.secretsDir})" || echo 0)"
64-
(( ++_agenix_generation ))
6569
echo "[agenix] symlinking new secrets to ${cfg.secretsDir} (generation $_agenix_generation)..."
6670
ln -sfn "${cfg.secretsMountPoint}/$_agenix_generation" ${cfg.secretsDir}
6771
68-
(( _agenix_generation > 1 )) && {
69-
echo "[agenix] removing old secrets (generation $(( _agenix_generation - 1 )))..."
70-
rm -rf "${cfg.secretsMountPoint}/$(( _agenix_generation - 1 ))"
72+
[[ $_agenix_last_generation ]] && {
73+
echo "[agenix] removing old secrets (generation $_agenix_last_generation)..."
74+
rm -rf "${cfg.secretsMountPoint}/$_agenix_last_generation"
7175
}
7276
'';
7377

74-
installSecrets = builtins.concatStringsSep "\n" (
78+
installSecrets = mkInstallScript (
7579
[ "echo '[agenix] decrypting secrets...'" ]
7680
++ testIdentities
7781
++ (map installSecret (builtins.attrValues cfg.secrets))
@@ -89,11 +93,25 @@ let
8993
chown :keys "${cfg.secretsMountPoint}" "${cfg.secretsMountPoint}/$_agenix_generation"
9094
'';
9195

92-
chownSecrets = builtins.concatStringsSep "\n" (
96+
chownSecrets = mkInstallScript (
9397
[ "echo '[agenix] chowning...'" ]
9498
++ [ chownMountPoint ]
9599
++ (map chownSecret (builtins.attrValues cfg.secrets)));
96100

101+
mkInstallScript = strings: ''
102+
[[ ! $_agenix_generation ]] || {
103+
${builtins.concatStringsSep "\n" strings}
104+
}
105+
'';
106+
107+
secretsHash = let
108+
sha256 = builtins.hashString "sha256" (builtins.concatStringsSep " " (
109+
map (secret: cfg.secrets.${secret}.path) (attrNames cfg.secrets)
110+
));
111+
in
112+
# Truncate to 128 bits (base16) to increase readability
113+
substring 0 32 sha256;
114+
97115
secretType = types.submodule ({ config, ... }: {
98116
options = {
99117
name = mkOption {
@@ -104,7 +122,13 @@ let
104122
'';
105123
};
106124
file = mkOption {
107-
type = types.path;
125+
type = mkOptionType {
126+
name = "nix-path";
127+
descriptionClass = "noun";
128+
check = builtins.isPath;
129+
merge = mergeEqualOption;
130+
};
131+
108132
description = ''
109133
Age file the secret is loaded from.
110134
'';

0 commit comments

Comments
 (0)