将网站的秘密值作为环境变量的好处是什么?


24

https://12factor.net/config上的devops指南建议将网站秘密(数据库密码,api密钥等)放入环境变量中。与使用版本控制忽略的文本文件(JSON,XML,YAML,INI或类似文件)相比,这有什么优点?

我发现复制带有机密的配置文件比处理.bash_profile和Webserver配置中的环境变量要容易得多。我想念什么吗?


1
从理论上讲,读取文件要比存储容易,因此您可以考虑将攻击面扩大而将复杂度降低。
FlorinAsăvoaie18年

我的开发人员的经验法则是,最好仅在类似docker的环境中将设置存储在环境变量中。在容器VM之外,他批准/更喜欢12factor.net的所有其他方面以及使用配置文件。我们谁都不喜欢常规服务器部署中环境变量的不安全特性。
科里·奥格本

Answers:


21

作者列出了他们的推理,尽管有些脱节。他们的主要论据是,很容易意外地检入配置文件,并且配置文件具有不同的格式,并且可能散布在系统中(对于安全性相关的配置,这三个参数充其量只是中等的参数,例如身份验证令牌和凭据)。

根据我自己的经验,您基本上可以选择以下三个选项,并具有各自的优点和缺点:

将数据存储在配置文件中。

采用这种方法时,最好将它们与存储库本身隔离开,并确保它们不在应用程序将其内容存储在其中的区域内。

好处:

  • 隔离和控制对访问的访问非常容易,尤其是当您使用SELinux或AppArmor之类的东西来提高整体系统安全性时。
  • 对于非技术用户来说,通常很容易更改(这对于已发布的软件是一个优点,但对于组织特定的软件则不一定)。
  • 易于跨大型服务器组进行管理。有各种各样的工具可以进行配置部署。
  • 相当容易地验证所使用的确切配置是什么。
  • 对于编写良好的应用程序,通常可以通过更新配置文件然后向应用程序发送特定信号(通常为SIGHUP)来更改配置而不会中断服务。

缺点:

  • 需要进行适当的计划以确保数据安全。
  • 您可能必须学习不同的格式(尽管这些天只需要担心一些,并且它们通常具有相似的语法)。
  • 确切的存储位置可能会在应用程序中进行硬编码,从而使部署可能会出现问题。
  • 解析配置文件可能会出现问题。

将数据存储在环境变量中。

通常,这是通过从启动脚本中获取环境变量和值的列表来完成的,但是在某些情况下,它可能只是在命令行中在程序名称之前声明了它们。

好处:

  • 与解析配置文件相比,在几乎所有编程语言中,从环境变量中提取值都是微不足道的。
  • 您不必担心意外发布配置。
  • 通过这种默默无闻的方式获得某种程度的安全性是因为这种做法并不常见,并且大多数入侵您应用程序的人都不会立即考虑查看环境变量。
  • 访问可以由应用程序本身控制(当它生成子进程时,它可以轻松地清理环境以删除敏感信息)。

缺点

  • 在大多数UNIX系统上,可以很容易地访问进程的环境变量。某些系统提供了缓解此问题的方法(例如LInux上的hidepidmount选项/proc),但默认情况下未启用它们,并且无法防范拥有该进程的用户的攻击。
  • 如果正确处理了上述安全问题,则可以轻松地看到正在使用的确切设置。
  • 您必须信任该应用程序在产生子进程时清理环境,否则它将泄漏信息。
  • 如果不重新启动应用程序,则无法轻松更改配置。

使用命令行参数来传递数据。

认真地,不惜一切代价避免这种情况,它不安全,维护起来很痛苦。

好处:

  • 比大多数语言中的环境变量更容易解析。
  • 子进程不会自动继承数据。
  • 提供了一种简单的方法来在开发应用程序时快速测试特定配置。

缺点:

  • 就像环境变量一样,在大多数系统上很容易读取另一个进程的命令行。
  • 更新配置非常繁琐。
  • 对配置的长度进行硬性限制(有时低至1024个字符)。

1
一个不重要的问题是无人值守(重新)引导服务器,而无需手动输入任何密码,最终它们位于磁盘上的某个位置
PlasmaHH

7
在大多数UNIX系统上,几乎不需要任何重要特权就可以读取几乎所有进程环境变量。 -您能对此进行扩展吗?/ proc / #### / environ文件仅可由所有者读取,因此您需要是root或具有sudo。
rrauenza

我认为这种env配置趋势也来自诸如docker之类的事情,您使用标准容器并通过将env变量传递给容器来对其进行配置。
rrauenza

