容器化 VPS 纵深安全加固:从 SSH 到 Docker 运行时一条链


一台暴露在公网、上面跑自托管全家桶的 VPS,本质是"一台机器 + 一堆 root 权限的容器进程"。Docker 的便利让人觉得容器是隔离的,但默认情况下 Docker 守护进程、容器网络、宿主机内核之间共享的东西比你以为的多得多。这篇文章按 Linux 防御纵深的顺序,把从 SSH 入口、主机防火墙到容器运行时这一整条链路上的关键加固点讲清楚,并说明每个措施到底在防什么、代价是什么。

一、先封住最常见的第一道门:SSH

默认 22 端口 + 密码登录是一天扫几千次的靶子。第一步把 SSH 改到非标准端口并禁止密码登录、改用密钥:编辑 /etc/ssh/sshd_config,至少加上 Port 50222、PasswordAuthentication no、PermitRootLogin no。提醒一点:PermitRootLogin no 禁用的是 root 直接用密钥登录,日常用普通用户 sudo 提权即可。改完 systemctl reload sshd(先开着当前会话,别把自己关在门外)。这一步的收益最大:密码爆破的入口直接关掉。

再叠加一个限速率:fail2ban。它读取日志、对多次失败尝试封禁 IP 一段时间。默认 jail 能覆盖 sshd,配合 ignoreip 白名单把自己的出口 IP 放行,避免误封。SSH 是主机层面最优先加固的入口,因为它一旦沦陷,后面的所有纵深都白搭。

二、主机防火墙:默认拒绝,只留必要端口

服务器还没有任何应用时,防火墙策略应当是"默认丢弃、显式放行"。用 ufw 或 firewalld 把端口收口:只放行自己的 SSH 端口、80/443(给 Traefik 之类网关)、以及你确实要对外暴露的少数端口,其余一律拒绝。ufw 的关键区别在于顺序:default deny incoming 要放在最前面,放行规则在其后追加,不要反着写,否则会出现"看着很安全、实际全开"的假象。改防火墙要分成微小步骤推进:先只追加放行 80/443,再停用多余的容器端口映射,最后刷新规则并确认新 SSH 端口可连,避免改到一半把自己断在门外。

三、少给容器发 Root 能力:cap-drop 与 nonroot

默认容器以 root 用户运行,还默认继承了若干 Linux capabilities。我们能做的最有价值的一件事是把这些能力的清单删到只剩业务必需:在 compose 里统一加 cap_add: [] 配合 cap_drop: [ALL],再按需放回 NET_BIND_SERVICE(绑 80 端口)这类少数能力。删除的能力少了,就算容器被攻破,攻击者能调用的内核特权面也大幅缩水。镜像层面,优先用官方标注的 nonroot 变体,并在 compose 里写 user: "65534:65534"(nobody)运行——一个不在任何权限组的 UID,横向移动难度大很多。

四、只读根文件系统与 seccomp:把"能写的都关了"

大多数无状态容器根本不需要写自己的根文件系统。给业务容器加 read_only: true,把确实要写临时文件的位置单独用 tmpfs 挂载(tmpfs: /tmp),这样容器内层变得不可写,"写入后门/持久化"这类攻击路径被直接切断。再叠一层 seccomp:Docker 默认的 seccomp profile 已过滤大量危险系统调用,除非业务明确需要,不要随便设 security_opt: seccomp=unconfined——那等于把内核系统调用的大门敞开。两个措施叠加之后,容器的运行时面就从一个"能执行大部分系统调用的 root",收敛成"只能做被允许的几件事的 nobody"。

五、镜像供应链:别把自己变成"带毒软件分发机"

运行时再硬,基础镜像有漏洞也白搭。镜像层面至少做两件事:一是固定版本的 tag,拒绝 latest,让每次启动在时间上可复现;二是定期用 trivy image 这类扫描器对新老镜像做一轮 CVE 扫描,高危漏洞出来后再决定是升级镜像还是评估暴露面。镜像扫描不能解决"别人往恶意仓库投毒"的供应链问题,但它是成本最低的第一道筛子,很多被大量复制的坑镜像就是靠它拦下来的。

六、网络隔离:容器也别在同一个"局域网"里畅聊

默认把所有容器放进同一个 bridge 网络,等于让它们可以任意互访——一旦一个容器失守,攻击者能以它当跳板。收敛办法是把服务按信任分区拆进独立的自定义网络:对外网暴露的放 frontend,Database 这类只被内部调用的放 internal,两者之间只有真正需要通信的容器才同时挂两个网。配合第一步里"业务容器不发布端口、只由网关转发",即便某个 Web 容器被攻破,它直接能触达的攻击面也被压缩到很小的范围。

七、把加固变成"持续的策略"而不是一次性的动作

纵深的每一层都解决一类特定问题:SSH 挡住暴力登录、防火墙收口暴露面、cap-drop/seccomp 缩容器特权面、read_only 断持久化后门、网络分区限横向移动、镜像扫描拦供应链。它们串在一起的意义不在任何单层多强,而在"单点失守不至于全线崩溃"。加固真正难的不是执行某一条,而是让每台新开的 VPS 都自动落到这一套基线里——把策略沉淀成模板,每次开机组装容器时按同一个 check 走一遍,才能让"这台还挺安全"是默认值,而不是运气。


手机扫码阅读

微信或手机浏览器扫一扫,随时随地随心阅读与分享

自托管监控告警实战:Prometheus + Grafana 一眼看全服务器

Docker 数据与升级之道:持久化、备份与零停机滚动更新

评 论
更换验证码