Skip to content

Working with ansible‐vault and Git

Mitchell Alessio edited this page Sep 13, 2023 · 10 revisions

ansible-vault with Git

Add ~/.gitattributes

*.eyaml diff=ansible-vault

Add to ~/.gitconfig

attributesfile = ~/.gitattributes
[diff "ansible-vault"]
textconv = "/Users/<USERNAME>/.bin/vault-decrypt"
cachetextconv = false

Add to PATH-available bin directory

Directory for this document is ~/.bin. This directory is not in PATH by default, so you will need to add it.

vault-pass

#!/bin/bash

SSM_VAULT_PASSWORD_PATH="/bfd/mgmt/jenkins/sensitive/ansible_vault_password"

/opt/homebrew/bin/aws ssm get-parameter \
  --region us-east-1 \
  --output text \
  --with-decryption \
  --query 'Parameter.Value' \
  --name "$SSM_VAULT_PASSWORD_PATH"

vault-edit

#!/usr/bin/env bash
ansible-vault edit --vault-password-file=~/.bin/vault-pass "${1}" 

vault-decrypt

Specifying LC_ALL and LANG along with the full path to the ansible-vault binary fixes broken diffing in Visual Studio Code. If you are not using Visual Studio Code, and ansible-vault is in your PATH, then they can removed.

#!/usr/bin/env bash

LC_ALL="en_US.UTF-8" LANG="en_US.UTF-8" /opt/homebrew/bin/ansible-vault decrypt --vault-password-file=~/.bin/vault-pass "${1}" --output -

vault-merge

sponge is not included by default on Mac OS, so you will need to install it with the moreutils or sponge package using brew, i.e.:

brew install moreutils
#!/bin/sh

# vault-merge
# Benjamin Ragheb <[email protected]>

# This shell script handles conflicts generated by attempts to merge encrypted
# Ansible Vault files. Run `git merge` as usual; when git warns of a merge
# conflict, run this command to attempt a merge on the unencrypted versions of
# the file. If there are conflicts, you will be given a chance to correct them
# in $EDITOR.

# First, we ensure we are inside the working directory of a git repo.

GIT_ROOT=$(git rev-parse --show-toplevel)
if [ $? != 0 ]; then
    exit $?
fi

VAULT_FILE=$1

# If no vault has been provided, abort!

if [ -z "$VAULT_FILE" ]; then
    echo "Usage: $0 VAULT_FILE"
    exit 1
fi

# Fetch the base (common ancestor) version of the encrypted vault file, save
# it to a temporary location, and decrypt it. (Hat Tip to the git-merge manual
# page for tipping me off to the `git show :1:path` notation.)

BASE=$(mktemp "${VAULT_FILE}".base.XXXX)
git show :1:"${VAULT_FILE}" > "$BASE" 2> /dev/null
if [ $? != 0 ]; then
    echo "Path '${VAULT_FILE}' does not have any conflicts."
    rm "$BASE"
    exit 1
fi
vault-decrypt "$BASE" | sponge "$BASE" || exit $?

# Do the same with the current (branch we are merging INTO) version of the vault
# file.

CURRENT=$(mktemp "${VAULT_FILE}".current.XXXX)
git show :2:"${VAULT_FILE}" > "$CURRENT" 2> /dev/null
vault-decrypt "$CURRENT" | sponge "$CURRENT" || exit $?

# And finally, with the other (branch we a merging FROM) version of the vault.

OTHER=$(mktemp "${VAULT_FILE}".other.XXXX)
git show :3:"${VAULT_FILE}" > "$OTHER" 2> /dev/null
vault-decrypt "$OTHER" | sponge "$OTHER" || exit $?

# Now that we have all three versions decrypted, ask git to attempt the merge
# again. If it fails again due to a conflict, open $EDITOR and let the user
# perform a manual merge.

git merge-file "$CURRENT" "$BASE" "$OTHER"
if [ $? == 0 ]; then
    echo "Merge OK"
else
    echo "Merge conflict; opening editor to resolve."
    $EDITOR "$CURRENT"
fi

# Now that we're done, encrypt the file and move it into the repo, and clean up
# the temporary files (they contain secrets!).

ansible-vault encrypt --vault-password-file=~/.bin/vault-pass "$CURRENT"
cp "$CURRENT" "$VAULT_FILE"
rm "$BASE" "$CURRENT" "$OTHER"

echo "$VAULT_FILE has been updated."
echo "    (use \"git add $VAULT_FILE\" to mark as resolved)"
echo "    (or re-run this command to retry the merge)"
exit 0
Clone this wiki locally