安全基线与加固 (Security Baseline)¶
[!CAUTION] 必须执行:本文档是后续所有部署的前置条件。未通过本基线检查的服务器,严禁安装 Docker 或连接公网。 原则:Default Deny (默认拒绝) > Convenience (便利性)。
1. 网络层防御 (Network Layer)¶
1.1 Oracle Cloud Security List (第一道防线)¶
在 Oracle Cloud 控制台 -> Networking -> VCN -> Security List 中,删除默认的 "Allow All" 规则。 仅允许以下入站规则 (Ingress Rules):
⚠️ 必读配置细节: * 源端口范围 (Source Port Range): 务必留空或填
All。千万不要填 22/80 等。(这是对方机器的随机端口) * 目的端口范围 (Destination Port Range): 这里才是填 22/80/443 的地方。(这是你服务器监听的端口) * 端口格式 (Syntax): 如果控制台允许你填逗号 (如80,443) 并保存成功,那就可以用。如果报错,请分两条规则写。 * 验证方法:配置完后在本地终端telnet <IP> 80和telnet <IP> 443确认都通。
| Protocol | Destination Port | Source CIDR | Description | Note |
|---|---|---|---|---|
| TCP | 22 | 0.0.0.0/0 |
SSH | 仅限密钥登录 (见下文) |
| TCP | 80 | 0.0.0.0/0 |
HTTP | 仅限 Web 业务 |
| TCP | 443 | 0.0.0.0/0 |
HTTPS | 仅限 Web 业务 |
| UDP | 41641 | 0.0.0.0/0 |
Tailscale | P2P 穿透 (必须开启) |
| ICMO | - | 0.0.0.0/0 |
Ping | 方便监控连通性 (可选) |
| All | All | 10.0.0.0/16 | VCN Internal | Oracle 内网互通 (Swarm 必需) |
❌ 严禁开放:9000 (Portainer), 8080 (Traefik Dashboard), 2375 (Docker API), 3306 (MySQL), 6379 (Redis)。
1.2 出站规则 (Egress Rules / Outbound)¶
对于普通服务器,保持全开 (Allow All) 即可。如果限制出站,你将无法执行 apt update、docker pull 或访问外部 API。
| Protocol | Destination CIDR | Port | Description |
|---|---|---|---|
| All Protocols | 0.0.0.0/0 |
All | 允许所有出站流量 (默认配置) |
💡 这会被攻击者利用吗? 是的,高级攻击者确实会利用 80/443 伪装成正常流量外传数据 (Data Exfiltration)。 但对于通用服务器,限制出站弊大于利(会导致系统更新、Docker 拉取、时钟同步频繁失败)。 真正的出站防护 需要 域名白名单 (Domain Whitelisting) 网关,这超出了基础防火墙 (Layer 4) 的能力范围。
1.3 主机防火墙 UFW (第二道防线)¶
即使 Oracle 安全组配置正确,主机层也必须配置防火墙,防止 Docker 自动修改 iptables 导致端口泄露 (Docker 的 iptables: true 特性会忽略 UFW,除非特殊配置,但我们要养成习惯)。
脚本:一键初始化 (分步执行)
Step 1: 基础防御 (UFW Base)
任何服务器都必须执行。
sudo apt update && sudo apt install -y ufw wget && \ sudo ufw default deny incoming && \ sudo ufw default allow outgoing && \ sudo ufw allow 22/tcp comment 'SSH' && \ sudo ufw allow 41641/udp comment 'Tailscale Direct' && \ sudo ufw allow in on tailscale0 comment 'Allow Tailscale Net' && \ sudo ufw allow from 10.0.0.0/16 comment 'Allow Oracle VCN' && \ sudo ufw --force enable && \ sudo ufw reload
Step 2: 容器增强 (ufw-docker Extension)
[新增] 如果这台机器要运行 Docker,必须执行此步以防穿透。
sudo wget -O /usr/local/bin/ufw-docker https://github.com/chaifeng/ufw-docker/raw/master/ufw-docker && \ sudo chmod +x /usr/local/bin/ufw-docker && \ sudo ufw-docker install && \ sudo ufw reload💡 UFW 能完全接管 iptables 吗? 不能。UFW 本质上只是 iptables 的一个前端工具。 * Docker 的特权:Docker 会直接修改 iptables 的
PREROUTING链,优先级高于 UFW。这就是 UFW 最大的坑:你以为封了端口,结果 Docker 一启容器,端口全开了。 * 解决方案: 1. Oracle 安全组 (第一道防线):必须配置。只要云厂商防火墙关了,Docker 再怎么折腾也出不去。 2. ufw-docker (修复 UFW):安装ufw-docker工具,让 UFW 能正确管理 Docker 暴露的端口。
🛡️ 安装 ufw-docker (强烈推荐)¶
解决 Docker 绕过 UFW 的问题,并提供便捷的容器防火墙管理。
# 1. 下载并安装脚本
sudo wget -O /usr/local/bin/ufw-docker https://github.com/chaifeng/ufw-docker/raw/master/ufw-docker
sudo chmod +x /usr/local/bin/ufw-docker
# 2. 安装规则 (这会修改 /etc/ufw/after.rules)
sudo ufw-docker install
# 3. 重启 UFW 生效
sudo ufw reload
⚠️ Swarm Mode 特别配置 (Critical)¶
注意:
ufw-docker默认会拦截所有发往 Docker 容器的流量,包括 Swarm 内部的 Overlay 网络和 Ingress 流量。 必须手动添加白名单,否则 Traefik 无法连接后端服务,Ingress 端口也无法访问。
修改配置文件:sudo nano /etc/ufw/after.rules
在文件末尾 (即 COMMIT 行之前) 添加:
# --- Docker Swarm & Traefik Fix ---
# 1. 允许 Docker 容器间互访 (解决 Swarm Overlay 网络不通问题)
-I DOCKER-USER -s 10.0.0.0/8 -j ACCEPT
-I DOCKER-USER -s 172.16.0.0/12 -j ACCEPT
# 2. 允许外网访问 Swarm Ingress 端口 (如 80/443)
# 即使 Oracle 安全组放行了,这里不放行也会被 reject
-I DOCKER-USER -p tcp -m tcp --dport 80 -j ACCEPT
-I DOCKER-USER -p tcp -m tcp --dport 443 -j ACCEPT
# ----------------------------------
最后重启 UFW:
sudo ufw reload
🛠️ 常用命令¶
| 场景 | 命令 | 说明 |
|---|---|---|
| 查看状态 | ufw-docker status |
查看 Docker 相关的 UFW 规则 |
| 暴露端口 | ufw-docker allow <容器名> <端口> |
允许外网访问特定容器的端口 |
| 特定IP访问 | ufw-docker allow <容器名> <端口> from <IP> |
仅允许特定 IP 访问容器 |
| 删除规则 | ufw-docker delete allow <容器名> <端口> |
撤销之前的允许规则 |
⚠️ 注意:使用
ufw-docker后,Docker run 的-p 80:80依然有效,但ufw-docker install会默认阻止外部访问 Docker 端口(除非显式allow),从而修复了安全漏洞。建议配合 Oracle 安全组 双重防护。
2. 系统层防御 (OS Layer)¶
2.1 SSH 加固:端口要不要改?(To Change or Not To Change)¶
结论:改回 22 (标准化 > 隐匿性)。
* 理由 1 (无效防御):改端口属于“Security by Obscurity”。脚本扫全端口只需几秒钟就能找出来,对真正的攻击者毫无意义。
* 理由 2 (运维成本):改了端口后,所有工具 (Ansible/SCP/Git/Jenkins) 都要特殊配置,徒增心智负担。
* 正解:只要禁用了密码登录 (PasswordAuthentication no),端口 22 就是铜墙铁壁,没人能爆破 RSA/Ed25519 密钥。
2.2 SSH 核心配置 (禁止密码,仅密钥)¶
黑客无时无刻不在爆破你的 root 密码。
操作步骤:
1. 确保你已经配置好了 SSH Key 并能成功登录。
2. 编辑配置文件:sudo nano /etc/ssh/sshd_config
3. 修改/确认以下参数:
echo -e "PasswordAuthentication no\nPubkeyAuthentication yes\nPermitRootLogin prohibit-password" | sudo tee /etc/ssh/sshd_config.d/99-hardened.conf
sudo systemctl restart sshd
2.2 自动安全更新¶
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
# 选择 "Yes"
2.3 操作系统生命周期 (OS Lifecycle Strategy)¶
原则:宠物 (Pet) vs 牲畜 (Cattle) —— 把服务器当牲畜养。
- 什么时候该重装?
- EOL (End of Life): 比如 Ubuntu 20.04 标准支持于 2025 年 4 月结束。现在是 2026 年,必须重装。
- 内核过旧:
uname -r显示内核版本落后主流 2 个大版本 (如还在用 4.x/5.4),且无法通过apt upgrade升级。 - 脏乱差: 系统里装了太多不知名的软件,与其清理,不如重建。
- 最佳实践:
- 不要做跨版本升级 (
do-release-upgrade):很容易挂。 - 直接开新机器:部署 Docker -> 导入数据 -> 切换 DNS -> 销毁旧机器。
- 不要做跨版本升级 (
2.4 推荐版本 (Recommended OS Versions - 2026 Edition)¶
选型原则: 1. LTS (长期支持版):必须。 2. Minimal (最小化安装):强烈推荐。
| 发行版 | 推荐版本 | 代号 | 适用场景 |
|---|---|---|---|
| Ubuntu | 24.04 LTS (Minimal) | Noble | 首选通用系统。生态最好,文档最全。Minimal 版仅含内核+SSH+APT,其它全靠自己装。 |
| Debian | Debian 13.3 | Trixie | 极客/资源敏感型。内存占用极低,但配置稍繁琐 (无 sudo, ssh 默认禁 root)。 |
💡 Ubuntu 24.04 Minimal 少了什么? * 少了便利工具:
vim,pico,Python3-full,net-tools,man-pages(文档)。 * 多了安全与性能: 启动更快,补丁更少,攻击面更小。 * 建议: 在安装时勾选 "Minimized" 选项,进系统后手动装回需要的工具 (sudo apt install curl wget nano htop git)。这就叫“按需分配”。
2.5 资源适配指引 (OS Sizing Strategy)¶
针对不同配置的服务器,建议采用 分层策略:
| 如果您的服务器配置是... | 推荐系统 | 理由 |
|---|---|---|
| 内存 > 2GB (如 Oracle 2核12G) | Ubuntu 24.04 LTS | 便利性优先。资源充裕,享受完整的生态支持和便利工具,无需折腾。 |
| 内存 ≤ 1GB (如 1核1G) | Debian 12/13 | 生存优先。Ubuntu 待机 ~180MB,Debian 仅 ~80MB。这就差出了一个 Redis 的内存空间。 |
🤔 只有 1G 内存能装 Ubuntu 吗? 可以,但必须用 Minimal 版,且必须配置 ZRAM (内存压缩) 或 Swap。否则做一次
apt upgrade甚至docker build都可能 OOM (内存溢出) 导致死机。
3. Docker 安全规范 (Container Layer)¶
在部署任何容器前,必须遵守:
- Binding (绑定):管理面板 (Portainer, Traefik Dashboard) 必须 绑定到
127.0.0.1。- ❌
ports: - "9000:9000"(危险!暴露给 0.0.0.0) - ✅
ports: - "127.0.0.1:9000:9000"(安全,仅本机访问)
- ❌
- Network (网络):数据库/缓存 (Redis, MySQL) 严禁 映射端口到宿主机,除非绑定到内网 IP (
10.0.x.x或 Tailscale IP)。- ✅ 推荐使用 Docker Network 内部互联,不映射端口。
- Privilege (特权):除非是 VPN 或硬件驱动容器,严禁 使用
privileged: true。
4. 持续安全运营 (Ongoing Security Operations)¶
安全不是一次性配置,而是持续的过程。
4.1 凭证轮换周期 (Credential Rotation)¶
建立定期更换密钥的习惯,防止凭证泄露导致的长期潜伏。
| 凭证类型 | 建议周期 | 操作方式 | 备注 |
|---|---|---|---|
| SSH Key (User) | 6-12 个月 | 生成新 Key -> 更新 authorized_keys -> 删除旧 Key |
个人电脑端私钥同步更新 |
| Tailscale Key | 90 天 | Console -> Regenerate Auth Key | 使用 Ephemeral Key 部署临时节点 |
| Portainer Admin | 90 天 | User Settings -> Password | 开启 2FA (双因素认证) |
| Database User | 180 天 | ALTER USER ... IDENTIFIED BY ... |
更新相关服务的环境变量 |
4.1.1 如何生成新密钥?(Client Side)¶
请在您的本地电脑 (Windows) 上执行,而不是在服务器上!
私钥 (id_ed25519) 必须永远留在您手里,公钥 (id_ed25519.pub) 才发给服务器。
- 本地生成: 打开 PowerShell,运行
ssh-keygen -t ed25519 -C "your_email"- System asks for passphrase: 强烈建议输入一个密码。这样即使您的电脑中了木马,私钥被偷走,黑客因为不知道密码也无法使用。
- 上传公钥:
type $env:USERPROFILE\.ssh\id_ed25519.pub | ssh user@host "cat >> .ssh/authorized_keys" - 验证登录:
ssh user@host(确认不再询问服务器密码,但可能会问 Key 的密码)
4.2 审计与监控 (Audit & Monitor)¶
每月检查一次服务器是否存在异常行为。
- 登录审计:
lastlog | grep -v "Never" # 查看最近登录用户 sudo cat /var/log/auth.log | grep "Accepted" # 成功登录记录 - 进程审计:
htop # 按 P (CPU) 或 M (Memory) 排序,寻找名为 "xmrig", "kdevtmpfsi" 等陌生进程 - 端口审计:
sudo ss -tulpn # 确认没有未知端口监听 0.0.0.0
4.3 应急响应 SOP (Emergency SOP)¶
当怀疑服务器被入侵时:
1. 断网: 立即去 Oracle 控制台 Deny All Ingress。
2. 取证: 不重启,保存 /var/log 和当前进程快照。
3. 重建: 以前文提到的 不可变基础设施 理念,直接销毁实例,用代码重新部署。不要尝试杀毒。
✅ 基线检查清单¶
- [ ] Oracle Security List 入站规则仅剩 22/80/443/41641。
- [ ] 运行
sudo ufw status显示Status: active且规则符合预期。 - [ ] 尝试
ssh -o PreferredAuthentications=password user@host提示 "Permission denied" (密码登录已关闭)。 - [ ] 确认没有 Docker 容器直接映射敏感端口到
0.0.0.0。 - [ ] [新增] 已在日历设置每季度一次的“密钥轮换日”。
🔍 5.1 自动化核查脚本 (Firewall Verification Script)¶
在所有节点部署完毕后,请直接复制粘贴以下脚本进行最终验收:
# === Firewall Security Audit ===
# (Tips: Copy all lines and paste into terminal)
# 1. 临时关闭历史记录扩展 (防止 ! 被转义报错)
set +H
# 2. Check UFW Status
if sudo ufw status | grep -q "Status: active"; then
echo "✅ [PASS] UFW is ACTIVE"
else
echo "❌ [FAIL] UFW is INACTIVE (Huge Risk!)"
fi
# 3. Check ufw-docker Integration
if sudo iptables -L DOCKER-USER -n | grep -q "ufw-docker-logging-deny"; then
echo "✅ [PASS] ufw-docker chains detected"
else
echo "❌ [FAIL] ufw-docker NOT detected (Docker ports are bypassing firewall!)"
fi
# 4. Check Critical Ports (Should be ALLOW)
echo "--- Port Checks ---"
sudo ufw status | grep -E "22/tcp|41641/udp"
# 5. Check Dangerous Ports (Should NOT be ALLOW)
if sudo ufw status | grep -E "9000|9001|2375|3306" | grep -q "ALLOW"; then
echo "❌ [FAIL] DANGEROUS ports (9000/9001/3306/...) found in ALLOW list!"
else
echo "✅ [PASS] No dangerous ports found in UFW"
fi
# 恢复历史记录扩展
set -H
echo "==============================="