#!/bin/bash # # Script to remove GPG key from git-crypt # # It will re-initialize git-crypt for the repository and re-add all keys except # the one requested for removal. # # Note: You still need to change all your secrets to fully protect yourself. # Removing a user will prevent them from reading future changes but they will # still have a copy of the data up to the point of their removal. # # Usage: see 'remove-gpg-user.sh -h' # remove-gpg-user.sh -l : list GPG keys configured within git-crypt for the current directory # remove-gpg-user.sh -r : remove specified key from git-crypt configuration # Ex: remove-gpg-user.sh -r 3BC18383F838C0B815B961480F8CAF5467D # # Typical workflow (assuming the script is placed in ~/bin/) : # # cd /path/to/protected/repo # git checkout -b git-crypt-remove # ~/bin/$(basename $0) -l # List configured GPG keys # ~/bin/$(basename $0) -r # # The script will create multiple commits to your repo. Feel free to squash them # all down to one. # # Based on https://github.com/AGWA/git-crypt/issues/47#issuecomment-212734882 # # GIST source https://gist.github.com/glogiotatidis/e0ab45ed5575a9d7973390dace0552b0 # amended to work on Mac OS and with cosmetic changes for a more convenient interface in # https://gist.github.com/Falkor/7b29f16f5f79404fe41476be0d992783 ################# set -eo pipefail KEY_TO_REMOVE= KEY_FINGERPRINT= CMD_PREFIX= ############### print_error_and_exit() { echo -e "*** ERROR *** $*\n Usage: see '$(basename $0) -h'"; exit 1; } really_continue() { echo -n -e "/!\\ WARNING: $*\n Are you sure you want to continue? [Y|n]" read ans case $ans in n*|N*) exit 1;; esac } print_usage() { cat < : remove key from git-crypt configuration Typical workflow: cd /path/to/protected/repo git checkout -b git-crypt-remove ~/bin/$(basename $0) -l # List configured GPG keys ~/bin/$(basename $0) -r You can check the full, 64-bit (8-byte) key ID for a key within your keyring with gpg -k [email | pattern] gpg -k --with-colons [email | pattern | id] | awk -F: '/^pub:/ { print $5 }' EOF } ### # Print info for a given key from your keyring ## print_key_info() { [ -z "$1" ] && print_error_and_exit "[$FUNCNAME] missing text argument" local key=$1 local gpgid=$(gpg --list-keys --with-colons $key | awk -F: '/^pub:/ { print $5 }') local fpr=$(gpg -k --with-colons $key | awk -F: '/^fpr:/ { print $10; exit; }') # Only first fpr echo "==== Key Fingerprint: ${fpr} ===" echo "==== Long GPG ID: ${gpgid}" gpg --list-key "$key" || print_error_and_exit "Couldn't find info about $key" export KEY_FINGERPRINT=$fpr } ### # List GPG keys configured for protecting this repository ## list_git_crypt_keys() { for f in .git-crypt/keys/default/0/*.gpg; do # key="$(basename "${f}" .gpg)" print_key_info $(basename "${f}" .gpg) # gpgid=$(gpg --list-keys --with-colons $key | awk -F: '/^pub:/ { print $5 }') # echo "==== Key Fingerprint: ${key} ===" # echo "==== Long GPG ID: ${gpgid}" # gpg --list-key "$key" || print_error_and_exit "Couldn't find info about $key" done } ##### Let's go ##### # Check for options while [ $# -ge 1 ]; do case $1 in -h | --help) print_usage; exit 0;; -l | --list) list_git_crypt_keys; exit 0;; -r | --remove) shift; KEY_TO_REMOVE=$1;; # -n | --dry-run) CMD_PREFIX=echo ;; esac shift done [ -z "${KEY_TO_REMOVE}" ] && print_error_and_exit "No key to remove has been indicated" print_key_info "${KEY_TO_REMOVE}" [ -z "${KEY_FINGERPRINT}" ] && print_error_and_exit "Unable to retrieve key fingerprint" really_continue "About to remove the GPG Key ID ${KEY_TO_REMOVE} from Git-crypt configuration" # Below code adapted from @glogiotatidis - https://gist.github.com/glogiotatidis/e0ab45ed5575a9d7973390dace0552b0 TMPDIR=$(mktemp -d) CURRENT_DIR=$(git rev-parse --show-toplevel) BASENAME=$(basename `pwd`) TMPFILE=list-encrypted-files.txt cat < ${TMPFILE} if [ -s "${TMPFILE}" ]; then awk '{print $2}' ${TMPFILE} | xargs rm git commit -a -m "Remove encrypted files" fi rm -rf .git-crypt git commit -m "Remove git-crypt (in particular configuration related to key ${KEY_TO_REMOVE})" .git-crypt rm -rf .git/git-crypt # Re-initialize git crypt git crypt init # Add existing users, except the for keyfilename in `ls $CURRENT_DIR/.git-crypt/keys/default/0/*gpg`; do basename=`basename $keyfilename` key=${basename%.*} if [[ $key == $KEY_FINGERPRINT ]]; then echo "ignoring key ${KEY_FINGERPRINT} to be removed" continue; fi git crypt add-gpg-user $key done cd $CURRENT_DIR for i in `awk '{print $2}' ${TMPDIR}/${BASENAME}/${TMPFILE}`; do #cp -rp --parents $i $TMPDIR/$BASENAME; #gcp -rp --parents $i $TMPDIR/$BASENAME; rsync -rp -R $i $TMPDIR/$BASENAME; done cd $TMPDIR/$BASENAME for i in `awk '{print $2}' ${TMPFILE}`; do git add $i done git commit -m "New encrypted files" || true popd git crypt lock git pull $TMPDIR/$BASENAME rm -rf $TMPDIR