|
15 | 15 | users = config.users.users; |
16 | 16 |
|
17 | 17 | 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 |
20 | 25 | echo "[agenix] creating new generation in ${cfg.secretsMountPoint}/$_agenix_generation" |
21 | 26 | mkdir -p "${cfg.secretsMountPoint}" |
22 | 27 | chmod 0751 "${cfg.secretsMountPoint}" |
23 | 28 | grep -q "${cfg.secretsMountPoint} ramfs" /proc/mounts || mount -t ramfs none "${cfg.secretsMountPoint}" -o nodev,nosuid,mode=0751 |
24 | 29 | mkdir -p "${cfg.secretsMountPoint}/$_agenix_generation" |
25 | 30 | chmod 0751 "${cfg.secretsMountPoint}/$_agenix_generation" |
| 31 | + fi |
26 | 32 | ''; |
27 | 33 |
|
28 | 34 | identities = builtins.concatStringsSep " " (map (path: "-i ${path}") cfg.identityPaths); |
|
60 | 66 | '') cfg.identityPaths; |
61 | 67 |
|
62 | 68 | cleanupAndLink = '' |
63 | | - _agenix_generation="$(basename "$(readlink ${cfg.secretsDir})" || echo 0)" |
64 | | - (( ++_agenix_generation )) |
65 | 69 | echo "[agenix] symlinking new secrets to ${cfg.secretsDir} (generation $_agenix_generation)..." |
66 | 70 | ln -sfn "${cfg.secretsMountPoint}/$_agenix_generation" ${cfg.secretsDir} |
67 | 71 |
|
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" |
71 | 75 | } |
72 | 76 | ''; |
73 | 77 |
|
74 | | - installSecrets = builtins.concatStringsSep "\n" ( |
| 78 | + installSecrets = mkInstallScript ( |
75 | 79 | [ "echo '[agenix] decrypting secrets...'" ] |
76 | 80 | ++ testIdentities |
77 | 81 | ++ (map installSecret (builtins.attrValues cfg.secrets)) |
|
89 | 93 | chown :keys "${cfg.secretsMountPoint}" "${cfg.secretsMountPoint}/$_agenix_generation" |
90 | 94 | ''; |
91 | 95 |
|
92 | | - chownSecrets = builtins.concatStringsSep "\n" ( |
| 96 | + chownSecrets = mkInstallScript ( |
93 | 97 | [ "echo '[agenix] chowning...'" ] |
94 | 98 | ++ [ chownMountPoint ] |
95 | 99 | ++ (map chownSecret (builtins.attrValues cfg.secrets))); |
96 | 100 |
|
| 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 | + |
97 | 115 | secretType = types.submodule ({ config, ... }: { |
98 | 116 | options = { |
99 | 117 | name = mkOption { |
|
104 | 122 | ''; |
105 | 123 | }; |
106 | 124 | 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 | + |
108 | 132 | description = '' |
109 | 133 | Age file the secret is loaded from. |
110 | 134 | ''; |
|
0 commit comments