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

时间:2018-09-12 10:54:39

标签: git secret-key

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

什么是最好的保密方法,而不必每次我提交并推送内容时都将其清除?

4 个答案:

答案 0 :(得分:3)

根据要实现的目标,可以选择以下方法之一:

  • 将文件保留在git管理的树中,但在gitignore中输入则忽略它
  • 将文件内容保留在环境变量中,
  • 根本不使用带有密钥的文件,将密钥内容保留在其他位置(诸如hashicorp的保管库,数据库,云等外部系统(如果不建议,则不建议这样做)等)

第一种方法很简单,不需要很多工作,但是仍然存在将密钥传递到以安全方式使用同一存储库的不同位置的问题。第二种方法需要更多的工作,与第一种方法有相同的缺点。

第三项肯定比第一项和第二项需要更多的工作,但可能会导致设置真正安全。

答案 1 :(得分:2)

这在很大程度上取决于项目的需求

基本上,最好的安全策略是不要在源代码控制系统中存储密钥,密码以及一般而言任何易受攻击的信息。如果达到目标,则有许多不同的方法:

  • 在运行时中“提供”此类信息,并将其保存在其他位置:

      
        

    ./ runMyApp.sh -db.password =

      
  • 使用专用工具(例如Vault by Hashicorp)来管理机密

  • 离线加密秘密值,并将加密后的值存储在git中。如果没有用于解码的密钥,则仅此编码值是无用的。在运行时使用某种共享密钥(红外线/非对称密钥对)再次解码该值,在这种情况下,您可以使用公共密钥进行编码,使用私钥进行解码

答案 2 :(得分:1)

  

我想使用Git来存储我的存储库,但是我不想发布密钥。

对于像秘密密钥一样重要的事情,我将使用位于开发环境外部的专用密钥环基础结构,还可以选择与秘密密码相结合。

除了这种情况,我个人使用子模块。检出:

git submodule

尤其是,我声明了一个全局Git存储库,在其中依次声明了另一个Git存储库,其中包含将公开的实际项目。这使我们能够在顶层存储与给定项目相关的所有内容,但不强制与之相关且不公开的所有内容。例如,这可能是我的所有草稿,自动化脚本,工作说明,项目规范,测试,错误报告等。

在此功能提供的所有优点中,我们可以强调一个事实,您可以将一个已经存在的存储库声明为子模块,该存储库位于父存储库的内部或外部。

真正有趣的是,主存储库和子模块仍然是不同的Git存储库,仍然可以独立配置。这意味着您不需要父存储库来配置其远程服务器。

通过这种方式,无论您在哪里工作,都可以获得版本控制系统的所有好处,同时仍可确保自己绝不会意外将未存储在公共子模块中的内容推送出去。

答案 3 :(得分:1)

如果您没有太多要管理的秘密,并且您确实希望将这些秘密保留在版本控制中,那么我会将父存储库设为私有。它包含2个文件夹-一个secrets文件夹和一个公共存储库的gitsubmodule(在另一个文件夹中)。我使用ansible crypt对secrets文件夹中的所有内容进行加密,并使用bash脚本传递解密后的内容,并将这些密钥作为环境变量加载,以确保secret文件始终保持加密状态。

Ansible地穴可以对环境变量进行加密和解密,我将其包装在bash脚本中以执行类似so-

的功能
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中的方式包装ans 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模板用于父级私有存储库结构,以便其他人可以继承该结构,但可以使用自己的秘密。这也使CI可以提取测试所需的一切。

或者,如果您不希望秘密包含在版本控制中,则可以在包含该秘密的包含文件夹中简单地使用gitignore。

就个人而言,这让我感到紧张,由于用户错误仍然可能导致公开提交的机密,因为这些文件仍处于公共存储库的根源下,因此许多事情可能出错,使这种方法感到尴尬