除非您非常擅长按帐户隔离事物,否则,进程的所有权不是一个重要的特权,并且如果您不是所有者,则实际上只需要CAP_SYS_ADMIN功能(根隐式拥有)。另外,关于环境变量问题,您可能是对的,但是即使使用Docker,这也是边缘设计。
奥斯汀·海默加恩

3
我同意@rrauenza的观点。答案是很不错的,但是我想澄清一下,如何能够准确地读取几乎所有进程环境变量而又不需要任何重要特权。关于“ 并且您实际上只需要CAP_SYS_ADMIN功能(root隐式具有) ...”,如果恶意代理具有root特权,则进一步的讨论是多余的,并且CAP_SYS_ADMIN也可能是root特权(请参见man7.org/linux /man-pages/man7/capabilities.7.htmlCAP_SYS_ADMIN注意事项内核开发者
Nubarke

13

Web服务器的每个子进程都将继承环境变量。那就是连接到服务器的每个会话,以及由它们产生的每个程序。这些秘密将自动显示给所有这些过程。

如果您在文本文件中保留机密,则服务器进程必须读取它们,因此每个子进程也可能读取它们。但是至少程序必须去找到它们;它们不会自动提供。您也许还可以使某些子进程在不同的帐户下运行,并使机密仅由那些帐户可读。例如,suEXEC在Apache中执行此操作。


1
“这就是连接到服务器的每个会话”是一种误导性陈述。您无法打开服务器的http会话并访问其环境变量,也不能登录该服务器上的Shell并获取它们,除非您具有root访问权或拥有Web服务器进程。
Segfault

Web服务器产生的每个进程都将继承其环境,除非您采取其他措施。HTML页面不具备使用该信息的功能,但是脚本具有。
安德鲁·舒尔曼

虽然是正确的,这个答案可能有一些修正/让步做,特别是有关术语的会话。初读时,似乎很难用环境变量来暗示向外部客户公开信息的可能性。另外,可以对env-vars进行有限的设置,从而获得与suexec相当的让步,例如,设置每个进程的env-vars(a la MYVAR=foo /path/to/some/executable)将传播限制到一个进程,并且仅限于其子进程-并且在需要的主守护程序可以擦洗/重置/修改的地方子进程的环境。
shalomb

2

即使在环境变量或文件方面需要进行一些与安全性相关的折衷,我也不认为安全性是此建议的主要推动力。还记得12factor.net的作者还是Heroku PaaS的开发人员吗?让每个人都使用环境变量可能会大大简化他们的开发。不同的配置文件格式和位置种类繁多,因此很难完全支持它们。环境变量很容易比较。

猜测一些对话并不需要太多的想象力。

开发人员A:“啊,这个秘密的配置文件UI太混乱了!我们真的需要下拉列表在json,xml和csv之间切换吗?”

开发人员B:“哦,如果只有每个人都为应用程序配置使用环境变量,生活将会如此美好。”

开发人员A:“实际上,这样做有一些与安全性相关的理由。环境变量可能不会被意外检查到源代码管理中。”

开发人员B:“您不是使用启动守护程序的脚本或配置文件来设置环境变量吗?”

开发人员A:“不在Heroku中!我们将让他们在用户界面中键入它们。”

开发人员B:“哦,我的12factor.net域名警报刚响了。” 1个


1:来源:组成。


1

TL; DR

使用环境变量而不是配置文件的原因很多,但是最容易忽略的两个原因是带外配置的实用价值以及服务器,应用程序或组织角色之间的增强隔离。我没有给出所有可能原因的详尽列表,而是在回答中仅涉及了这两个主题,并轻轻地涉及了它们的安全性。

带外配置:将秘密与源代码分开

如果将所有机密存储在配置文件中,则必须将这些机密分发到每个服务器。这意味着将机密信息与代码一起检查到修订控制中,或者具有完全独立的机密信息库或机密分发机制。

加密您的秘密并不能真正解决问题。所有要做的就是将这个问题一举解决,因为现在您也必须担心密钥管理和分发!

简而言之,当您要将开发与操作分开时,环境变量是一种将每个服务器或每个应用程序数据移出源代码的方法。如果您已发布源代码,这尤其重要!

增强分隔:服务器,应用程序和角色

虽然您当然可以有一个配置文件来保存您的机密,但是如果您将机密存储在源代码中,则会遇到特殊性问题。对于每组秘密,您是否有单独的分支或存储库?您如何确保正确的机密集到达正确的服务器?还是通过使“秘密”在任何地方都是相同的(如果在一个文件中都具有可读性,则到处都是可读的)来降低安全性,从而在任何一个系统的安全控制失败时构成更大的风险?

如果要在每个服务器或每个应用程序上拥有唯一的机密,则环境变量消除了必须管理多个文件的问题。如果添加新的服务器,应用程序或角色,则不必创建新文件或更新旧文件:您只需更新相关系统的环境即可。

安全分手思想

尽管对内核/内存/文件安全性的彻底探讨超出了此答案的范围,但值得指出的是,正确实现的每个系统环境变量的安全性不亚于“加密”机密。无论哪种情况,目标系统仍必须在某个时候将解密的机密保存在内存中才能使用它。

还值得指出的是,当值存储在给定节点上的易失性内存中时,没有磁盘上的文件可以复制和脱机攻击。通常认为这对内存中的秘密是有好处的,但是肯定不是决定性的。

与其他机密管理技术相比,环境变量的问题实际上更多地是关于安全性和可用性的权衡,而不是绝对值。你的旅费可能会改变。


2
这并不令人信服,因为您提到的配置文件的所有缺点也适用于环境变量。环境变量配置数据。他们没有神奇地设置自己。必须将它们分发到每个系统,并且必须使用某种配置机制来设置它们。
jpaugh

@jpaugh您在说一个稻草人,并且在攻击我从未说过的话。我要解决的问题是带外配置和数据分离。正如清楚说明的那样,您可以按照自己喜欢的任何方式来做这些事情。如果愿意,可以将您的秘密与代码一起公开发布在GitHub上,但这在一般情况下当然是不明智的。但是,只有可以确定权衡必要系统给定的威胁模型中正常运行。
CodeGnome

2
您的所有观点都是正确的,除了它适用于环境变量以及适用于任何其他配置数据一样。如果将环境变量存储在文件中,则可以提交它们。并且如果您将它们带外发送,那么在文件中进行处理比通过键入它们要容易得多。但是,如果您喜欢键入它们,为什么不键入一个JSON对象,然后在stdin上读取它呢?这实际上比命令行更安全。
jpaugh

1

就个人而言,我不建议设置环境变量,.bashrc因为它们对于外壳程序启动的所有进程都是可见的,而是将其设置为守护程序/主管级别(init / rc脚本,systemd config),以便将它们的范围限制在需要的地方。

在由单独的团队管理操作的地方,环境变量为操作提供了一个简单的界面,以便为应用程序设置环境,而不必了解配置文件/格式和/或诉诸于其内容的处理。在多语言/多框架设置中,尤其如此,运营团队可以根据运营需求(部署简便性,可伸缩性,安全性等)选择部署系统(操作系统,主管流程)。

另一个考虑因素是CI / CD管道-代码在不同的环境中运行(即开发,测试/质量保证,分段,生产)环境细节(部署区域,数据库连接细节,凭据,IP地址,域名等)最好由专用的配置管理工具/框架进行设置,并由应用程序使用环境中的进程(在DRY中,一次写入,以任何方式运行)。传统上,开发人员倾向于管理这些运营问题,他们倾向于签入除代码之外的配置文件或模板-然后当运营需求发生变化(例如出现新的环境/部署/站点,可伸缩性/安全性)时最终会增加变通方法和其他复杂性称量体重,

  • Env-vars简化了规模的配置/复杂性。
  • Env-vars将操作配置与负责应用程序中与代码无关的方面的团队以统一的(如果不是标准的)非约束性方式统一放置。
  • Env-vars支持换出支持应用程序的主/监督进程(例如,神,监视,监督,sysvinit,systemd等),甚至还可以将部署系统(操作系统,容器映像等)作为操作需求演变/变化。尽管当今的每个语言框架都有某种类型的流程运行时,但它们在操作上往往较差,更适合开发环境和/或增加了多语言/多框架生产环境中的复杂性。

对于生产,我赞成设置应用程序ENV-瓦尔在EnvironmentFile/etc/default/myapplication.conf由配置管理部署,并只能通过设置读取root,使得systemd(或任何其他为此事)可以生成一个专用下的应用非特权系统用户私有组。用专用的用户群为后盾opssudo-这些文件不可读由世界默认。这是12因子兼容标准,支持Dev + Ops的所有优点,并具有体面安全性的所有优点,同时仍允许开发人员/测试人员在dev / qa / test环境中放入自己的EnvironmentFiles。


0

从开发人员的角度来看,将配置数据存储在环境变量中可简化在不同环境(开发,QA和生产)之间的部署,并使开发人员不必担心部署错误的配置文件。

Azure Web应用程序提供了使用此模式的选项,并且效果很好。

除此之外,它将潜在的敏感数据置于源代码控制之外。从源代码管理中忽略这些文件实际上是不可行的(至少在.NET中是这样),因为这些文件中还存在许多必需的样板配置。

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.