代码之家  ›  专栏  ›  技术社区  ›  philfreo

服务器/数据库配置文件(包括密码)是否应存储在源代码管理中?

  •  50
  • philfreo  · 技术社区  · 15 年前

    我想听听一些最佳实践。。。

    假设一个web应用程序与几个不同的生产服务器(数据库等)交互。。。是否应将包含数据库密码的配置文件存储在源代码管理中(例如git、svn)?

    如果不是,那么跟踪应用程序需要访问的服务器数据库(或其他相关)密码的最佳方法是什么?

    编辑: 增加了一笔奖金以鼓励更多的讨论,并听取更多人认为最佳做法是什么。

    12 回复  |  直到 15 年前
        1
  •  27
  •   GreyCat    15 年前

    这里没有一个“银弹”答案,这将在很大程度上取决于细节。

    首先,我考虑将所有源代码和配置分离到单独存储库中的最佳实践。所以,源代码仍然是源代码,但它的安装或部署(配置、密码等)是另一回事。这样,您就可以将开发人员的任务与系统管理员的任务牢牢地分开,并最终可以构建两个不同的团队来完成他们擅长的工作。

    当您拥有单独的源代码存储库+部署存储库时,下一个最佳选择是考虑部署选项。我在这里看到的最好的方法是使用针对所选操作系统的典型部署过程(即,像操作系统维护人员那样为所选操作系统构建自治包)。

    例如,Red Hat或Debian打包过程通常意味着从外部站点(即从源代码VCS导出源代码)获取软件tarball,对其进行解包,编译并准备好准备部署的包。理想情况下,部署本身应该意味着只需执行一个安装软件包的快速简单命令,例如 rpm -U package.rpm , dpkg --install package.deb apt-get dist-upgrade (假设您构建的包进入apt-get能够找到它们的存储库)。

    显然,要使它以这种方式工作,您必须为处于完全工作状态的系统的所有组件提供所有配置文件,包括所有地址和凭据。

    为了更简洁,让我们考虑一个典型的“小服务”情况:一个部署在 n个 运行apache/mod_php的应用服务器,访问 MySQL服务器。所有这些服务器(或虚拟容器,其实并不重要)都位于受保护的专用网络中。为了简化这个例子,我们假设所有真正的internet连接都是由 HTTP加速器/反向代理(如NGNX/LaTTDP/APACHE),它们具有非常简单的配置(只是内部的IPS转发)。

    我们有什么可以让他们相互联系并充分发挥作用?

    • MySQL服务器:设置IP/主机名、设置数据库、提供登录和密码
    • PHP应用程序:设置IPs/hostnames,创建包含MySQL服务器IPs、登录名、密码和数据库的配置文件

    注意,这里有两种不同的“类型”信息:IPs/hostnames是固定的,您可能希望一次性地分配它们。另一方面,登录和密码(甚至数据库名称)纯粹是为了连接,以确保MySQL是我们的PHP应用程序连接到它。所以,我的建议是将这两种“类型”分开:

    • “永久”信息(如IP)应存储在某些VCS中(不同于源代码VCS)
    • “暂时”信息(如两个应用程序之间的密码)不应存储,而应在生成部署包期间生成。

    最后一个也是最棘手的问题仍然是:如何创建部署包?有多种技术可用,主要有两种方法:

    • 从VCS1导出源代码+从VCS2导出“永久”配置+从VCS3生成脚本=包
    • 源代码在VCS1中;VCS2是一个分布式版本控制(如git或hg),它本质上包含VCS1的“分叉”+配置信息+可以生成的构建脚本。我个人更喜欢这种方法,它要短得多,而且最终更容易使用,但是学习曲线可能要陡一些,特别是对于那些必须掌握git或hg的管理员来说。

    对于上面的示例,我将创建如下包:

    • my-application-php -这将取决于mod_php、apache,并将包括生成的如下文件 /etc/my-php-application/config.inc.php 其中包括MySQL数据库IPs/hostnames和作为 md5(current source code revision + salt) . 此软件包将安装在 n个 应用服务器。理想情况下,它应该能够安装在一个干净安装的操作系统上,并使一个完全工作的应用程序群集节点无需任何手动操作。
    • my-application-mysql -这将取决于MySQL服务器,并将包括安装后脚本:
      • 启动MySQL服务器并确保它在操作系统启动时自动启动
      • 连接到MySQL服务器
      • 检查是否需要数据库存在
      • 如果否-创建数据库,则用内容引导数据库并用密码创建登录(与在 /etc/my php应用程序/config.inc.php ,使用md5算法)
      • 如果是-连接到数据库,应用迁移将其升级到新版本,终止所有旧登录名/密码并重新创建新的登录名/密码对(同样,使用md5(revision+salt)方法生成)

    最终,它将带来使用如下命令升级部署的好处 generate-packages && ssh-all apt-get dist-upgrade . 此外,您不会在任何地方存储应用程序间的密码,而且每次更新时都会重新生成这些密码。

    这个相当简单的例子说明了很多你可以在这里使用的方法——但是,最终,由你来决定哪一种解决方案更好,哪一种解决方案过多。如果你把更多的细节放在这里或作为一个单独的问题,我会很高兴地尝试进入细节。

        2
  •  18
  •   paxdiablo    12 年前

    撇开密码不应以纯文本存储这一点不谈 在任何地方 (除了只有CEO、CFO和CIO才能使用的头盖骨或上锁的金库(同时需要所有三把钥匙)),您应该将所有内容存储到源代码管理中,这需要 建造 你的产品。

    这不仅意味着你的源代码,甚至是构建机器的规范,编译器选项,编译器本身等等。

    如果我们能找到检查物理硬件的方法,我们也会这样做的:-)

    可以由构建过程本身复制的所有内容,或者 跑步 而不是建立软件(如您的密码)通常不属于源代码管理,但一些商店会这样做,为他们的可执行文件,生成的文档等,只是为了他们可以迅速得到一个特定的版本,安装。

        3
  •  11
  •   Richard Harrison    15 年前

    密码不应存储在源代码管理中。完全。永远。见 How to keep secrets secret

    密码、服务器名等是由服务器管理员执行的部署配置的一部分。必须记录本程序,并将记录的程序置于控制之下。

    除了服务器配置之外,其他一切 必须 进行源头控制。

    在源代码管理中存储服务器配置通常是一个坏主意,因为它会妨碍部署,并可能导致小的灾难(例如,当某人没有意识到从源代码管理部署的测试版本正在与实时服务通信时)。

    始终将这些配置文件保存在webroot之外。

    可信连接可能是一个选项,允许已知的IP地址通过该服务的配置连接到服务。。

        4
  •  7
  •   Marnix van Valen    15 年前

    总的来说,我同意paxdiablo:尽可能地将所有内容置于源代码控制之下。其中包括具有数据库凭据的生产配置文件。

    想想你的服务器崩溃的情况,备份结果很糟糕,你需要备份服务器。我想你和你的客户(或老板)肯定会同意,在源代码管理中部署站点所需的一切都是一个很大的好处。

    如果要使用连续集成(另一个最佳实践)从源代码构建易于部署的包,则必须将配置文件置于源代码管理下。

    另外,在大多数情况下,具有源代码管理访问权限的开发人员无法直接访问生产数据库服务器。生产密码对他们毫无用处。

    如果错误的人访问了您的源,他们仍然需要访问生产服务器,以便对密码造成危害。因此,如果您的生产环境得到了适当的保护,那么源代码管理中密码的安全风险是非常有限的。

        5
  •  3
  •   8DH    15 年前

    我认为这个问题更多的是关于信息所有权、信任和组织。你应该扪心自问,你相信你组织的哪一部分会保护你的系统密码不被泄露和滥用?

    我曾在一些机构工作,由负责这项业务的人保管。在其他情况下,它们被委托给运营团队,运营团队还拥有围绕创建和使用等的流程。

    最重要的是,在您的组织中明确定义了谁应该有权访问系统密码。之后,您可以决定适当的技术解决方案来保护密码。

        6
  •  1
  •   Jinesh Parekh    15 年前

    不可以。生产密码应该直接在服务器上配置。您应该为部署团队/人员创建部署说明,以便在部署期间更改正确的属性文件。

        7
  •  1
  •   Linus Kleen    15 年前

    在我的Subversion repos for PHP中,包含密码的配置文件作为 config.php.sample 提示必须提供什么,脚本依赖需要 config.php 出现在同一地点。

    存储库配置为忽略 配置.php 以避免“意外”添加或签入。

        8
  •  1
  •   user502515    15 年前

    示例配置文件,当然,我会将它们置于版本控制之下。但通常不与现实世界访问数据,如服务器地址或密码。更像是

    # program.conf
    #
    # mysql option for $myprog.
    #
    #SERVER_ADDR=127.0.0.1
    #SERVER_USER=mysql
    #SERVER_PASSWD=abcdef
    
        9
  •  1
  •   snakehiss    15 年前

    源代码中的密码问题:

    • 很难从一个部署到另一个部署(我不想在生产中修改源代码)
    • 开发时意外损坏生产数据库的可能性增加
    • 安全问题(在大多数商店中,代码/开发人员没有理由知道prod密码)
    • 更改的密码需要重新部署

    我发现最有效的方法是签入一个配置,该配置对特定于部署的数据使用混合的sane默认值和占位符。我们的应用程序总是寻找一个允许重写任何变量的系统配置。这允许生产机器具有适合其部署的配置。

    注意:当我作为管理员工作时,我总是将配置与代码分开管理(有充分的理由)。

        10
  •  0
  •   Matthew Morek    15 年前

    我总是排除包含密码或其他访问详细信息的重要配置文件(如数据库),这纯粹是最佳实践。除此之外,源代码和版本控制通常为多个用户提供服务,并且并非所有用户都使用相同的数据库详细信息,甚至使用相同的服务器配置(域等),为此,配置文件应该从整个版本中排除。

        11
  •  0
  •   Steve Clay    14 年前

    如果没有正确的构建过程,我将使用此策略(对于PHP应用程序):

    1. 创建文件夹 /etc/companyname
    2. 在其中,放置两个文件:

      <?php // env.php
      return 'prod'; 
      
      <?php // appname-prod.php
      return array(
        'db' => array( /* credentials */ ),
        /* other host-specific conf data */
      ); 
      
    3. 使两个文件只能由PHP进程读取

    现在你的应用程序的配置文件如下:

    <?php // config.php
    $env = (require "/etc/companyname/env.php");
    $creds = (require "/etc/companyname/appname-{$env}.php");
    

    使用此选项,环境将定义所使用的凭据,您可以在预先配置的环境之间移动代码(并使用 $env ). 当然,这可以通过服务器环境变量来实现,但是a)设置起来更简单,b)不会向服务器上的每个脚本公开凭据(不会出现在诸如 phpinfo() ).

    为了便于在PHP之外阅读,您可以将凭证文件设置为JSON或其他格式,并忍受微小的性能影响(APC不会缓存它们)。

        12
  •  0
  •   iman    12 年前

    我更喜欢吃 本地设置 主文件旁边的文件 设置 文件。这个 本地设置 不应该添加到存储库中,但我将添加 sample.local_设置 以显示此文件的结构。

    在运行时,如果存在LoalAll设置,其值将重写主设置文件的值。

    例如在python中:

    设置.py:

    log='error.log'
    db=lambda:None
    db.host='localhost'
    db.user=''
    db.password=''
    
    try:
        import local_settings
    except ImportError:
        pass
    

    本地设置.py:

    from settings import *
    
    db.user='abcd'
    db.password='1234'
    
    推荐文章