存储应用程序配置的首选方法是什么?


38

大多数时候,我将开发应用程序配置存储在项目的根目录中,如下所示:

app
|-- config.json

但这似乎不是最佳方法,因为此配置最终存储在版本控制系统中-可能导致用户名,密码和其他敏感内容泄漏。

12 Factor App指南建议完全删除配置文件,并使用环境变量进行配置设置:

...将配置存储在环境变量中。Env var易于在部署之间进行更改,而无需更改任何代码。与配置文件不同,它们很少有可能被意外检入代码存储库;与自定义配置文件或其他配置机制(例如Java系统属性)不同,它们是与语言和操作系统无关的标准。

这对我来说听起来真的很不错,但是在没有将其检入源代码管理的情况下,该变量存储在哪里呢?我可以使用哪些工具将这些变量传递给应用程序?可能有数十种配置选项,每次启动应用程序时手动键入它们都不是一件好事-因此它们必须存储在某种文件中。这样,该文件将最终在源代码控制中,然后我们返回到开始的地方。

是否有一些公认的处理配置选项的方法,而没有将本地配置存储在源代码管理中的风险?


1
好吧,至少git有类似.gitignore我可以定义不应检查到版本控制中的文件或文件夹的地方。正如您所说的,我看不到Env var真正有帮助的地方,要么您有一个脚本来设置它们,并应将其与项目一起存储,要么它们在系统中的某个位置(主目录,甚至在机器启动时)脚本)似乎会自己带来很多问题,尤其是在需要大量配置的情况下。无论如何,我都会分割配置文件,以使机密信息进入不同的文件中。
thorstenmüller2015年

@thorstenmüller-.gitignore的唯一问题是仍必须存储基本/模板配置,这意味着应用程序必须读取两个配置-基本配置(具有默认选项(存储在scm中)和本地配置),可覆盖基本配置(和未存储在scm中)。使用env vars,我想大规模部署会更容易-为新的虚拟机设置指定环境变量比向某些非标准文件中写入内容更简单。
罗加奇(Rogach)2015年

很好的问题,在我开始为此使用常规的特定于用户的应用程序数据存储之后,生活变得更轻松了;-)
Wolf

1
您是否尝试过“ Redis” redis.io。它专门用于键值结构存储。
卡兰2015年

2
@jporcenaluk-我确实喜欢键值存储,但是在应用程序中添加完整的redis只是为了处理配置管理,感觉有些过头了。另一方面,也许我从未从事过足够大的项目。
Rogach

Answers:


16

对此可能没有一个好的答案。似乎您需要将这些数据存储在安全的地方,因为有一天将其用于灾难恢复。这同样适用于设置环境变量的属性文件和脚本。

  • 使用源代码(在SVN / GIT等中)是一个非常糟糕的主意,因为此数据将包含生产数据库密码等。
  • 公司的每夜备份可能就足够了,但是不太可能保留易于获取的变更历史记录。
  • 数据需要分别与使用软件进行版本控制。在我们当前的系统中,配置的更改导致了新应用程序的构建,这是完全错误的。

我们目前正在寻找解决该问题的方法,并且倾向于访问受限的代码存储库。该存储库将仅包含配置数据。别人有经验可以分享吗?


2
为一个项目拥有两个单独的存储库似乎不是一个好主意-您不能进行干净的回滚或使用分支,因为那样您就需要同时操作两个存储库(例如,另一个分支需要一些新的config选项,当您切换到该新分支,而无需同时切换配置存储库,事情会以奇怪的方式中断)。
罗加奇(Rogach)2015年

2
@罗加奇我明白你的意思。有充分的理由对代码进行一些配置,但是正如您在问题中所说的那样,敏感内容需要放在其他地方。因此,两个存储库似乎是不可避免的。另外,我没有提到应用服务器经常在这里提供帮助。数据源和JNDI变量可以由管理员设置,并且不会公开。
猕猴桃

第二家商店很有意义。可能还会有其他类型的数据(也属于机密数据)与配置一起存储(例如,正在分析生产数据以解决客户问题)。
沃尔夫

1
@Rogach他们似乎吸引了很多讨厌的人,但是我认为git子模块可以很好地解决这一问题-如果主要的子模块设置正确,并且受限访问的回购协议可能只存在于其中。
SeldomNeedy

9

在检查问题和可能的解决方案时,它有助于我使用Jeff Atwood流行的方法:如果上帝要创建一种存储敏感配置信息的方法,他将如何做?

好吧,他会知道谁需要配置信息并将其仅提供给那些人,其他人将永远无法访问该信息。

第一部分应该已经处理了:您的源代码控制系统应该对用户进行身份验证。根据Troy Hunt的《源代码管理的10条诫命》中的第10条,“依赖关系必须存在于源代码控制中” ,该方法也具有一定的有效性。

但是,如果泄漏,如何确保它的安全呢?好吧,它不需要以纯文本格式存储在那里!使用加密。在.NET中,您可以采取一些步骤来加密配置文件中的连接字符串数据。您将必须找到与选择的特定技术相同的方法。


3
只是想澄清一下-加密配置将如何提供帮助?据我了解,您将需要在所有开发人员之间共享相同的解密密码,这听起来像是在提问题。
罗加奇

如果公司外部的人可以访问您的存储库,则密码会被混淆。如果有人将文件从项目复制到USB驱动器,然后将其留在某处,那也是一样。当然,将需要做更多的工作。更高的安全性通常是以便利为代价的。这个解决方案有点笨拙,我给你。我愿意以更好的方式来解决OP的问题!
jporcenaluk 2015年

5

