Skip to content

Commit 9ac24cf

Browse files
committed
contrib: use mkDerivation for agenix cli
I want to move toward a world where we test the agenix cli. I feel this is a reasonable organizational step, so we can separate the nix code from the bash code.
1 parent 6d3a415 commit 9ac24cf

File tree

2 files changed

+181
-180
lines changed

2 files changed

+181
-180
lines changed

pkgs/agenix.nix

Lines changed: 21 additions & 180 deletions
Original file line numberDiff line numberDiff line change
@@ -1,187 +1,28 @@
11
{
22
lib,
3-
writeShellScriptBin,
4-
runtimeShell,
5-
callPackage,
3+
stdenv,
64
rage,
75
gnused,
86
nix,
97
mktemp,
108
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+
}

pkgs/agenix.sh

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
set -Eeuo pipefail
2+
3+
PACKAGE="agenix"
4+
5+
function show_help () {
6+
echo "$PACKAGE - edit and rekey age secret files"
7+
echo " "
8+
echo "$PACKAGE -e FILE [-i PRIVATE_KEY]"
9+
echo "$PACKAGE -r [-i PRIVATE_KEY]"
10+
echo ' '
11+
echo 'options:'
12+
echo '-h, --help show help'
13+
echo '-e, --edit FILE edits FILE using $EDITOR'
14+
echo '-r, --rekey re-encrypts all secrets with specified recipients'
15+
echo '-i, --identity identity to use when decrypting'
16+
echo '-v, --verbose verbose output'
17+
echo ' '
18+
echo 'FILE an age-encrypted file'
19+
echo ' '
20+
echo 'PRIVATE_KEY a path to a private SSH key used to decrypt file'
21+
echo ' '
22+
echo 'EDITOR environment variable of editor to use when editing FILE'
23+
echo ' '
24+
echo 'RULES environment variable with path to Nix file specifying recipient public keys.'
25+
echo "Defaults to './secrets.nix'"
26+
echo ' '
27+
echo "agenix version: @version@"
28+
echo "age binary path: @ageBin@"
29+
echo "age version: $(@ageBin@ --version)"
30+
}
31+
32+
test $# -eq 0 && (show_help && exit 1)
33+
34+
REKEY=0
35+
DEFAULT_DECRYPT=(--decrypt)
36+
37+
while test $# -gt 0; do
38+
case "$1" in
39+
-h|--help)
40+
show_help
41+
exit 0
42+
;;
43+
-e|--edit)
44+
shift
45+
if test $# -gt 0; then
46+
export FILE=$1
47+
else
48+
echo "no FILE specified"
49+
exit 1
50+
fi
51+
shift
52+
;;
53+
-i|--identity)
54+
shift
55+
if test $# -gt 0; then
56+
DEFAULT_DECRYPT+=(--identity "$1")
57+
else
58+
echo "no PRIVATE_KEY specified"
59+
exit 1
60+
fi
61+
shift
62+
;;
63+
-r|--rekey)
64+
shift
65+
REKEY=1
66+
;;
67+
-v|--verbose)
68+
shift
69+
set -x
70+
;;
71+
*)
72+
show_help
73+
exit 1
74+
;;
75+
esac
76+
done
77+
78+
RULES=${RULES:-./secrets.nix}
79+
80+
function cleanup {
81+
if [ ! -z ${CLEARTEXT_DIR+x} ]
82+
then
83+
rm -rf "$CLEARTEXT_DIR"
84+
fi
85+
if [ ! -z ${REENCRYPTED_DIR+x} ]
86+
then
87+
rm -rf "$REENCRYPTED_DIR"
88+
fi
89+
}
90+
trap "cleanup" 0 2 3 15
91+
92+
function edit {
93+
FILE=$1
94+
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)
95+
96+
if [ -z "$KEYS" ]
97+
then
98+
>&2 echo "There is no rule for $FILE in $RULES."
99+
exit 1
100+
fi
101+
102+
CLEARTEXT_DIR=$(@mktempBin@ -d)
103+
CLEARTEXT_FILE="$CLEARTEXT_DIR/$(basename "$FILE")"
104+
105+
if [ -f "$FILE" ]
106+
then
107+
DECRYPT=("${DEFAULT_DECRYPT[@]}")
108+
if [ -f "$HOME/.ssh/id_rsa" ]; then
109+
DECRYPT+=(--identity "$HOME/.ssh/id_rsa")
110+
fi
111+
if [ -f "$HOME/.ssh/id_ed25519" ]; then
112+
DECRYPT+=(--identity "$HOME/.ssh/id_ed25519")
113+
fi
114+
if [[ "${DECRYPT[*]}" != *"--identity"* ]]; then
115+
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."
116+
exit 1
117+
fi
118+
DECRYPT+=(-o "$CLEARTEXT_FILE" "$FILE")
119+
@ageBin@ "${DECRYPT[@]}" || exit 1
120+
cp "$CLEARTEXT_FILE" "$CLEARTEXT_FILE.before"
121+
fi
122+
123+
$EDITOR "$CLEARTEXT_FILE"
124+
125+
if [ ! -f "$CLEARTEXT_FILE" ]
126+
then
127+
echo "$FILE wasn't created."
128+
return
129+
fi
130+
[ -f "$FILE" ] && [ "$EDITOR" != ":" ] && @diffBin@ "$CLEARTEXT_FILE.before" "$CLEARTEXT_FILE" 1>/dev/null && echo "$FILE wasn't changed, skipping re-encryption." && return
131+
132+
ENCRYPT=()
133+
while IFS= read -r key
134+
do
135+
ENCRYPT+=(--recipient "$key")
136+
done <<< "$KEYS"
137+
138+
REENCRYPTED_DIR=$(@mktempBin@ -d)
139+
REENCRYPTED_FILE="$REENCRYPTED_DIR/$(basename "$FILE")"
140+
141+
ENCRYPT+=(-o "$REENCRYPTED_FILE")
142+
143+
@ageBin@ "${ENCRYPT[@]}" <"$CLEARTEXT_FILE" || exit 1
144+
145+
mv -f "$REENCRYPTED_FILE" "$1"
146+
}
147+
148+
function rekey {
149+
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)
150+
151+
for FILE in $FILES
152+
do
153+
echo "rekeying $FILE..."
154+
EDITOR=: edit "$FILE"
155+
cleanup
156+
done
157+
}
158+
159+
[ $REKEY -eq 1 ] && rekey && exit 0
160+
edit "$FILE" && cleanup && exit 0

0 commit comments

Comments
 (0)