如果您没有太多秘密需要管理,并且您确实希望将这些秘密保留在版本控制中,我将父存储库设为私有。它包含 2 个文件夹 - 一个 secrets 文件夹和一个用于公共存储库的 gitsubmodule(在另一个文件夹中)。我使用 ansible crypt 加密秘密文件夹中的任何内容,并使用 bash 脚本传递解密的内容,并将这些秘密加载为环境变量以确保秘密文件始终保持加密状态。
Ansible crypt 可以加密和解密一个环境变量,我将它包装在一个 bash 脚本中来执行这些功能,就像这样-
testsecret=$(echo 'this is a test secret' | ./scripts/ansible-encrypt.sh --vault-id $vault_key --encrypt)
result=$(./scripts/ansible-encrypt.sh --vault-id $vault_key --decrypt $testsecret)
echo $result
这里的testsecret是加密的base64结果,可以安全地存储在文本文件中。稍后您可以获取该文件以将加密结果保存在内存中,最后当您需要使用秘密时,您可以解密它./scripts/ansible-encrypt.sh --vault-id $vault_key --decrypt $testsecret
上面引用的这个 bash 脚本在下面(ansible-encrypt.sh)。它以一种可以将加密变量存储在 base64 中的方式包装 ansible crypt 函数,从而解决了编码可能出现的一些问题。
#!/bin/bash
# This scripts encrypts an input hidden from the shell and base 64 encodes it so it can be stored as an environment variable
# Optionally can also decrypt an environment variable
vault_id_func () {
if [[ "$verbose" == true ]]; then
echo "Parsing vault_id_func option: '--${opt}', value: '${val}'" >&2;
fi
vault_key="${val}"
}
secret_name=secret
secret_name_func () {
if [[ "$verbose" == true ]]; then
echo "Parsing secret_name option: '--${opt}', value: '${val}'" >&2;
fi
secret_name="${val}"
}
decrypt=false
decrypt_func () {
if [[ "$verbose" == true ]]; then
echo "Parsing secret_name option: '--${opt}', value: '${val}'" >&2;
fi
decrypt=true
encrypted_secret="${val}"
}
IFS='
'
optspec=":hv-:t:"
encrypt=false
parse_opts () {
local OPTIND
OPTIND=0
while getopts "$optspec" optchar; do
case "${optchar}" in
-)
case "${OPTARG}" in
vault-id)
val="${!OPTIND}"; OPTIND=$(( $OPTIND + 1 ))
opt="${OPTARG}"
vault_id_func
;;
vault-id=*)
val=${OPTARG#*=}
opt=${OPTARG%=$val}
vault_id_func
;;
secret-name)
val="${!OPTIND}"; OPTIND=$(( $OPTIND + 1 ))
opt="${OPTARG}"
secret_name_func
;;
secret-name=*)
val=${OPTARG#*=}
opt=${OPTARG%=$val}
secret_name_func
;;
decrypt)
val="${!OPTIND}"; OPTIND=$(( $OPTIND + 1 ))
opt="${OPTARG}"
decrypt_func
;;
decrypt=*)
val=${OPTARG#*=}
opt=${OPTARG%=$val}
decrypt_func
;;
encrypt)
encrypt=true
;;
*)
if [ "$OPTERR" = 1 ] && [ "${optspec:0:1}" != ":" ]; then
echo "Unknown option --${OPTARG}" >&2
fi
;;
esac;;
h)
help
;;
*)
if [ "$OPTERR" != 1 ] || [ "${optspec:0:1}" = ":" ]; then
echo "Non-option argument: '-${OPTARG}'" >&2
fi
;;
esac
done
}
parse_opts "$@"
if [[ "$encrypt" = true ]]; then
read -s -p "Enter the string to encrypt: `echo $'\n> '`";
secret=$(echo -n "$REPLY" | ansible-vault encrypt_string --vault-id $vault_key --stdin-name $secret_name | base64 -w 0)
unset REPLY
echo $secret
elif [[ "$decrypt" = true ]]; then
result=$(echo $encrypted_secret | base64 -d | /snap/bin/yq r - "$secret_name" | ansible-vault decrypt --vault-id $vault_key)
echo $result
else
# if no arg is passed to encrypt or decrypt, then we a ssume the function will decrypt the firehawksecret env var
encrypted_secret="${firehawksecret}"
result=$(echo $encrypted_secret | base64 -d | /snap/bin/yq r - "$secret_name" | ansible-vault decrypt --vault-id $vault_key)
echo $result
fi
将加密值存储为环境变量比解密静止的内容并将明文结果留在内存中要安全得多。这对于任何进程来说都非常容易被虹吸掉。
如果您只想与他人共享代码而不是秘密,您可以为父私有 repo 结构使用 git 模板,以便其他人可以继承该结构,但使用他们自己的秘密。这也允许 CI 获取您测试所需的一切。
或者,如果您不希望版本控制中的秘密,您可以简单地在包含您的秘密的包含文件夹上使用 git ignore。
就我个人而言,这让我很紧张,用户错误仍有可能导致公开提交的秘密,因为这些文件仍在公共回购的根目录下,任何数量的事情都可能出错,这种方法可能会令人尴尬.