简介 我对 Docker 世界还很陌生,除了舒适之外,容器化的巨大优势是服务隔离。然而,令我完全惊讶的是,这既不是默认设置,也似乎不方便实现。
我的场景实际上是一个很常见的场景,反向代理(例如traefik)和一些容器化服务,其中一些需要互联网访问。 虽然设置很容易,但通常的指南建议在 A B C P(反向代理)之间使用共享桥接网络。
动机 然而,从安全角度来看,这意味着所有服务都能够在网络上互相看到对方。如果使用具有前向身份验证的中间件(例如 authelia)进行身份验证,则一个受感染的服务很容易冒充另一服务上的另一个用户,例如通过
container-a$ curl -H "Remote-User: admin" http://container-b:8080
借助诸如 arp 缓存欺骗之类的技术,一个受感染的容器甚至有可能捕获用于另一容器的所有网络流量。
目标 我的目标是以这样一种方式设置我的容器,即使一个容器受到损害,即攻击者在该容器中具有 shell 访问权限,所有其他服务仍然是安全的。因此
反向代理,以及每个服务都有自己独立的设置
docker-compose.yml
。
当前解决方案 我首先禁用容器间通信 (
enable_icc: false
),但这并不能阻止容器访问其他容器已发布的端口。
经过一番实验,我终于通过为每个服务创建一个单独的自定义桥接网络(即 P<->A、P<->B 和 P<->C)来实现我的目标,例如
docker network create proxy_A -o com.docker.network.bridge.name=br-a
并将其连接到反向代理和服务。所以反向代理的 docker-compose 看起来像这样
services:
revproxy:
networks:
- proxy_A
- proxy_B
- proxy_C
[...]
networks:
proxy_A:
driver: bridge
external: true
proxy_B:
driver: bridge
external: true
proxy_C:
driver: bridge
external: true
只要容器不发布任何端口,它们不需要被反向代理访问,这就将它们全部分开并允许互联网访问。 如果该服务不需要互联网访问,则只需将网络标记为
--internal
即可完成。
但是,如果确实如此,非内部网络也允许访问我的本地以太网。为了阻止这个问题,我为所有容器添加了以下自定义 iptables 规则,例如
# deny access to ethernet
iptables -I DOCKER-USER -i br-a -d 192.168.0.0/16 -j DROP # or probably better REJECT
# except for DNS
iptables -I DOCKER-USER -i br-a -d 192.168.1.1 -p udp --dport 53 -j ACCEPT
iptables -I DOCKER-USER -i br-a -d 192.168.1.1 -p tcp --dport 53 -j ACCEPT
虽然这有效,但我不是很高兴,因为它需要为每个服务进行大量的手动配置工作:为新服务创建网络,将反向代理连接到它并设置 iptables 规则。 我能想出的唯一能稍微改善这种情况的解决方案是创建另一个
docker-compose.yml
,它使用 include
来设置代理、所有服务和相应的网络。
version: '3'
include:
- A/docker-compose.yml
- B/docker-compose.yml
- C/docker-compose.yml
networks:
proxy_A:
driver: bridge
driver_opts:
com.docker.network.bridge.name: br-a
[...]
但特别是关于 iptables 规则,我期望有某种方法将它们添加到 docker-compose 文件中,但我没有找到任何方法。
问题
docker-compose.yml
内,而不需要任何进一步的修改,例如编辑反向代理docker-compose文件,docker network connect
和iptables
?正如使用 traefik 的 docker 提供程序通常可以(无需隔离)一样,我想启动新的服务容器并能够通过反向代理访问它。我只能回答1个问题:
有没有更好的方法来实现我的目标[...]。
是的,有。然而,这不在 Docker 中。您应该使用 Kubernetes 或其他容器管理器。这些本质上是更安全的。 Docker 以 root 身份运行其容器。 (除非您使用 Podman)。这意味着,如果容器逃逸成功,它们将成为整个服务器的根。
Docker 非常手动,像 Kubernetes(或使用 helmcharts)这样的管理器会给你很大帮助! (他们也更注重安全)。
希望这对您有一点帮助!