许多人批评将配置与您的源代码一起存储在常规文件中,但是根据我的经验,这实际上是一个很好的解决方案:

  • 易于以任何语言实施。在许多情况下,您可以立即获得对复杂配置文件的支持。例如,对于带有Spring Boot的Java,您将获得YAML支持,该支持可以表达任何树状结构,并且很容易拥有用于不同环境的单独配置文件以及可以从中继承特定环境文件的基准配置。
  • 运行您的软件需要进行配置,并且更改代码通常需要添加/修改配置设置,因此将配置和代码保持在一起是很自然的。
  • 将配置与源一起存储可为您提供源控制的所有好处,例如知道在常规代码检查期间谁修改了哪些设置以及何时或能够检查配置。
  • 除非您为中央情报局工作,否则我对安全性的论点似乎不屑一顾。因此,您的数据库密码存储在运行应用程序的计算机上的文件中。好吧,如果有人可以使用您的应用程序访问该计算机,则可能已经遇到了很多麻烦-他们可以例如关闭您的应用程序并在同一端口上的位置启动自己的应用程序。在这种情况下,访问数据库密码可能不是一个大问题。除非您的所有连接都经过完全加密,并且可以访问您的计算机,否则它们仍然可以从网络接口嗅探许多有趣的数据。
  • 您可以使用Hiera之类的工具来拥有文本配置文件,但不能在其中存储密码或其他敏感数据。

因此,在许多情况下,与代码一起存储在源代码控制中的文本配置是一个好的开始。

如果您正在使用分布式系统,或者希望能够在不重新部署应用程序的情况下热交换您的配置,则可能会发现更好的基于配置服务器的解决方案。Spring Cloud 支持这种机制,后端服务配置可以是git存储库或Eureka。您也可以使用Zookeeper滚动自己的游戏。这些方法中的任何一种都将使在许多服务器上管理一致的配置变得更容易,以更新配置,而无需重建和重新部署软件。这当然是有代价的,这是在学习配置服务器以及如何从应用程序以及另一个要部署和维护的系统中使用它。


但是代码会移交给那些不拥有配置文件秘密的人,这真是一团糟。
蒂姆·卢德温斯基

@TimLudwinski密钥/机密属于公司,而不是单个开发人员,因此,应以这样一种方式来维护它们:如果任何一个单独的人员离开,它们都不会丢失。例如,它们可能是问题,并由管理员/安全团队维护,因此有一个中央注册表。
米哈尔Kosmulski

5

在我工作的地方,我们正在同一个问题作斗争。现在,我们所有的配置都是基于文件的,并由使用它们的单个应用程序进行源代码控制。这将导致重复,并使开发人员可以访问生产/质量密码,而不仅仅是开发。

就是说,我认为我们已经提出了一个很好的解决方案。我们将配置文件移动到单独的git repo(标记为config repo)。然后,我们建立了一个spring-cloud-config(java)服务器,该服务器仅根据传递给它的配置文件为config存储库提供文件。这对于Java应用程序非常有用,它可以在启动时使用客户端并下载它们。对于我们的PHP /非Java应用程序,我们将直接下拉文件。(不理想)。将来,我们可能会编写一些内容,使PHP应用程序自己下载配置并将其缓存在某个位置,但是对于第一次运行而言,它并不是高优先级。我认为此解决方案是config-as-a-service,它并未明确违反12个因素的应用建议。

我相信zookeeper可以用于同一件事(我看到了kubernetes + zookeeper的安装程序),所以我不太确定为什么答案高于-1。

链接:

https://spring.io/guides/gs/centralized-configuration/

https://cloud.spring.io/spring-cloud-config/


3

与其将整个配置存储在一个文件中,不如将其存储在多个文件中。

  • 有一个配置目录。那里的所有文件都被解释为配置文件,可能除外README*
  • 所有文件名均按字母顺序排序,并按该顺序加载文件。这就是在这种情况下文件通常以一两位数字开头的原因01-logging.json02-database.json
  • 来自所有文件的数据都加载到应用程序可用的相同配置结构中。这样,几个文件可以相互补充设置,甚至以可预测的方式覆盖它们。
  • 仅将具有安全可见值或默认值的配置文件存储在VCS中。在部署期间添加带有机密的配置文件,或者最好使用经过身份验证的机密存储服务。

在离您最近的Linux机器上,查看/etc/sudoers.d/etc/nginx/conf.d。它显示了相同的模式。

秘密管理是另一回事。小型时,您可以手动进行管理。您可以使用Zookeeper之类的东西。您甚至可以将机密以加密形式签入VCS,然后将其解密作为部署步骤。存在许多其他选项。

(还有一个观点:JSON不是一种好的配置文件格式,因为它不允许注释;注释至关重要。TOML,YAML甚至INI格式在实际使用中更好。)


2

我认为您的选项在某种程度上由您要部署的操作系统定义

我建议,是的,将值放在源代码管理中。但是只有'dev'版本。您希望您的源代码能够编译和运行!不包括额外的秘密步骤

然后,您的构建和部署过程应在部署期间按环境交换这些值。(章鱼有这种模型)


0

Apache zookeeper提供了很棒的选项来存储分布式系统的应用程序配置。在动物园管理员处进行的更改可以通过在应用程序端具有策展人或动物园管理员侦听器来捕获和处理。


6
有什么选择?它是如何工作的?它存储在哪里?一个人比另一个人优先吗?每种选择有哪些优点和缺点?如何在不同的操作系统上进行交互?

3
@Gangz-我将对更详细的答案感兴趣,请不要因为投票不足而气,,并改善您的答案,这样可以有所帮助。
杰伊·埃尔斯顿
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.