如何将密钥信息保存在Git仓库之外

5

我在我的存储库中有一些文件,其中一个包含Adafruit秘钥。我想使用Git来存储我的存储库,但是我不想发布这个秘钥。

有什么最好的方法可以保密,而不必每次提交和推送时都将其清空?


根据你的使用情况,一种方法是从环境中读取秘钥而不是直接包含在文件中。这样可以将配置与代码分离。https://12factor.net/ 是一个很好的阅读材料。 - Ian Kenney
在.gitIgnore文件中放置所有的文件/文件夹名称。Git不会推送任何在此处提及的文件或文件夹,而且只能用于开发目的。 - Pramod Patil
请查看此链接以配置Git忽略文件。 - Pramod Patil
5个回答

6
根据您想要实现的目标,您可以选择以下方法之一:
  • 将文件保留在由git管理的树中,但使用gitignore条目忽略它
  • 将文件内容保存在环境变量中
  • 根本不使用具有密钥的文件,将密钥内容保存在其他地方(外部系统,如hashicorp的vault、数据库、云(不确定,不建议),等等)
第一种方法很容易且不需要太多工作,但您仍然需要解决如何在不泄露密钥的情况下将其传递到使用同一存储库的其他位置。第二种方法需要稍微更多的工作,并且与第一种方法具有相同的缺点。
第三种方法肯定比第一种和第二种方法需要更多的工作,但可能会导致一个真正安全的设置。

3
这在很大程度上取决于项目的要求。
从安全角度来看,最好的策略是不要在源代码控制系统中存储密钥、密码或任何易受攻击的信息。如果这是目标,有许多不同的方法:
- 在运行时“提供”此类信息并将其保留在其他地方:./runMyApp.sh -db.password= - 使用专门的工具(例如Hashicorp的Vault)管理机密信息 - 离线编码秘密值并将编码后的值存储在git中。没有用于解码的秘密密钥,单独使用此编码值是无用的。在运行时再次解码该值,使用某种共享密钥基础设施/非对称密钥对,在这种情况下,您可以使用公钥进行编码,私钥进行解码

1
我想使用Git来存储我的代码库,但我不想公开密钥。
对于像密钥这样关键的东西,我会使用位于开发环境之外的专用密钥管理基础设施,可选择与秘密密码短语配对使用。
除此之外,我个人使用子模块来处理这个问题。请查看:
git submodule

特别地,我声明了一个全局的Git仓库,其中我又声明了另一个Git仓库,该仓库将包含实际要公开的项目。这使我们能够在顶层存储与给定项目相关但不强制相关且不需发布的所有内容。例如,我的所有草稿、自动化脚本、工作笔记、项目规范、测试、缺陷报告等。
在所有提供的优势中,我们可以强调这个设施提供的事实,即您可以将已经存在的仓库声明为子模块,该仓库位于父仓库内部或外部。
而且,这种方式真正有趣的是,主仓库和子模块仍然是独立的Git仓库,仍然可以独立配置。这意味着您不需要配置父仓库的远程服务器。
通过这种方式,您无论在哪里工作都可以获得版本控制系统的所有好处,同时确保您永远不会意外地推送超出未存储在公共子模块内的内容。

1
如果你没有太多需要管理的机密信息,但是又想将这些机密信息保存在版本控制中,可以将父仓库设为私有。它包含两个文件夹——一个机密文件夹和一个公共仓库的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

将加密值存储为环境变量比在静态状态下解密并将明文结果留存在内存中更加安全。这对于任何进程来说都非常容易被窃取。
如果您只希望与他人共享代码而不是秘密,可以使用git模板作为父私有repo结构,以便其他人可以继承该结构,但使用自己的秘密。这也允许CI获取您测试所需的所有内容。
或者,如果您不希望将秘密放入版本控制中,可以简单地在包含秘密的文件夹上使用git ignore。
就个人而言,这让我感到紧张,因为用户错误仍可能导致公开提交的秘密,由于这些文件仍在公共repo的根目录下,因此可能会出现任何尴尬的问题。

0
对于Django,添加另一个名为secrets.py或其他任何名称的文件,以及另一个名为.gitignore的文件。
在.gitignore中输入secrets.py。
将密钥粘贴到secrets.py文件中,并通过使用以下方式在设置文件中导入它:
from foldername.secrets import * 

这对我有用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接