Cover image for 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を使用
  • ログインを1ユーザーに制限:AllowUsers deploy
  • 10分後にアイドルセッションを切断:

    • ClientAliveInterval 300
    • ClientAliveCountMax 2

これら5つの変更で、自動化された攻撃の大部分を排除できる。不可視になるわけではないが、もはや簡単な標的ではなくなる。

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

べき等性とは何か — なぜ重要か

べき等(Idempotent)とは、同じ操作を2回実行しても1回実行した結果と同じになることを意味する。

学術的に聞こえるが、そうではない。

実際には次のことを意味する:

  • deployユーザーが既に存在する場合、エラーを返さずにスキップする。
  • 証明書が既に存在する場合、重複してリクエストせずにスキップする。
  • パッケージが既にインストールされている場合、apt-getが適切に処理する。

べき等性がなければ、部分的な失敗後にセットアップスクリプトを再実行すると、自分のサーバーからロックアウトされる可能性がある。べき等性があれば、中断後も安心してスクリプトを実行できる。

この習慣は、Ansible、Terraform、プロフェッショナルレベルで使用するすべての自動化ツールに引き継がれる。

スクリプト

完全なスクリプトはこちら:

github.com/tesddev/server-bootstrap

新品のUbuntu 22.04サーバーで、1つのコマンドですべてを実行:

sudo bash setup.sh

Enter fullscreen mode Exit fullscreen mode

スクリプトは順に以下の処理を行う:

  1. システムを更新し、必須パッケージをインストール。
  2. 非rootのdeployユーザーを作成し、SSHキーをコピー。
  3. ポート変更、rootログインとパスワード認証の無効化、アイドルタイムアウト設定によりSSHを強化。
  4. 明示的な許可リストでUFWを設定。
  5. Nginxをインストールし、カスタムページを提供。
  6. Certbotを使用してLet's Encrypt証明書を取得。

最終的に得られるもの

  • 非標準ポートで鍵認証のみに制限されたSSH
  • 必要なトラフィックのみを許可するファイアウォール
  • 有効で自動更新される証明書を持つhttps://tes-devops.duckdns.org上のライブサイト
  • 今日または半年後、どの新しいサーバーでも実行可能なスクリプト

本当の教訓

手動のサーバー設定はスケールせず、何より確実に再現できない。2人の異なる人が2日の異なる日に同じ手順を実行しても、微妙に異なるサーバーができあがる。

スクリプトにはその問題がない。

小さくべき等な自動化スクリプトを書くことは、DevOpsで最も移行可能な習慣の1つである。以降のすべて — Ansibleプレイブック、Terraformモジュール、Kubernetesマニフェスト — は、同じアイデアをより大きな規模で適用したものである。

➡️ GitHubでserver-bootstrapリポジトリを表示