How I Automated Ubuntu Server Hardening with One Script 封面图片

Tesleem Amuda

云服务器的安全与自动化

第一次启动云服务器时,我以为最难的部分已经完成。其实不然。那台服务器暴露在公网:root 登录已启用,22 端口对互联网上的每一台扫描器开放,没有防火墙,也没有证书。

几个小时后,我检查 /var/log/auth.log,发现数百次登录失败。那一刻,我明白了为什么 SSH 加固不是可选项。

为什么 SSH 加固至关重要

SSH 是服务器的正门。默认情况下,这扇门完全敞开:22 端口、允许密码认证、允许 root 登录。自动化机器人每小时都在扫描数百万 IP 地址,专门寻找这类目标。

SSH 加固意味着在任何其他操作之前关闭这个缺口:

  • 禁用 root 登录:PermitRootLogin no
  • 禁用密码认证,仅使用密钥:PasswordAuthentication no
  • 将 SSH 端口改为非 22——我使用端口 2247
  • 限制仅允许特定用户登录:AllowUsers deploy
  • 10 分钟后断开空闲会话:

    • ClientAliveInterval 300
    • ClientAliveCountMax 2

这五项更改能消除绝大多数自动化攻击。你不会隐形,但也不再是容易的目标。

UFW 的作用

UFW(Uncomplicated Firewall)是 Ubuntu 为 iptables 提供的易用界面。与其编写底层规则,不如直接表达意图:

ufw default deny incoming
ufw default allow outgoing

ufw allow 2247/tcp   # SSH on custom port
ufw allow 80/tcp     # HTTP
ufw allow 443/tcp    # HTTPS

ufw --force enable

Enter fullscreen mode Exit fullscreen mode

所有未明确允许的流量都会被阻断。这就是最小权限原则在网络中的体现,与 Kubernetes NetworkPolicies、IAM 角色和 RBAC 遵循的原则相同。

从这里开始学习。

Let's Encrypt 的工作原理

Let's Encrypt 是一个受主流浏览器信任的免费、自动化证书颁发机构。流程如下:

  1. 将域名指向服务器 IP 地址。
  2. Certbot 通过 HTTP 提供挑战文件,证明你拥有该域名。
  3. Let's Encrypt 颁发有效期 90 天的证书。
  4. Certbot 重写 Nginx 配置,自动提供 HTTPS 并重定向 HTTP。
  5. 计划任务在证书到期前自动续期,无需人工操作。

最终得到的是一个免费、自动维护的 HTTPS 网站。

以下命令可在不修改生产证书的情况下验证续期流程:

certbot renew --dry-run

Enter fullscreen mode Exit fullscreen mode

幂等性的含义及其重要性

幂等意味着同一操作执行两次与执行一次的结果相同。

这听起来像是学术概念,实则不然。

在实践中,它意味着:

  • 如果 deploy 用户已存在,则跳过创建而非报错。
  • 如果证书已存在,则跳过申请而非重复请求。
  • 如果软件包已安装,apt-get 会妥善处理。

没有幂等性,在部分失败后重新运行设置脚本可能导致你无法访问自己的服务器。有了它,你可以在任何中断后放心运行脚本。

这一习惯会延续到 Ansible、Terraform 以及你在专业工作中使用的所有自动化工具。

脚本

完整脚本见:

github.com/tesddev/server-bootstrap

在全新的 Ubuntu 22.04 服务器上,一条命令即可完成所有操作:

sudo bash setup.sh

Enter fullscreen mode Exit fullscreen mode

脚本按顺序执行:

  1. 更新系统并安装必要软件包。
  2. 创建非 root deploy 用户并复制 SSH 密钥。
  3. 加固 SSH:更改端口、禁用 root 登录和密码认证、设置空闲超时。
  4. 配置 UFW 白名单。
  5. 安装 Nginx 并提供自定义页面。
  6. 使用 Certbot 获取 Let's Encrypt 证书。

最终成果

  • SSH 限制为非标准端口的密钥认证
  • 防火墙仅允许必要流量
  • 拥有有效且自动续期的证书的实时网站:https://tes-devops.duckdns.org
  • 可在任何新服务器上随时运行的脚本

真正收获

手动配置服务器无法扩展,更重要的是无法可靠复现。同样的步骤由不同的人在不同的日子执行,会得到略有差异的服务器。

脚本不存在这个问题。

编写小型、幂等的自动化脚本是 DevOps 中最可迁移的习惯之一。之后的一切——Ansible playbook、Terraform 模块和 Kubernetes manifest——都只是这一理念在更大规模上的应用。

➡️ 在 GitHub 上查看 server-bootstrap 仓库