|
1 | 1 | {
|
2 | 2 | lib,
|
3 |
| - writeShellScriptBin, |
4 |
| - runtimeShell, |
5 |
| - callPackage, |
| 3 | + stdenv, |
6 | 4 | rage,
|
7 | 5 | gnused,
|
8 | 6 | nix,
|
9 | 7 | mktemp,
|
10 | 8 | diffutils,
|
11 |
| - ageBin ? "${ |
12 |
| - # we need at least rage 0.5.0 to support ssh keys |
13 |
| - if rage.version < "0.5.0" |
14 |
| - then callPackage ./rage.nix {} |
15 |
| - else rage |
16 |
| - }/bin/rage", |
17 |
| -}: let |
18 |
| - sedBin = "${gnused}/bin/sed"; |
19 |
| - nixInstantiate = "${nix}/bin/nix-instantiate"; |
20 |
| - mktempBin = "${mktemp}/bin/mktemp"; |
21 |
| - diffBin = "${diffutils}/bin/diff"; |
22 |
| -in |
23 |
| - lib.recursiveUpdate (writeShellScriptBin "agenix" '' |
24 |
| - set -Eeuo pipefail |
25 |
| -
|
26 |
| - PACKAGE="agenix" |
27 |
| -
|
28 |
| - function show_help () { |
29 |
| - echo "$PACKAGE - edit and rekey age secret files" |
30 |
| - echo " " |
31 |
| - echo "$PACKAGE -e FILE [-i PRIVATE_KEY]" |
32 |
| - echo "$PACKAGE -r [-i PRIVATE_KEY]" |
33 |
| - echo ' ' |
34 |
| - echo 'options:' |
35 |
| - echo '-h, --help show help' |
36 |
| - echo '-e, --edit FILE edits FILE using $EDITOR' |
37 |
| - echo '-r, --rekey re-encrypts all secrets with specified recipients' |
38 |
| - echo '-i, --identity identity to use when decrypting' |
39 |
| - echo '-v, --verbose verbose output' |
40 |
| - echo ' ' |
41 |
| - echo 'FILE an age-encrypted file' |
42 |
| - echo ' ' |
43 |
| - echo 'PRIVATE_KEY a path to a private SSH key used to decrypt file' |
44 |
| - echo ' ' |
45 |
| - echo 'EDITOR environment variable of editor to use when editing FILE' |
46 |
| - echo ' ' |
47 |
| - echo 'RULES environment variable with path to Nix file specifying recipient public keys.' |
48 |
| - echo "Defaults to './secrets.nix'" |
49 |
| - echo ' ' |
50 |
| - echo "agenix version: 0.13.0" |
51 |
| - echo "age binary path: ${ageBin}" |
52 |
| - echo "age version: $(${ageBin} --version)" |
53 |
| - } |
54 |
| -
|
55 |
| - test $# -eq 0 && (show_help && exit 1) |
56 |
| -
|
57 |
| - REKEY=0 |
58 |
| - DEFAULT_DECRYPT=(--decrypt) |
59 |
| -
|
60 |
| - while test $# -gt 0; do |
61 |
| - case "$1" in |
62 |
| - -h|--help) |
63 |
| - show_help |
64 |
| - exit 0 |
65 |
| - ;; |
66 |
| - -e|--edit) |
67 |
| - shift |
68 |
| - if test $# -gt 0; then |
69 |
| - export FILE=$1 |
70 |
| - else |
71 |
| - echo "no FILE specified" |
72 |
| - exit 1 |
73 |
| - fi |
74 |
| - shift |
75 |
| - ;; |
76 |
| - -i|--identity) |
77 |
| - shift |
78 |
| - if test $# -gt 0; then |
79 |
| - DEFAULT_DECRYPT+=(--identity "$1") |
80 |
| - else |
81 |
| - echo "no PRIVATE_KEY specified" |
82 |
| - exit 1 |
83 |
| - fi |
84 |
| - shift |
85 |
| - ;; |
86 |
| - -r|--rekey) |
87 |
| - shift |
88 |
| - REKEY=1 |
89 |
| - ;; |
90 |
| - -v|--verbose) |
91 |
| - shift |
92 |
| - set -x |
93 |
| - ;; |
94 |
| - *) |
95 |
| - show_help |
96 |
| - exit 1 |
97 |
| - ;; |
98 |
| - esac |
99 |
| - done |
100 |
| -
|
101 |
| - RULES=''${RULES:-./secrets.nix} |
102 |
| -
|
103 |
| - function cleanup { |
104 |
| - if [ ! -z ''${CLEARTEXT_DIR+x} ] |
105 |
| - then |
106 |
| - rm -rf "$CLEARTEXT_DIR" |
107 |
| - fi |
108 |
| - if [ ! -z ''${REENCRYPTED_DIR+x} ] |
109 |
| - then |
110 |
| - rm -rf "$REENCRYPTED_DIR" |
111 |
| - fi |
112 |
| - } |
113 |
| - trap "cleanup" 0 2 3 15 |
114 |
| -
|
115 |
| - function edit { |
116 |
| - FILE=$1 |
117 |
| - KEYS=$((${nixInstantiate} --eval -E "(let rules = import $RULES; in builtins.concatStringsSep \"\n\" rules.\"$FILE\".publicKeys)" | ${sedBin} 's/"//g' | ${sedBin} 's/\\n/\n/g') | ${sedBin} '/^$/d' || exit 1) |
118 |
| -
|
119 |
| - if [ -z "$KEYS" ] |
120 |
| - then |
121 |
| - >&2 echo "There is no rule for $FILE in $RULES." |
122 |
| - exit 1 |
123 |
| - fi |
124 |
| -
|
125 |
| - CLEARTEXT_DIR=$(${mktempBin} -d) |
126 |
| - CLEARTEXT_FILE="$CLEARTEXT_DIR/$(basename "$FILE")" |
127 |
| -
|
128 |
| - if [ -f "$FILE" ] |
129 |
| - then |
130 |
| - DECRYPT=("''${DEFAULT_DECRYPT[@]}") |
131 |
| - if [ -f "$HOME/.ssh/id_rsa" ]; then |
132 |
| - DECRYPT+=(--identity "$HOME/.ssh/id_rsa") |
133 |
| - fi |
134 |
| - if [ -f "$HOME/.ssh/id_ed25519" ]; then |
135 |
| - DECRYPT+=(--identity "$HOME/.ssh/id_ed25519") |
136 |
| - fi |
137 |
| - if [[ "''${DECRYPT[*]}" != *"--identity"* ]]; then |
138 |
| - echo "No identity found to decrypt $FILE. Try adding an SSH key at $HOME/.ssh/id_rsa or $HOME/.ssh/id_ed25519 or using the --identity flag to specify a file." |
139 |
| - exit 1 |
140 |
| - fi |
141 |
| - DECRYPT+=(-o "$CLEARTEXT_FILE" "$FILE") |
142 |
| - ${ageBin} "''${DECRYPT[@]}" || exit 1 |
143 |
| - cp "$CLEARTEXT_FILE" "$CLEARTEXT_FILE.before" |
144 |
| - fi |
145 |
| -
|
146 |
| - $EDITOR "$CLEARTEXT_FILE" |
147 |
| -
|
148 |
| - if [ ! -f "$CLEARTEXT_FILE" ] |
149 |
| - then |
150 |
| - echo "$FILE wasn't created." |
151 |
| - return |
152 |
| - fi |
153 |
| - [ -f "$FILE" ] && [ "$EDITOR" != ":" ] && ${diffBin} "$CLEARTEXT_FILE.before" "$CLEARTEXT_FILE" 1>/dev/null && echo "$FILE wasn't changed, skipping re-encryption." && return |
154 |
| -
|
155 |
| - ENCRYPT=() |
156 |
| - while IFS= read -r key |
157 |
| - do |
158 |
| - ENCRYPT+=(--recipient "$key") |
159 |
| - done <<< "$KEYS" |
160 |
| -
|
161 |
| - REENCRYPTED_DIR=$(${mktempBin} -d) |
162 |
| - REENCRYPTED_FILE="$REENCRYPTED_DIR/$(basename "$FILE")" |
163 |
| -
|
164 |
| - ENCRYPT+=(-o "$REENCRYPTED_FILE") |
165 |
| -
|
166 |
| - ${ageBin} "''${ENCRYPT[@]}" <"$CLEARTEXT_FILE" || exit 1 |
167 |
| -
|
168 |
| - mv -f "$REENCRYPTED_FILE" "$1" |
169 |
| - } |
170 |
| -
|
171 |
| - function rekey { |
172 |
| - FILES=$((${nixInstantiate} --eval -E "(let rules = import $RULES; in builtins.concatStringsSep \"\n\" (builtins.attrNames rules))" | ${sedBin} 's/"//g' | ${sedBin} 's/\\n/\n/g') || exit 1) |
173 |
| -
|
174 |
| - for FILE in $FILES |
175 |
| - do |
176 |
| - echo "rekeying $FILE..." |
177 |
| - EDITOR=: edit "$FILE" |
178 |
| - cleanup |
179 |
| - done |
180 |
| - } |
181 |
| -
|
182 |
| - [ $REKEY -eq 1 ] && rekey && exit 0 |
183 |
| - edit "$FILE" && cleanup && exit 0 |
184 |
| - '') |
185 |
| - { |
186 |
| - meta.description = "age-encrypted secrets for NixOS"; |
187 |
| - } |
| 9 | + substituteAll, |
| 10 | + ageBin ? "${rage}/bin/rage", |
| 11 | +}: |
| 12 | +stdenv.mkDerivation rec { |
| 13 | + pname = "agenix"; |
| 14 | + version = "0.13.0"; |
| 15 | + src = substituteAll { |
| 16 | + inherit ageBin version; |
| 17 | + sedBin = "${gnused}/bin/sed"; |
| 18 | + nixInstantiate = "${nix}/bin/nix-instantiate"; |
| 19 | + mktempBin = "${mktemp}/bin/mktemp"; |
| 20 | + diffBin = "${diffutils}/bin/diff"; |
| 21 | + src = ./agenix.sh; |
| 22 | + }; |
| 23 | + dontUnpack = true; |
| 24 | + installPhase = '' |
| 25 | + install -D $src ${placeholder "out"}/bin/agenix |
| 26 | + ''; |
| 27 | + meta.description = "age-encrypted secrets for NixOS"; |
| 28 | +} |
0 commit comments