我读过有关开发 Web 应用程序的当前最佳实践(例如十二因素指南),存储配置数据的推荐方法是环境变量。这与将它们保存在配置文件中形成鲜明对比,因为这些配置文件经常被意外签入项目的存储库,破坏“代码/配置”分离,并可能暴露秘密(例如 API 密钥、盐等)。
然而,我还没有看到解决的是防止意外暴露的问题。使用配置文件时,可以相应地设置文件权限,防止除特定用户之外的任何人读取秘密配置。但是 Unix 系统似乎没有为进程的环境变量提供这样的保护——即使该进程是由不同的用户启动的:
$ sudo -u root x=5 sleep 30
$ ps au -E | grep sleep # in different terminal
root 53814 s003 S+ 0:00.01 sudo -u root x=5 sleep 30
如果x
变量包含敏感数据,则只需以任何用户(不一定是 root 或启动我们想要窥探的进程的用户)登录访问计算机即可读取它。因此,这种配置方法似乎比配置文件更不安全(从深度防御 PoV 来看;显然,应该保护机器免受未经授权的访问)——除非我们能够以某种方式保护环境变量。
因此我的问题是:有没有办法阻止同一 Unix 系统上的其他用户看到进程的环境变量(通过ps a -E
和任何其他可能的方式)?
答案1
首先,好问题!
该-E
开关仅显示进程启动时的环境,因此任何更改对此方法都是不可见的。因此,如果在启动进程后将数据加载到环境中,则将无法通过此方法发现它。然而,恕我直言,这可能不是一个可行的策略,原因如下所述。
我同意十二因素,即环境变量技巧是可行的方法。然而,《十二要素》指南中没有明确说明一些重要的注意事项,以及实现这一目标的一些实际考虑因素和技巧。
首先,环境变量是易失性的(非持久性的)。重新启动后所有数据都会丢失。这意味着如果配置不是如果它持续存在某处,则在服务器重新启动时它将无法恢复,除非它位于/dev/brain0
系统管理员的内存中(我不会用 128 位密钥进行赌博)。如果这是服务器的私钥,那么您的手上最好的情况是一个重大问题,最坏的情况下是一个灾难性的问题(您的 CA 可能需要重新颁发密钥)。这是一个很好的例子,配置必须写在某个地方,我认为很多人不会对此提出异议。然而,重要的是在哪里/如何存储它。
十二因素应用程序解决了这个问题,尽管不是以直接的方式。 “检验应用程序是否已从代码中正确提取所有配置的试金石是代码库是否可以随时开源,而不损害任何凭据。”所以我们知道我们必须把它写下来某处,并且我们不能将配置放入代码库中。 “另一种配置方法是使用未签入版本控制的配置文件。”这就是我要做的。
十二因素应用程序说,“很容易错误地将配置文件签入存储库。”为了解决这个问题,生产配置(如私钥)应该与开发和测试配置不同。他们也应该是严格地受控。某些版本控制系统git
有黑名单(如.gitignore
文件),可以防止签入某些文件。这些也应该被使用。 “配置文件往往分散在不同的地方并采用不同的格式,这使得很难在一个地方查看和管理所有配置。此外,这些格式往往是特定于语言或框架的。”只需在配置文件中定义“环境变量”即可解决此问题。然后,服务器可以在启动时将其加载到环境中。
我会做什么:
- 将生产服务器配置信息(例如服务器的私钥)存储在与主存储库不同且不同的单独存储库中
- 很好地保护生产配置文件。只有少数人需要访问它,而不是团队中的每个开发人员。例如,QA/DevOps/系统管理员/等。将此文件视为服务器的密钥,因为它们可能就在其中。开发和测试环境应具有与生产环境不同的凭据和密钥。然后可以更松散地存储这些
- 让服务器的 init 例程将配置文件信息加载到实时环境变量中
- 让应用程序在运行时从环境变量加载所需的配置信息