-
Notifications
You must be signed in to change notification settings - Fork 119
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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.
- Loading branch information
Showing
2 changed files
with
181 additions
and
180 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,187 +1,28 @@ | ||
{ | ||
lib, | ||
writeShellScriptBin, | ||
runtimeShell, | ||
callPackage, | ||
stdenv, | ||
rage, | ||
gnused, | ||
nix, | ||
mktemp, | ||
diffutils, | ||
ageBin ? "${ | ||
# we need at least rage 0.5.0 to support ssh keys | ||
if rage.version < "0.5.0" | ||
then callPackage ./rage.nix {} | ||
else rage | ||
}/bin/rage", | ||
}: let | ||
sedBin = "${gnused}/bin/sed"; | ||
nixInstantiate = "${nix}/bin/nix-instantiate"; | ||
mktempBin = "${mktemp}/bin/mktemp"; | ||
diffBin = "${diffutils}/bin/diff"; | ||
in | ||
lib.recursiveUpdate (writeShellScriptBin "agenix" '' | ||
set -Eeuo pipefail | ||
PACKAGE="agenix" | ||
function show_help () { | ||
echo "$PACKAGE - edit and rekey age secret files" | ||
echo " " | ||
echo "$PACKAGE -e FILE [-i PRIVATE_KEY]" | ||
echo "$PACKAGE -r [-i PRIVATE_KEY]" | ||
echo ' ' | ||
echo 'options:' | ||
echo '-h, --help show help' | ||
echo '-e, --edit FILE edits FILE using $EDITOR' | ||
echo '-r, --rekey re-encrypts all secrets with specified recipients' | ||
echo '-i, --identity identity to use when decrypting' | ||
echo '-v, --verbose verbose output' | ||
echo ' ' | ||
echo 'FILE an age-encrypted file' | ||
echo ' ' | ||
echo 'PRIVATE_KEY a path to a private SSH key used to decrypt file' | ||
echo ' ' | ||
echo 'EDITOR environment variable of editor to use when editing FILE' | ||
echo ' ' | ||
echo 'RULES environment variable with path to Nix file specifying recipient public keys.' | ||
echo "Defaults to './secrets.nix'" | ||
echo ' ' | ||
echo "agenix version: 0.13.0" | ||
echo "age binary path: ${ageBin}" | ||
echo "age version: $(${ageBin} --version)" | ||
} | ||
test $# -eq 0 && (show_help && exit 1) | ||
REKEY=0 | ||
DEFAULT_DECRYPT=(--decrypt) | ||
while test $# -gt 0; do | ||
case "$1" in | ||
-h|--help) | ||
show_help | ||
exit 0 | ||
;; | ||
-e|--edit) | ||
shift | ||
if test $# -gt 0; then | ||
export FILE=$1 | ||
else | ||
echo "no FILE specified" | ||
exit 1 | ||
fi | ||
shift | ||
;; | ||
-i|--identity) | ||
shift | ||
if test $# -gt 0; then | ||
DEFAULT_DECRYPT+=(--identity "$1") | ||
else | ||
echo "no PRIVATE_KEY specified" | ||
exit 1 | ||
fi | ||
shift | ||
;; | ||
-r|--rekey) | ||
shift | ||
REKEY=1 | ||
;; | ||
-v|--verbose) | ||
shift | ||
set -x | ||
;; | ||
*) | ||
show_help | ||
exit 1 | ||
;; | ||
esac | ||
done | ||
RULES=''${RULES:-./secrets.nix} | ||
function cleanup { | ||
if [ ! -z ''${CLEARTEXT_DIR+x} ] | ||
then | ||
rm -rf "$CLEARTEXT_DIR" | ||
fi | ||
if [ ! -z ''${REENCRYPTED_DIR+x} ] | ||
then | ||
rm -rf "$REENCRYPTED_DIR" | ||
fi | ||
} | ||
trap "cleanup" 0 2 3 15 | ||
function edit { | ||
FILE=$1 | ||
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) | ||
if [ -z "$KEYS" ] | ||
then | ||
>&2 echo "There is no rule for $FILE in $RULES." | ||
exit 1 | ||
fi | ||
CLEARTEXT_DIR=$(${mktempBin} -d) | ||
CLEARTEXT_FILE="$CLEARTEXT_DIR/$(basename "$FILE")" | ||
if [ -f "$FILE" ] | ||
then | ||
DECRYPT=("''${DEFAULT_DECRYPT[@]}") | ||
if [ -f "$HOME/.ssh/id_rsa" ]; then | ||
DECRYPT+=(--identity "$HOME/.ssh/id_rsa") | ||
fi | ||
if [ -f "$HOME/.ssh/id_ed25519" ]; then | ||
DECRYPT+=(--identity "$HOME/.ssh/id_ed25519") | ||
fi | ||
if [[ "''${DECRYPT[*]}" != *"--identity"* ]]; then | ||
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." | ||
exit 1 | ||
fi | ||
DECRYPT+=(-o "$CLEARTEXT_FILE" "$FILE") | ||
${ageBin} "''${DECRYPT[@]}" || exit 1 | ||
cp "$CLEARTEXT_FILE" "$CLEARTEXT_FILE.before" | ||
fi | ||
$EDITOR "$CLEARTEXT_FILE" | ||
if [ ! -f "$CLEARTEXT_FILE" ] | ||
then | ||
echo "$FILE wasn't created." | ||
return | ||
fi | ||
[ -f "$FILE" ] && [ "$EDITOR" != ":" ] && ${diffBin} "$CLEARTEXT_FILE.before" "$CLEARTEXT_FILE" 1>/dev/null && echo "$FILE wasn't changed, skipping re-encryption." && return | ||
ENCRYPT=() | ||
while IFS= read -r key | ||
do | ||
ENCRYPT+=(--recipient "$key") | ||
done <<< "$KEYS" | ||
REENCRYPTED_DIR=$(${mktempBin} -d) | ||
REENCRYPTED_FILE="$REENCRYPTED_DIR/$(basename "$FILE")" | ||
ENCRYPT+=(-o "$REENCRYPTED_FILE") | ||
${ageBin} "''${ENCRYPT[@]}" <"$CLEARTEXT_FILE" || exit 1 | ||
mv -f "$REENCRYPTED_FILE" "$1" | ||
} | ||
function rekey { | ||
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) | ||
for FILE in $FILES | ||
do | ||
echo "rekeying $FILE..." | ||
EDITOR=: edit "$FILE" | ||
cleanup | ||
done | ||
} | ||
[ $REKEY -eq 1 ] && rekey && exit 0 | ||
edit "$FILE" && cleanup && exit 0 | ||
'') | ||
{ | ||
meta.description = "age-encrypted secrets for NixOS"; | ||
} | ||
substituteAll, | ||
ageBin ? "${rage}/bin/rage", | ||
}: | ||
stdenv.mkDerivation rec { | ||
pname = "agenix"; | ||
version = "0.13.0"; | ||
src = substituteAll { | ||
inherit ageBin version; | ||
sedBin = "${gnused}/bin/sed"; | ||
nixInstantiate = "${nix}/bin/nix-instantiate"; | ||
mktempBin = "${mktemp}/bin/mktemp"; | ||
diffBin = "${diffutils}/bin/diff"; | ||
src = ./agenix.sh; | ||
}; | ||
dontUnpack = true; | ||
installPhase = '' | ||
install -D $src ${placeholder "out"}/bin/agenix | ||
''; | ||
meta.description = "age-encrypted secrets for NixOS"; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
set -Eeuo pipefail | ||
|
||
PACKAGE="agenix" | ||
|
||
function show_help () { | ||
echo "$PACKAGE - edit and rekey age secret files" | ||
echo " " | ||
echo "$PACKAGE -e FILE [-i PRIVATE_KEY]" | ||
echo "$PACKAGE -r [-i PRIVATE_KEY]" | ||
echo ' ' | ||
echo 'options:' | ||
echo '-h, --help show help' | ||
echo '-e, --edit FILE edits FILE using $EDITOR' | ||
echo '-r, --rekey re-encrypts all secrets with specified recipients' | ||
echo '-i, --identity identity to use when decrypting' | ||
echo '-v, --verbose verbose output' | ||
echo ' ' | ||
echo 'FILE an age-encrypted file' | ||
echo ' ' | ||
echo 'PRIVATE_KEY a path to a private SSH key used to decrypt file' | ||
echo ' ' | ||
echo 'EDITOR environment variable of editor to use when editing FILE' | ||
echo ' ' | ||
echo 'RULES environment variable with path to Nix file specifying recipient public keys.' | ||
echo "Defaults to './secrets.nix'" | ||
echo ' ' | ||
echo "agenix version: @version@" | ||
echo "age binary path: @ageBin@" | ||
echo "age version: $(@ageBin@ --version)" | ||
} | ||
|
||
test $# -eq 0 && (show_help && exit 1) | ||
|
||
REKEY=0 | ||
DEFAULT_DECRYPT=(--decrypt) | ||
|
||
while test $# -gt 0; do | ||
case "$1" in | ||
-h|--help) | ||
show_help | ||
exit 0 | ||
;; | ||
-e|--edit) | ||
shift | ||
if test $# -gt 0; then | ||
export FILE=$1 | ||
else | ||
echo "no FILE specified" | ||
exit 1 | ||
fi | ||
shift | ||
;; | ||
-i|--identity) | ||
shift | ||
if test $# -gt 0; then | ||
DEFAULT_DECRYPT+=(--identity "$1") | ||
else | ||
echo "no PRIVATE_KEY specified" | ||
exit 1 | ||
fi | ||
shift | ||
;; | ||
-r|--rekey) | ||
shift | ||
REKEY=1 | ||
;; | ||
-v|--verbose) | ||
shift | ||
set -x | ||
;; | ||
*) | ||
show_help | ||
exit 1 | ||
;; | ||
esac | ||
done | ||
|
||
RULES=${RULES:-./secrets.nix} | ||
|
||
function cleanup { | ||
if [ ! -z ${CLEARTEXT_DIR+x} ] | ||
then | ||
rm -rf "$CLEARTEXT_DIR" | ||
fi | ||
if [ ! -z ${REENCRYPTED_DIR+x} ] | ||
then | ||
rm -rf "$REENCRYPTED_DIR" | ||
fi | ||
} | ||
trap "cleanup" 0 2 3 15 | ||
|
||
function edit { | ||
FILE=$1 | ||
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) | ||
if [ -z "$KEYS" ] | ||
then | ||
>&2 echo "There is no rule for $FILE in $RULES." | ||
exit 1 | ||
fi | ||
CLEARTEXT_DIR=$(@mktempBin@ -d) | ||
CLEARTEXT_FILE="$CLEARTEXT_DIR/$(basename "$FILE")" | ||
if [ -f "$FILE" ] | ||
then | ||
DECRYPT=("${DEFAULT_DECRYPT[@]}") | ||
if [ -f "$HOME/.ssh/id_rsa" ]; then | ||
DECRYPT+=(--identity "$HOME/.ssh/id_rsa") | ||
fi | ||
if [ -f "$HOME/.ssh/id_ed25519" ]; then | ||
DECRYPT+=(--identity "$HOME/.ssh/id_ed25519") | ||
fi | ||
if [[ "${DECRYPT[*]}" != *"--identity"* ]]; then | ||
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." | ||
exit 1 | ||
fi | ||
DECRYPT+=(-o "$CLEARTEXT_FILE" "$FILE") | ||
@ageBin@ "${DECRYPT[@]}" || exit 1 | ||
cp "$CLEARTEXT_FILE" "$CLEARTEXT_FILE.before" | ||
fi | ||
$EDITOR "$CLEARTEXT_FILE" | ||
if [ ! -f "$CLEARTEXT_FILE" ] | ||
then | ||
echo "$FILE wasn't created." | ||
return | ||
fi | ||
[ -f "$FILE" ] && [ "$EDITOR" != ":" ] && @diffBin@ "$CLEARTEXT_FILE.before" "$CLEARTEXT_FILE" 1>/dev/null && echo "$FILE wasn't changed, skipping re-encryption." && return | ||
ENCRYPT=() | ||
while IFS= read -r key | ||
do | ||
ENCRYPT+=(--recipient "$key") | ||
done <<< "$KEYS" | ||
REENCRYPTED_DIR=$(@mktempBin@ -d) | ||
REENCRYPTED_FILE="$REENCRYPTED_DIR/$(basename "$FILE")" | ||
ENCRYPT+=(-o "$REENCRYPTED_FILE") | ||
@ageBin@ "${ENCRYPT[@]}" <"$CLEARTEXT_FILE" || exit 1 | ||
mv -f "$REENCRYPTED_FILE" "$1" | ||
} | ||
function rekey { | ||
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) | ||
for FILE in $FILES | ||
do | ||
echo "rekeying $FILE..." | ||
EDITOR=: edit "$FILE" | ||
cleanup | ||
done | ||
} | ||
[ $REKEY -eq 1 ] && rekey && exit 0 | ||
edit "$FILE" && cleanup && exit 0 |