Cloud Storageのバケットをうっかり爆破した
この記事はしおだいふく Advent Calendar 2020 10日目の記事です。 10日続いてよかったけどそろそろ力尽きそうです。
今日はひさしぶりに一発やらかして冷汗かいたので反省文を書きます。
悪かったな、実にすまない。
SSGしたWebサイトの配信に使っているCloud Storageのバケットがありました。
CI/CD環境から自動デプロイをする際に過去にデプロイしたファイルが残っていると邪魔なので、 いったんバケットの中身を全部消してから新しいファイルをアップロードしようと思って
$ gsutil -m rm -r gs://<バケット名>
を実行しました。
詳しい方ならお察しいただけると思いますが、このコマンドを実行するとバケットの中身どころかバケットそのものが抹消されます。 CDNとの接続がぶっ壊れたり、バケット名がドメイン形式だったために独力での復旧ができず1、非常にまずい状況に陥りました。
本格運用を開始する前のテスト環境だったのが不幸中の幸いでした。
今回の件からお前が得る教訓は...
やらかしたあとで振り返ってみれば油断以外の何物でもないのですが、どうしてやらかしてしまったのかを正直に記録しておきます。
gsutil helpはちゃんと読め
そもそもなんでこんなコマンドを気軽に打ってしまったかというと、
$ gsutil -m rm -r gs://<バケット名>/<適当なパス>/
というようなコマンドがそれまでいい感じに動いていたからなんですね。 パスなんかとっちゃっても動くでしょ~と思ったのが大きな誤りでした。
gsutil help rm
を打つとコマンドの詳細な使い方がでてくるのですが、
それがむちゃくちゃ長くてちゃんと読まなかったのもよくないところです。
しかしよくみると、一瞬で流れていく上の方にまさに今回の話が書いてあります。
Running gsutil rm -r on a bucket will delete all versions of all objects in the bucket, and then delete the bucket:
gsutil rm -r gs://bucket
If you want to delete all objects in the bucket, but not the bucket itself, this command will work:
gsutil rm gs://bucket/**
というわけで、 gsutil rm -r
はシンプルにバケット名を指定するとバケットもろとも消してしまいますので注意してください。
Firebase 管理者に気をつけろ
そして本日の油断その2が、「いうてこのサービスアカウントにつけてるCloud Storageの権限、『Storage オブジェクト管理者』だから そんなやばいことはできんでしょ」と思い込んでいたところです。
よくよくみるとこのサービスアカウント、Firebaseへのデプロイも兼ねているので『Firebase 管理者』の権限も持っています。
実はこのFirebase管理者、 storage.buckets.delete
というバケット削除に必要な権限を内包しています。
まぁFirebaseの一部としてStorageが提供されているのでそりゃそうかという話ではあるのですが、 Firebase側から見えないGCPで管理しているバケットやオブジェクトにもパワーを行使してきます。 当たり前ですが、必要ない権限はちゃんと絞らないとダメですね。
ということだ
僕が実行すべきコマンドは
$ gsutil -m rm gs://<バケット名>/**
でした。
環境を復旧し、CI/CDの設定も修正したので今日はもう寝ます。
- ドメイン形式の名前を使う場合は、そのドメインの所有権確認が必要です。↩