Docker容器

Docker端口:你真的公开了哪些东西?

本文主要是介绍Docker端口:你真的公开了哪些东西?,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
实际上是背后操盘的人,而不是网络端口或网络安全。

单个命令就能启动你的整个应用,包括环境和所有依赖项,简直令人梦寐以求。如果你懂 Docker,它是一款强大的工具,可以安全地部署应用。

但对于新手来说,这很容易做到。我最近在阅读Docker 的网络文档的时候,页面上弹出的大大的橙色警告让我想起了我刚开始使用 Docker 时感到惊讶的那个时刻。

A whale bursts through a firewall, exposing your containers

鲸鱼冲破了防火墙,暴露了你的容器们。——图片来自 Midjourney

虽然这篇文章主要关注Docker中的一个特定问题,但我的主要不满其实并不是针对Docker本身。Docker以这种方式工作是有其合理原因的,并且这方面的文档说明也很详细。其网络页面上有明确的警告,深入阅读还可以找到例如以下段落明确说明了Docker与防火墙的交互方式:

这意味着,当你通过 Docker 发布一个端口时,这个端口会自动对外发布,无论你的防火墙当前配置了什么规则。如果你想让这些规则在通过 Docker 发布端口时仍然有效,你必须把这些规则添加到 DOCKER-USER 链。

这篇文章更像是对围绕这一问题及类似问题所观察到的吐槽。我的吐槽在于,软件开发行业特别倾向于培养那些不理解工具工作原理却使用工具的开发者,然后在他们不可避免地自找苦吃时责备他们。

创建和部署应用程序其实并不难入门。如果你想建造一栋楼,你需要克服许多审批程序和繁琐的手续。在施工开始前,你的计划必须获得批准,以确保符合安全、环境和分区法规。还有各种规章制度,例如防火规范,都必须遵循。在建筑可以被占用之前,还需要进行检查以确保符合规定,特别是像电力、供水和燃气这样的关键系统。另一方面,没有人会阻止你编写和部署软件。虽然这种自由是我们的职业特权,但这也有其两面性。

在职场或专业领域,理想情况下应该有经验丰富的开发者进行代码审查、安全审计,甚至黑客攻击模拟以及其他类似检查,以确保应用的安全。但并不是每一个为了兴趣开发应用的独立开发者都了解如何进行这些检查,甚至他们可能根本不知道应该执行这些检查。这篇文章就是写给这些人的。

这个问题

我来告诉你一下我第一次遇到这个问题的情况。当时我在桌面上运行了一个小型的MySQL数据库,用于一个侧项目,使用的是公开的数据集。数据库运行在3306端口,但我配置了防火墙,防止所有传入连接。我有一个小Python脚本,可以运行它从原始来源下载数据并更新我的小型本地数据库。随着时间的推移,我从安装的MySQL版本切换到了Docker容器。为了继续运行Python脚本而无需做任何更改,我只需在docker run命令中添加参数-p 3306:3306。当我想要更新数据时,我可以运行这个脚本来下载新的数据。

我还记得特别清楚地读过上述提到的Docker网络文档里的那个大橙色警告。

默认情况下,发布容器端口是不安全的。换句话说,当你发布一个容器的端口时,它不仅对Docker主机可用,还对外部世界开放。

“哇,肯定挺重要的!幸好有那么大的橙色警告好让大家注意。我还是再检查一下防火墙设置,确保它能拦住。”

有一天,我在调试一个与之完全无关的网络问题——我是在另一个房间用笔记本调试一些与 Samba 共享相关的问题。我用 nmap 查看了台式机上哪些端口是开放的,当我看到 3306 端口开放时,尽管防火墙明确禁止了该端口的连接,我感到非常震惊。

幸好,我的暴露仅限于家里的局域网。数据库用一个相对弱的密码保护,里面只包含公开的数据。但是,一想到有多少开发者可能将应用数据库部署在带有公开端口的容器中,这让我非常担心,他们可能无意中将数据暴露给整个互联网。

不止我一个人吧?

显然不止我一个人担心这个问题。有很多像这样的bug报告和另一个,在各种平台上还有相关的讨论和文章,甚至还有一个尝试解决问题的项目。如果你查看这些bug报告中的讨论,你会发现无休止的争论,甚至有人怀疑这个问题是否存在。

如前所述,我不反对 Docker 这样运行,而是许多人在回复这些讨论时表现出的轻视态度令我不满。以下这些 Reddit 上的评论尽管已有 9 年之久,但却完美地说明了我的立场。

如果你在运行 Docker,要注意,UFW 是一个 iptables 的前端工具,任何有足够权限的程序都可以修改这些规则。

“我相当确定,而且希望我说得对,使用Docker的人应该自己能弄清楚这一点。”

