Merge pull request #158 from whentze/decrypt-only

add -d/--decrypt option to decrypt a file to stdout
This commit is contained in:
Ryan Mulligan 2023-02-22 20:25:46 -08:00 committed by GitHub
commit c2a71c83c7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 45 additions and 5 deletions

View file

@ -483,6 +483,8 @@ Overriding `age.secretsMountPoint` example:
### agenix CLI reference ### agenix CLI reference
``` ```
agenix - edit and rekey age secret files
agenix -e FILE [-i PRIVATE_KEY] agenix -e FILE [-i PRIVATE_KEY]
agenix -r [-i PRIVATE_KEY] agenix -r [-i PRIVATE_KEY]
@ -490,6 +492,7 @@ options:
-h, --help show help -h, --help show help
-e, --edit FILE edits FILE using $EDITOR -e, --edit FILE edits FILE using $EDITOR
-r, --rekey re-encrypts all secrets with specified recipients -r, --rekey re-encrypts all secrets with specified recipients
-d, --decrypt FILE decrypts FILE to STDOUT
-i, --identity identity to use when decrypting -i, --identity identity to use when decrypting
-v, --verbose verbose output -v, --verbose verbose output
@ -499,6 +502,8 @@ PRIVATE_KEY a path to a private SSH key used to decrypt file
EDITOR environment variable of editor to use when editing FILE EDITOR environment variable of editor to use when editing FILE
If STDIN is not interactive, EDITOR will be set to "cp /dev/stdin"
RULES environment variable with path to Nix file specifying recipient public keys. RULES environment variable with path to Nix file specifying recipient public keys.
Defaults to './secrets.nix' Defaults to './secrets.nix'
``` ```

View file

@ -14,6 +14,7 @@ function show_help () {
# shellcheck disable=SC2016 # shellcheck disable=SC2016
echo '-e, --edit FILE edits FILE using $EDITOR' echo '-e, --edit FILE edits FILE using $EDITOR'
echo '-r, --rekey re-encrypts all secrets with specified recipients' echo '-r, --rekey re-encrypts all secrets with specified recipients'
echo '-d, --decrypt FILE decrypts FILE to STDOUT'
echo '-i, --identity identity to use when decrypting' echo '-i, --identity identity to use when decrypting'
echo '-v, --verbose verbose output' echo '-v, --verbose verbose output'
echo ' ' echo ' '
@ -45,6 +46,7 @@ function err() {
test $# -eq 0 && (show_help && exit 1) test $# -eq 0 && (show_help && exit 1)
REKEY=0 REKEY=0
DECRYPT_ONLY=0
DEFAULT_DECRYPT=(--decrypt) DEFAULT_DECRYPT=(--decrypt)
while test $# -gt 0; do while test $# -gt 0; do
@ -77,6 +79,17 @@ while test $# -gt 0; do
shift shift
REKEY=1 REKEY=1
;; ;;
-d|--decrypt)
shift
DECRYPT_ONLY=1
if test $# -gt 0; then
export FILE=$1
else
echo "no FILE specified"
exit 1
fi
shift
;;
-v|--verbose) -v|--verbose)
shift shift
set -x set -x
@ -89,7 +102,6 @@ while test $# -gt 0; do
done done
RULES=${RULES:-./secrets.nix} RULES=${RULES:-./secrets.nix}
function cleanup { function cleanup {
if [ -n "${CLEARTEXT_DIR+x}" ] if [ -n "${CLEARTEXT_DIR+x}" ]
then then
@ -102,10 +114,13 @@ function cleanup {
} }
trap "cleanup" 0 2 3 15 trap "cleanup" 0 2 3 15
function edit { function keys {
FILE=$1 (@nixInstantiate@ --eval -E "(let rules = import $RULES; in builtins.concatStringsSep \"\n\" rules.\"$1\".publicKeys)" | @sedBin@ 's/"//g' | @sedBin@ 's/\\n/\n/g') | @sedBin@ '/^$/d' || exit 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) }
function decrypt {
FILE=$1
KEYS=$2
if [ -z "$KEYS" ] if [ -z "$KEYS" ]
then then
err "There is no rule for $FILE in $RULES." err "There is no rule for $FILE in $RULES."
@ -132,6 +147,12 @@ function edit {
@ageBin@ "${DECRYPT[@]}" || exit 1 @ageBin@ "${DECRYPT[@]}" || exit 1
cp "$CLEARTEXT_FILE" "$CLEARTEXT_FILE.before" cp "$CLEARTEXT_FILE" "$CLEARTEXT_FILE.before"
fi fi
}
function edit {
FILE=$1
KEYS=$(keys "$FILE") || exit 1
decrypt "$FILE" "$KEYS" || exit 1
[ -t 0 ] || EDITOR='cp /dev/stdin' [ -t 0 ] || EDITOR='cp /dev/stdin'
@ -160,6 +181,14 @@ function edit {
mv -f "$REENCRYPTED_FILE" "$1" mv -f "$REENCRYPTED_FILE" "$1"
} }
function decrypt_only {
FILE=$1
KEYS=$(keys "$FILE") || exit 1
decrypt "$FILE" "$KEYS"
printf "%s" "$(<"${CLEARTEXT_FILE}")"
cleanup
}
function rekey { 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) 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)
@ -172,4 +201,5 @@ function rekey {
} }
[ $REKEY -eq 1 ] && rekey && exit 0 [ $REKEY -eq 1 ] && rekey && exit 0
[ $DECRYPT_ONLY -eq 1 ] && decrypt_only "${FILE}" && exit 0
edit "$FILE" && cleanup && exit 0 edit "$FILE" && cleanup && exit 0

View file

@ -90,6 +90,11 @@ pkgs.nixosTest {
# user1 can edit a secret by piping in contents # user1 can edit a secret by piping in contents
system1.succeed(userDo("echo 'secret1234' | agenix -e passwordfile-user1.age")) system1.succeed(userDo("echo 'secret1234' | agenix -e passwordfile-user1.age"))
assert "secret1234" in system1.succeed(userDo("EDITOR=cat agenix -e passwordfile-user1.age"))
# and get it back out via --decrypt
assert "secret1234" in system1.succeed(userDo("agenix -d passwordfile-user1.age"))
# finally, the plain text should not linger around anywhere in the filesystem.
system1.fail("grep -r secret1234 /tmp")
''; '';
} }