「バックアップ暗号化」という悪夢
半年ほど前、提携先の同僚からパニック状態で電話がかかってきました。彼らのインフラ全体がランサムウェアの被害に遭ったのです。堅牢なバックアップルーチンを運用していましたが、攻撃者はまずバックアップサーバーへの横方向のアクセス(ラテラルムーブメント)を確保していました。彼らは本番データベースの暗号化を実行する前に、4TB分のクラウドエクスポートデータを一掃したのです。セーフティネットが機能しなかっただけでなく、切断されてしまったのです。
現代のランサムウェアは, 単にファイルをロックするだけではありません。攻撃者はバックアップの認証情報を積極的に探し出し、被害者が支払いに応じるしかない状況を作り出します。もしバックアップユーザーに「削除」権限があれば、そのキーを盗んだマルウェアも同様の権限を持つことになります。これを阻止するため、私はLinuxのバックアップワークフロー全体を、S3 Object Lockを使用した「不変(イミュータブル)」モデルに移行しました。半年間の運用を経て、この構成は私たちの災害復旧計画において最も不可欠な要素となっています。
何がバックアップを真に「不変」にするのか?
不変性(イミュータビリティ)とは、設定された期間中、rootユーザーやアカウント所有者を含むいかなる人物によっても、データの変更や削除ができないことを保証するものです. S3では、これにWORM(Write Once, Read Many)モデルを利用します。たとえ攻撃者が AWSコンソールの完全な管理者権限を取得したとしても、タイマーが切れるまではロックされたデータに手を出すことはできません。
Object Lockには、主に2つのモードがあります:
- ガバナンスモード(Governance Mode):
s3:BypassGovernanceRetention権限を持つユーザーであれば、オブジェクトを削除できます。テストには便利ですが、高度な攻撃者に対しては隙を残すことになります。 - コンプライアンスモード(Compliance Mode): ゴールドスタンダードです。AWSサポートですら、保持期間が終了するまでオブジェクトを削除することはできません。オーバーライドキーが存在しないデジタル金庫です。
Linuxでの実践的な実装
Linuxネイティブのツールは、自動化において最高の柔軟性を提供します。今回の構成では、設定にAWS CLIを、データ同期にRcloneを使用します。Rcloneはコマンドラインから直接S3 Object Lockのパラメータを扱えるため、非常に効果的です。
1. 環境の要塞化
安全な認証情報は防御の第一線です。IAMシークレットキーやサーバーパスワードを生成する際、私はブラウザベースのジェネレーター toolcraft.app/ja/tools/security/password-generator を使用しています。ブラウザ内でローカルに動作するため、機密性の高い文字列がネットワークを流れることはありません。要塞を築くには、エントロピーの高いキーが不可欠です。
まず、LinuxマシンにAWS CLIをインストールします:
sudo apt update && sudo apt install awscli -y
aws configure
2. Object Lockを有効にしたバケットの作成
既存のバケットでObject Lockを後から有効にするのは容易ではありません。最初からこの機能が有効な新しいバケットを作成する方がはるかに安全です。なお、ロックを使用するにはバージョニングの有効化が必須条件となります。
# バケットの作成
aws s3api create-bucket --bucket my-immutable-backups --region us-east-1
# 30日間のコンプライアンスモード保持ルールを設定してObject Lockを有効化
aws s3api put-object-lock-configuration \
--bucket my-immutable-backups \
--object-lock-configuration '{ "ObjectLockEnabled": "Enabled", "Rule": { "DefaultRetention": { "Mode": "COMPLIANCE", "Days": 30 }}}'
この設定により、my-immutable-backups にアップロードされるすべてのファイルは、即座に30日間保護されます。例外はありません。
3. Rcloneによる同期の自動化
Rcloneはクラウドストレージの「十徳ナイフ」です。軽量であり、マルチスレッド転送を非常に効率的に処理します。公式スクリプトを使用してインストールします:
sudo -v && curl https://rclone.org/install.sh | sudo bash
rclone config を実行してS3リモート(ここでは s3-backup と呼びます)を定義した後、同期スクリプトをデプロイできます。バケットポリシーによってロックが強制されるため、コマンド自体はシンプルです。以下は、私が /var/www/html ディレクトリを保護するために使用しているbashスクリプトです:
#!/bin/bash
# 不変性を備えたバックアップスクリプト
SOURCE="/var/www/html"
DEST="s3-backup:my-immutable-backups/web-files/$(date +%Y-%m-%d)"
rclone copy $SOURCE $DEST \
--s3-no-check-bucket \
--verbose \
--transfers 8 \
--checkers 16
最終テスト:動作確認
バックアップ戦略は、テストするまではただの理論に過ぎません。アップロード完了直後にファイルを削除してみて、ポリシーが有効であることを確認してください。
# ロックされたファイルの削除を試行
aws s3 rm s3://my-immutable-backups/web-files/2024-05-10/index.php
設定が正しければ、次のようなエラーが表示されます:An error occurred (AccessDenied) when calling the DeleteObject operation。このエラーこそが最大の安心材料です。有効な認証情報を持っていても、データが不可侵であることを証明しています。
現場からの教訓
不変バックアップを大規模に運用することで、ドキュメントにはあまり書かれていないいくつかのニュアンスが見えてきました。
ストレージコストの管理
不変であるということは、スペースを節約するために古いデータを削除(プルーニング)できないことを意味します。毎日10GBのデータベースダンプをアップロードすれば、月末には300GB分のストレージ料金が発生します。これを管理するため、私はS3ライフサイクルポリシーを使用しています。ロックされたオブジェクトを7日後に S3 Glacier Instant Retrieval に移行するようにしました。これにより、ストレージ料金を$0.023/GBから約$0.004/GBへと、長期保持コストを大幅に80%削減できました。
オブジェクトバージョンの取り扱い
不変性はファイルの特定のバージョンに適用されます。バックアップの新しいバージョンをアップロードすると、古いバージョンは非表示になりますが、容量を消費し続け、ロックされたまま残ります。リカバリ用スクリプトがバージョンを認識できるようにしておく必要がありますが、通常のプル操作ではS3はデフォルトで最新バージョンを提供します。
時刻同期の重要性
NTPを使用して、Linuxサーバーの時刻を正確に保ってください。S3は時間ベースのリクエスト署名を使用します。サーバーの時計が5分以上ずれると、AWSはリクエストを拒否します。さらに重要なのは、保持期間は時間に基づいているため、ローカルのログとクラウドのメタデータを完全に一致させておきたいという点です。
最後に
不変バックアップに切り替えたことで、心の平穏が劇的に向上しました。流出したAPIキーによってリカバリポイントが破壊される心配がないというのは、決定的な違いです。設定には1時間もかかりませんが、それによって数ヶ月に及ぶ復旧作業、あるいはビジネスそのものを救うことができるのです。もし、まだ標準的な rsync や基本的なS3アップロードを使っているなら、今すぐ不変レイヤーを追加することをお勧めします。
