Git clean / smudge filters для секретов хранилища

20

Я пытаюсь настроить фильтр clean / smudge в git для автоматического шифрования и дешифрования файлов, содержащих секреты, через команду ansible-vault .

Особенность команды ansible-vault в том, что она не идемпотентна (она создает новый двоичный файл каждый раз, когда она вызывается для одних и тех же данных).

Я начал с реализации, предложенной на этой странице блога . К сожалению, это не сработало правильно, так как всякий раз, когда вызывается smudge (будь то проверка git или просто состояние git), секретные файлы выглядят измененными для git, даже если это не так.

Поэтому я подумал, будет ли git сравнивать двоичный файл, который он имеет в индексе, с текущим файлом с чистой фильтрацией, и я попытался построить этот скрипт следующим образом:

#!/bin/sh -x
# clean filter, it is invoked with %f

if [ ! -r "$HOME/.vault_password" ]; then
  exit 1
fi

tmp=`mktemp`
cat > $tmp

# get the plain text from the binary in the index
tmphead=`mktemp`
git show HEAD:$1 > $tmphead
contenthead=`echo "embedded" | ansible-vault view $tmphead --vault-password-file=$HOME/.vault_password`
export PAGER=cat
echo -n "$contenthead" | tee $tmphead

# if current and index plain text version differ
if [ "`md5sum $tmp | cut -d' ' -f1`" != "`md5sum $tmphead | cut -d' ' -f1`" ]; then
  tmpcrypt=`mktemp`
  cp $tmp $tmpcrypt
  # generate a new crypted blob
  echo "embedded" | ansible-vault encrypt $tmpcrypt --vault-password-file=$HOME/.vault_password > /dev/null 2>&1
  cat "$tmpcrypt"
else
  # just return the HEAD version
  cat "$tmphead"
fi

rm $tmp $tmphead $tmpcrypt

Разница здесь в том, что он пытается сравнить текущие и HEAD-версии секретных файлов в виде простого текста (незашифрованные) и только в случае их различия выводит новый двоичный двоичный объект, зашифрованный с помощью ansible-vault.

К сожалению, после этого изменения git продолжает думать, что секретный файл всегда изменяется. Даже после git addповторного создания файла, чтобы вычислить git blob, git считает, что файл отличается, и позволяет изменениям перейти в фиксацию. Обратите внимание, что git diffвозвращайте пустые изменения, как и должно быть.

Для справки, это пятно:

#!/bin/sh

if [ ! -r "$HOME/.vault_password" ]; then
  exit 1
fi

tmp=`mktemp`
cat > $tmp

export PAGER='cat'
CONTENT="`echo "embedded" | ansible-vault view "$tmp" --vault-password-file=$HOME/.vault_password 2> /dev/null`"

if echo "$CONTENT" | grep 'ERROR: data is not encrypted' > /dev/null; then
  echo "Looks like one file was commited clear text"
  echo "Please fix this before continuing !"
  exit 1
else
  echo -n "$CONTENT"
fi

rm $tmp

и это diff:

#!/bin/sh

if [ ! -r "$HOME/.vault_password" ]; then
  exit 1
fi

export PAGER='cat'
CONTENT=`echo "embedded" | ansible-vault view "$1" --vault-password-file=$HOME/.vault_password 2> /dev/null`

if echo "$CONTENT" | grep 'ERROR: data is not encrypted' > /dev/null; then
  cat "$1"
else
  echo "$CONTENT"
fi
ᴳᵁᴵᴰᴼ
источник
Я обновил скрипты, которые ведут себя правильно, за исключением случаев, когда git пытается автоматически объединить конфликты в хранилищах, которые я
опубликую в
1
Бросив бутылку в море, но: может ли файл быть другим из-за разных концов строк или другой кодовой страницы?
Тенсибай
Я бы попробовал удалить -nиз эха пятна, но это предположение. Нет скрытого параметра для git diff, говорящего игнорировать окончания одной строки?
Тенсибай
Еще одна идея: github.com/dellis23/ansible-toolkit
углублюсь

Ответы:

8

Проблема здесь вызвана случайной солью в шифровании ansible-хранилища. Вы можете взломать класс VaultEditor, чтобы передать ему соль из аргумента в ansible-vault. В lib/ansible/parsing/vault/__init__.pyэтой строке генерируется случайная соль . Он вызывается из lib / ansible / cli / vault.py, где вы можете легко добавить аргумент для фиксированной соли. Если вы измените его, отправьте вышестоящий патч в Ansible, я бы с удовольствием его использовал.

Эта проблема более подробно обсуждается здесь в хакерских новостях . И есть другие реализации с инструментами, которые принимают фиксированную соль, а именно gitcrypt , transcrypt . Вот также ссылка на еще одну реализацию, использующую ansible-vault, называемую ansible-vault-tools , но эта, насколько я знаю, имеет ту же самую проблему.

Иржи Клауда
источник
Если вы проверите код, я использую контрольную сумму, чтобы обойти проблему с солью переменной, т.е. Сначала расшифруйте хранилище HEAD в папке tmp и сравните контрольные суммы простых текстовых файлов перед созданием нового двоичного двоичного объекта. Это немного медленно, но на самом деле хорошо. Моя проблема сейчас в слияниях; в некоторых ситуациях это работает, в других я включаю BLOB-объект, прежде чем смогу расшифровать его, и он сломается.
ᴳᵁᴵᴰᴼ
Если вы посмотрите на три примера, которые я связал, то есть несколько обходных путей для слияний. И это обсуждается в комментариях хакеров.
Иржи Клуда
Кстати, слияние сложно. Вам нужно понять, что в случае, когда вы выбираете все свои изменения или все изменения в восходящем потоке во время слияния, git выяснит это с помощью сравнения хешей, которое сработает, если соль окажется верной. Временного файла недостаточно для очистки / размазывания. Вам нужно будет сделать то же самое при слиянии и в случае бесконфликтного извлечения слияния правильной уже зашифрованной версии из git и использовать ее вместо повторного шифрования с новой случайной солью.
Иржи Клуда
Не уверен, что я понимаю, что вы говорите здесь; объединение будет происходить на простом тексте хранилищ (как это происходит посредством различий), и наличие секретов всегда помечается как конфликт даже для авто-слияний, таким образом, включая объединенные повторно зашифрованные секреты в любом коммите слияния, не будет действительно представляет проблему (для меня).
ᴳᵁᴵᴰᴼ
Можете ли вы быть конкретным по вопросам слияния? Вы должны предоставить воспроизводимый случай. Но я бы все же предложил поискать идеи в 3 упомянутых выше проектах. Что касается проблем слияния, когда вы объединяете контент A с контентом B, и вы все решили всегда брать A или всегда B, для систем контроля версий это особый случай, и они иногда делают это, связывая версию вместе. Git делает это с помощью хэша для содержимого, поэтому он будет предполагать, что хэш будет таким же, но если вы повторно зашифруете, даже если все содержимое - A, хэш не будет таким же. Но у вас может быть другая проблема
Иржи Клуда,