这种态度并不建设性。当然,如果一个普通的自学发烧友在部署应用程序时也熟悉安全最佳实践,那当然是很好的,但现实是,我们生活在一个没有障碍或繁琐的手续强制执行这种局面的世界里。

学习的一些注记

你不知道自己不知道的事。

我们通常通过反馈学得最好——如果你写的代码出错了,你会立刻知道你做错了什么;修复它并看到它正常工作,这会给你带来积极的反馈,强化了你解决特定问题的方法。这种即时反馈循环让你可以通过启动项目并逐步解决出现的挑战来轻松学习编码。然而,如果你写的代码难以维护或存在安全隐患,你可能要等到几个月甚至几年后才会收到这些反馈,如果有的话。这意味着像安全这样的概念不容易通过试错来掌握。

A painting of a tree surrounded by a river, with swirling loops, arrows, and some illegible text.

通过积极的反馈来学习,就像 Midjourney 想象的那样。

解决这个特定的Docker问题的方法

如果你在这里,你可能只是在寻找一种保护你的容器的方法。可能你在寻找一种保护你的容器的方法,如果是这样的话,非常感谢你看到这里。这里有几个方法:

  1. 实际上,最佳的解决方案是除非你确实希望公开暴露该端口,否则不要发布端口。对于容器间的通信,最佳实践是设置一个专门用于这种流量的Docker网络,并确保容器连接到该网络。主要的限制是,它不适用于不在容器内运行的进程。并非每个应用程序都适合容器化,并且有时你需要在主机上运行一个进程,该进程需要访问容器中的内容。
  2. 一个常见的建议,但官方文档特别建议不要这样做,就是将 /etc/docker/daemon.json 中的 iptables 设置为 false。这将阻止 Docker 添加其网络规则,这意味着容器中的网络将完全无法工作。如果你确实要这样做,你需要手动添加规则。这并不简单,也容易出错 —— 如果你不懂该怎么做,可能会导致不安全的配置,或者在极端情况下,把自己锁在服务器之外。
  3. 一个稍微好一点的方法,不会破坏容器网络,就是将默认地址绑定设为本地仅用。你可以通过将 /etc/docker/daemon.json 中的 ip 设置为 127.0.0.1 来实现。实际上,我认为从一开始就应该默认将IP地址绑定到本地,并且容器仅在显式配置后才可从主机外部访问。但现在已经太晚改变这一点了。这是过去我所采用的方法,但有一个缺点。它违背了容器的可移植性。如果你想在不同的主机上运行容器,需要记得更改配置。理想情况下,你希望容器在任何主机上以相同的方式运行。一个如果没有记住更改主机上的设置就存在安全风险的容器不是一个好主意。
  4. 最佳实践应该是习惯于在 Docker 命令和 docker-compose.yml 中使用明确的 IP 地址绑定。你应该习惯于从不写 -p 3306:3306,而应该选择写 -p 127.0.0.1:3306:3306,并且在确实需要将端口暴露给外部世界时,明确指出这一点: -p 0.0.0.0:3306:3306。这是我采用的方法,当 Docker 网络不可用时。

现在,我不清楚如何解决那些无意中推荐将数据库暴露给全世界的教程大量存在的问题?

解决通用问题的方法

这是一篇我一直想写几年的文章。开发者的态度常常是我经常抱怨的一个点。一种守门心态——“如果你不懂我懂的东西,那你可能不太适合做这件事”——非常普遍。

但在这种奇特的行业中,我们中的许多人是为了赚钱而做这件事,而另一些人则是纯粹为了乐趣。这让我有点不安,普通爱好者的善意安全措施在将应用程序部署到他们称为服务器的VPS或备用笔记本电脑上时,会忽略很多细节。

从整体来看,解决方案有两个方面:

  1. 对于缺乏经验的开发者,如果只是想开始做一些事情:继续努力!尽量吸收尽可能多的知识,不要跳过你所使用工具的官方文档。记住自己不知道什么,这是正常的,最好的学习方式就是不断尝试新事物。
  2. 对于有经验的开发者,尤其是那些在广泛使用的开源工具中负责关键设计决策的人:记住你仍然有义务保护那些永远不会阅读文档的人,他们依赖于快速浏览别人写的教程。设置安全的默认选项是我们的责任——也许对于 Docker 已经太晚了,但对你所参与的下一个工具来说可能还来得及。当我们的工具被以非预期的方式使用时,尽量不要轻视和不尊重用户,而是利用这些机会来教育用户,甚至可能学到新的东西。

你有过类似的经历吗?还有,你见过哪些工具默认设置不安全的吗?

这篇关于Docker端口:你真的公开了哪些东西?的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!