【问题标题】:How to keep secret key information out of Git repository如何将密钥信息保留在 Git 存储库之外
【发布时间】:2021-08-27 07:35:20
【问题描述】:

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

什么是保密的最佳方式,而不必每次我提交和推送某些内容时都将其空白?

【问题讨论】:

  • 根据您的用例,一种方法是从环境中读取密钥,而不是将其直接包含在文件中。这使配置与代码分开。 12factor.net 是一本好书。
  • 把你所有的文件/文件夹名放在 .gitIgnore 文件中。 Git不会推送这里提到的任何文件或文件夹,只能用于开发目的。
  • 勾选这个link来配置git ignore

标签: git secret-key


【解决方案1】:

根据您要达到的目标,您可以选择其中一种方法:

  • 将文件保留在由 git 管理的树中,但在 gitignore 中的条目中忽略它
  • 将文件内容保存在环境变量中,
  • 根本不要使用带密钥的文件,将密钥内容保存在其他地方(hashicorp 的保险库、数据库、云等外部系统(不确定,我不建议这样做)等)

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

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

【讨论】:

    【解决方案2】:

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

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

    • 在运行时“提供”这种信息并将其保存在其他地方:

      ./runMyApp.sh -db.password=

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

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

    【讨论】:

      【解决方案3】:

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

      对于像秘密密钥这样重要的东西,我会使用位于开发环境之外的专用密钥环基础设施,可选择与秘密密码相结合。

      除了这种情况,我个人为此使用 子模块。退房:

      git submodule
      

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

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

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

      这样做,无论您在哪里工作,您都可以获得版本控制系统的所有好处,同时仍确保您自己不会意外地将未存储在公共子模块中的内容推到外部。

      【讨论】:

        【解决方案4】:

        如果您没有太多秘密需要管理,并且您确实希望将这些秘密保留在版本控制中,我将父存储库设为私有。它包含 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。

        就我个人而言,这让我很紧张,用户错误仍有可能导致公开提交的秘密,因为这些文件仍在公共回购的根目录下,任何数量的事情都可能出错,这种方法可能会令人尴尬.

        【讨论】:

          【解决方案5】:

          对于 Django 添加另一个名为 secrets.py 或任何你想要的文件,以及另一个名为 .gitignore 的文件

          在 .gitignore 中输入 secrets.py

          将密钥粘贴到secrets.py 文件中,并通过使用将其导入到设置文件中

          from foldername.secrets import * 
          

          这对我有用。

          【讨论】:

            猜你喜欢
            • 2020-07-18
            • 1970-01-01
            • 2019-04-24
            • 1970-01-01
            • 2020-08-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-02-15
            相关资源
            最近更新 更多