jeremy-m
12/17/2017 - 1:53 PM

Transparent encryption/decryption with pre-commit and post-commit hooks

Transparent encryption/decryption with pre-commit and post-commit hooks

#!/bin/bash
#
# Pre-commit hook that verifies if all files containing 'vault: true' in it's modeline
# are encrypted.
# If not, commit will fail with an error message
#
# Original idea by Raphael Campardou (@ralovely)
#  * https://gist.github.com/ralovely/9367737
# Adapted for transparent encryption/decryption by leucos
#  * https://gist.github.com/leucos/405b406b9d6bde0c3d39
#
# File should be .git/hooks/pre-commit and executable
#
# If you want enryption/decryption to be transparent, you must add `.vault_password_hooks` 
# in your .gitignore file so the hooks won't delete this file, and reuse it when needed.
#

# Tag to look for
CRYPT_TAG='^# vault: true'

EXIT_STATUS=0
wipe="\033[1m\033[0m"
yellow='\033[1;33m'
red='\e[0;31m'
green='\e[0;32m'
# carriage return hack. Leave it on 2 lines.
cr='
'

if [[ -f "$HOME/.ansible_vault_pass" ]]; then
  KEY_LOCATION="~/.ansible_vault_pass"
  USE_LOCAL_ENCRYPTION=false
else
  KEY_LOCATION=".vault_password_hooks"
  USE_LOCAL_ENCRYPTION=true
fi

for f in $(git diff --cached --name-only)
do
  # test for the presence of the required bit.
  MATCH=`head -n4 $f | grep --no-messages -- "$CRYPT_TAG"`
  if [ ! -z "$MATCH" ] ; then
    # Build the list of unencrypted files if any
    UNENCRYPTED_FILES="$f$cr$UNENCRYPTED_FILES"
    EXIT_STATUS=1
  fi
done

if [ ! $EXIT_STATUS = 0 ] ; then
  echo "# ENCRYPTING "
  echo "# Ansible Vault files with key in : ${KEY_LOCATION}"
  echo "#"

  if [[ "$USE_LOCAL_ENCRYPTION" == "true" ]]; then
    if [ ! -r '.vault_password_hooks' ]; then
      echo -n "# Enter vault password:" 
      exec < /dev/tty
      read -s password
      echo -en "\n# Confirm vault password:" 
      read -s password_confirm
      echo -e "\n#"
      if [ "x${password}" != "x${password_confirm}" ]; then
        echo -e "#\n# ${red}Error: passwords do not match !${wipe}"
        exit 1
      fi
      echo $password > .vault_password_hooks
    fi
  fi

  while read -r line; do
    if [ -n "$line" ]; then
      echo -ne "#\tencrypting: $line${wipe} => "

      if [[ "$USE_LOCAL_ENCRYPTION" == "true" ]]; then
        if ansible-vault encrypt --vault-password-file=.vault_password_hooks ${line} > /dev/null 2>&1; then
          echo -e " ${green}success${wipe}"
          git add ${line}
        else
          echo -e " ${red}error${wipe}"
          exit 1
        fi
      else
        if ansible-vault encrypt ${line} > /dev/null 2>&1; then
          echo -e " ${green}success${wipe}"
          git add ${line}
        else
          echo -e " ${red}error${wipe}"
          exit 1
        fi
      fi
    fi
  done <<< "$UNENCRYPTED_FILES"

  if [[ "$USE_LOCAL_ENCRYPTION" == "true" ]]; then
    if [ ! -r '.gitignore' ] || ! grep '^.vault_password_hooks$' .gitignore > /dev/null; then
      echo -e "# Removed temporary password file."
      echo -e "# Add .vault_password_hooks to .gitgnore to make it persistent"
      rm .vault_password_hooks
    fi
  fi

  echo "#"
  exit 0
fi
exit $EXIT_STATUS
#!/bin/bash
#
# Post-commit hook that decrypts files containing '$ANSIBLE_VAULT'
#
# Original idea by Raphael Campardou (@ralovely)
#  * https://gist.github.com/ralovely/9367737
# Adapted for transparent encryption/decryption by leucos
#  * https://gist.github.com/leucos/405b406b9d6bde0c3d39
#
# File should be .git/hooks/post-commit and executable

CRYPT_TAG='^\$ANSIBLE_VAULT'

EXIT_STATUS=0
wipe="\033[1m\033[0m"
yellow='\033[1;33m'
red='\e[0;31m'
green='\e[0;32m'
# carriage return hack. Leave it on 2 lines.
cr='
'

if [[ -f "$HOME/.ansible_vault_pass" ]]; then
  KEY_LOCATION="~/.ansible_vault_pass"
  USE_LOCAL_ENCRYPTION=false
else
  KEY_LOCATION=".vault_password_hooks"
  USE_LOCAL_ENCRYPTION=true
fi

if [[ "$USE_LOCAL_ENCRYPTION" == "true" ]]; then
  if [ ! -r '.vault_password_hooks' ]; then
    exit 0
  fi
fi

for f in $(git diff --name-only HEAD^ HEAD)
do
  # test for the presence of the required bit.
  MATCH=`head -n4 $f | grep --no-messages -- "$CRYPT_TAG"`
  if [ ! -z "$MATCH" ] ; then
    # Build the list of unencrypted files if any
    UNENCRYPTED_FILES="$f$cr$UNENCRYPTED_FILES"
    EXIT_STATUS=1
  fi
done
if [ ! $EXIT_STATUS = 0 ] ; then
  echo "# DECRYPTING:"
  echo "# Ansible Vault files with key in : ${KEY_LOCATION}"
  echo "#"

  while read -r line; do
    if [ -n "$line" ]; then
      echo -ne "#\tdecrypting: $line${wipe} => "
      if [[ "$USE_LOCAL_ENCRYPTION" == "true" ]]; then
        if ansible-vault decrypt ${line} --vault-password-file=.vault_password_hooks > /dev/null 2>&1; then
          echo -e " ${green}success${wipe}"
        else
          echo -e " ${red}error${wipe}"
          exit 1
        fi
      else
        if ansible-vault decrypt ${line} > /dev/null 2>&1; then
          echo -e " ${green}success${wipe}"
        else
          echo -e " ${red}error${wipe}"
          exit 1
        fi
      fi
    fi
  done <<< "$UNENCRYPTED_FILES"

  echo "#"
  echo
  exit 0
fi
exit $EXIT_STATUS