「DELETE FROM users と打って Enter、WHERE id = 123 を打つ前にうっかり実行――月曜朝 9 時、顧客マスタが全部消えた。」 バイブコーディング (vibe coding = AI に書かせて雰囲気で作る開発スタイル) で運用している中堅企業の情シスにとって、データ消失は 「自分は起こさない」と思っている人が起こす タイプの事故です。
2017 年、世界中の開発者が利用する GitLab.com は、たった 1 人のエンジニアの誤操作で本番 PostgreSQL を約 6 時間分消失 させました。さらに同社が用意していた 5 段階のバックアップが全て機能せず、最終的に 6 時間前のスナップショットから復旧する事態となりました。公式 post-mortem (GitLab.com Database Incident) は世界中の情シスで教科書として読まれています。
「バックアップは取っている」「クラウドだから大丈夫」「コマンドは慎重に打つ」――どれも、データ消失の本当の防止策にはなりません。本記事は連載「バイブコーディング危機」第 5 回として、公開報道済 5 事案、AI 生成スクリプトが書かない 6 つの安全機構、バックアップが復旧してくれない 5 シーン、3-2-1 ルールと中堅企業実装、年 1 回 復旧演習の作り方、ハッキング / 操作 / 設計 の起因マトリクス、緊急 5 項目、FAQ までを一次ソース 22 件で整理します。
**連載「バイブコーディング危機」**は、AI で自社システムを開発する中堅企業向けに、専門家不在で起きるリスクを1 本ずつ深掘りしていきます。 第 1 回(概論 + 7 リスク類型 + チェックリスト 10 項目) 第 2 回(SQL Injection の現実 5 パターン) 第 3 回(認可漏れの現実 5 シーン) 第 4 回(江崎グリコ 4 ヶ月 BCP + 財務インパクト)
目次
- GitLab.com 2017 データ消失事案の時系列(公式 post-mortem 引用)
- 公開報道済 データ消失 5 事案
- バイブコーディングが書かない 6 つの安全機構
- バックアップが復旧してくれない 5 シーン
- 3-2-1 ルールと中堅企業実装(NIST SP 800-34 / CISA)
- 年 1 回 本物リストア演習の作り方
- ハッキング / 操作 / 設計の起因マトリクス
- 既存システムの「今すぐ」やる緊急 5 項目
- よくある質問(FAQ 12 問)
- 参考一次ソース
GitLab.com 2017 データ消失事案の時系列(公式 post-mortem 引用)
事案の重要性: 世界最大規模のソースコード管理 SaaS で、たった 1 人のエンジニアの誤操作 (rm -rf) が 本番 PostgreSQL の約 6 時間分のデータ消失 につながりました。さらに 5 段階のバックアップが全て機能しなかった という、「バックアップ取っている」を信じる全ての情シスに対する警告として、過去 10 年で最も重要な公開事案です。
参考: GitLab.com 公式 post-mortem (2017-02-10)
時系列(GitLab 公式 post-mortem より)
| 時刻 (UTC) | 出来事 |
|---|---|
| 2017-01-31 17:00 頃 | サイト負荷急増、スパム対策で IP ブロックを実施 |
| 17:20-21:00 頃 | レプリケーション遅延発生、PostgreSQL secondary が primary に追いつけない |
| 21:00 頃 | エンジニア (team-member-1) が secondary DB を手動再同期で復旧試行 |
| 23:00 頃 | secondary DB が空のまま起動、primary と判別がつかなくなる |
| 23:27 頃 | エンジニアが primary DB と思い込んだ secondary 側で rm -rf data/ を実行、気づいた時には 300GB を 4.5GB まで削除完了 |
| 23:27-翌日 | 全 5 段階のバックアップを順次確認 → 全て機能していないことが判明 |
| 翌 02:00 頃 | 唯一機能していた「staging サーバ向け 6 時間前スナップショット」から復旧開始 |
| 翌 18:14 頃 | サービス再開、6 時間分 (約 5,037 プロジェクト + 707 ユーザー + 5,000 コメント) のデータが永久消失 |
「機能しなかった 5 段階のバックアップ」の構造
GitLab 公式 post-mortem より、実際に機能しなかったバックアップ手段 5 種:
- LVM スナップショット = 24 時間に 1 回しか取得していなかった → 6 時間前のもの
- 通常のバックアップ =
pg_dumpのバージョンミスマッチでサイレント失敗、ファイルサイズが 0 だった - Azure ディスクスナップショット = 当時の DB サーバーでは有効化されていなかった
- S3 バックアップ = S3 バケットが空、原因不明
- レプリカ = 上記の通り、誤操作で削除されたのが「正常な方」
結果: 公式に発表された「設計上 5 重に守られていたデータ」が 1 つも残っていなかった。
この事案から学ぶ 5 つの教訓
- 「バックアップを取っている」と「実際に復旧できる」は全く別問題です
- 複数バックアップでも、全て同時に失敗する可能性があります (検証手順なしでは)
- エンジニアの誤操作は「気を付ける」では防げません、システム側で防ぐ設計が必要です
- 本番 DB へのコマンドは必ず確認 (dry-run / confirm) を挟みます
- 公開 post-mortem は最強の教科書です、自社の同種リスクを必ず洗い出しましょう
重要な注記: GitLab 事案は 熟練エンジニアによる障害対応中の誤操作 であり、「バイブコーディング起因」と断定するものではありません。中堅企業のバイブコーディング環境では 同種の「動くつもりのコマンドが本番で破壊する」現象がより低い規模で頻繁に起きる確率が高い、という観点で参照します。
AI ASSESSMENT
PoC の前に「そもそも使えるか」を30分で見極めませんか?
情シス部門の稟議書作成をサポートする無料の30分壁打ち。ROI 試算シート・失敗要因チェックリストをその場で共有します。
公開報道済 データ消失 5 事案
ここでは、メディア / 公式 post-mortem / 規制当局公表で確認できる 公開報道済の大規模データ消失 5 件 を整理します。
事案 1: GitLab.com 2017 本番 DB 消失(上記詳細)
- 消失規模: 6 時間分 / 約 5,037 プロジェクト / 707 ユーザー / 5,000 コメント
- 直接原因:
rm -rf誤実行 + 5 段階バックアップ全て不全 - 出典: GitLab.com 公式 post-mortem
事案 2: 全国銀行データ通信システム (全銀ネット) 2023 メモリテーブル破損
概要: 2023 年 10 月 10 日から 11 日にかけて、全銀ネットで 他行宛振込ができない障害。三菱 UFJ・りそな・あおぞらなど 複数行で計約 500 万件 の取引に影響。
技術的原因 (NTT データ公式報告書より): 中継コンピュータシステム (RC23) アップデートに伴うメモリテーブル破損。前日夜のメンテナンスで導入したパッチが想定外条件で動作。メモリ上のテーブル (索引データ) が壊れ、振込処理時の参照が異常終了。
結果:
- 全銀協 / NTT データ公式報告書発表
- 金融庁による検査・行政処分
- 「中央集権型インフラの SPOF (Single Point of Failure)」 リスク再認識
データ消失観点での教訓: 「メモリ上のデータ構造破損」はバックアップでも復旧できないため、システム稼働中の整合性確認 が決定打となります。
出典:
事案 3: Salesforce 2019 Pardot/Marketing Cloud 権限事故
概要: 2019 年 5 月、Salesforce の Pardot (旧 Marketing Cloud) 顧客の 全データに対し、組織内全ユーザーが read/write/edit 権限を持つ状態 が誤デプロイで発生。
技術的原因 (Salesforce 公式アップデートより): スクリプトの誤デプロイで全顧客の権限設定が「フルアクセス」に書き換わった。結果として誰でも他人のデータを変更・削除可能 な状態が複数時間継続。
結果:
- Salesforce が世界中の Pardot 顧客のサービスを一時停止 (全顧客がオフライン)
- 復旧に 約 15 時間、その後段階的な機能復旧
- 顧客は 自社管理画面で「何が起きたか」を確認できる よう Salesforce が監査ログを提供
データ消失観点での教訓: 「権限事故」は直接データを消すわけではありませんが、誰でもデータ削除できる状態 になっていた点でデータ消失リスクと同義です。スクリプトの誤デプロイは dry-run / staging テスト が無いと避けられません。
出典:
事案 4: マイナンバー 公金受取口座 別人紐付け事案(2023)
概要: 2023 年 5 月、デジタル庁が運用するマイナポータルの公金受取口座登録機能で、約 940 件の別人口座が誤って登録されていた ことが判明。
技術的原因 (デジタル庁公表より): 登録手続きを補助する自治体窓口で、前のユーザーのセッション情報が次のユーザーに引き継がれていた。具体的には、共用 PC のブラウザでログアウトしないまま次の人の口座情報を登録すると、前のユーザーの公金受取口座として上書きされる構造。
結果:
- 該当口座の修正対応
- デジタル庁による再発防止策発表 (セッション分離 / 操作完了確認画面の追加)
- マイナンバー制度全体への信頼低下
データ消失観点での教訓: 「正しいデータが正しい場所に紐づかない」論理的データ消失 も、物理的削除と同じ深刻さです。AI 生成コードでも セッション管理 / ユーザー識別 / 操作確認の 3 セット が抜けると同種事象が発生します。
出典:
事案 5: Google Cloud UniSuper 事案(2024-05)
概要: 2024 年 5 月、豪 大手年金基金 UniSuper の Google Cloud 上のプライベートクラウド (約 62 万人 / 1,250 億豪ドル相当の年金資産管理) が 「内部設定エラーにより削除された」。約 2 週間サービス停止 → 別 region のバックアップから復旧。
技術的原因 (Google Cloud + UniSuper 共同発表より): Google Cloud 側の「Cloud VMware Engine」プロビジョニング中に 「unprecedented sequence of events (前例のない一連の事象)」 で UniSuper のプライベートクラウド全体が削除された。Google Cloud で前例のない事案 と公式発表。
結果:
- UniSuper はバックアップを 複数の cloud provider (Google + 別 provider) で取っていたため復旧可能だった
- Google Cloud CEO Thomas Kurian と UniSuper CEO Peter Chun が共同声明発表
- 全業界に「クラウド + クロスプロバイダーバックアップ」の重要性を周知
データ消失観点での教訓: クラウドプロバイダー自体の障害でデータが消える ケースは現実に存在します。「Google Cloud / AWS / Azure に預けている = 安全」は誤解です。3-2-1 ルールの「2 種類のメディア」「1 つはオフサイト」を本気で守る必要があります。
出典:
5 件の共通パターン
| 共通点 | 該当事案 |
|---|---|
| 誤操作 (人為ミス) が直接原因 | GitLab 2017 / マイナンバー 2023 |
| アップデート / デプロイ直後の障害 | 全銀ネット 2023 / Salesforce 2019 |
| 「自動化された保護機構」が機能せず | GitLab (5 段階バックアップ全不全) |
| クラウド事業者側の障害 | Google Cloud UniSuper 2024 |
| バックアップで完全復旧できなかった | GitLab (6 時間分消失) / マイナンバー (論理的破損) |
中堅企業のバイブコーディング環境では、これら 5 つすべての構造的要因が同時成立しやすくなります。
バイブコーディングが書かない 6 つの安全機構
AI に「データ削除スクリプトを書いて」と頼むと、動きますがほぼ確実に安全機構を書きません。以下 6 つは自社の全 destructive 操作 (DELETE / DROP / TRUNCATE / UPDATE / rm -rf) で必須実装としてください。
安全機構 1: dry-run mode(実行前にプレビュー)
目的: 「これから何を削除するか」を実行前に表示し、確認後に本実行します。
脆弱なコード(AI 初期生成)
def delete_inactive_users():
db.execute("DELETE FROM users WHERE last_login < NOW() - INTERVAL '1 year'")
db.commit()
print("Deleted inactive users")
安全機構あり
def delete_inactive_users(dry_run=True):
candidates = db.execute(
"SELECT id, email FROM users WHERE last_login < NOW() - INTERVAL '1 year'"
).fetchall()
print(f"[DRY-RUN]" if dry_run else "[EXECUTE]")
print(f" {len(candidates)} users will be deleted")
for user in candidates[:10]:
print(f" - {user.email} (id={user.id})")
if len(candidates) > 10:
print(f" ... and {len(candidates) - 10} more")
if not dry_run:
db.execute("DELETE FROM users WHERE last_login < NOW() - INTERVAL '1 year'")
db.commit()
print(f" Deleted {len(candidates)} users")
# 実行時は必ず dry-run から
# python script.py --dry-run # 1 回目
# python script.py # 2 回目(実行)
運用ルール: 本番環境では 必ず dry-run を 1 回挟みます。CI / CD でも --dry-run を default にし、--execute フラグでのみ本実行する設計にします。
安全機構 2: interactive confirm(実行前に y/N 確認)
目的: ターミナルで操作する場合、最後の砦として人間の意思を確認します。
def confirm(message):
answer = input(f"{message} (yes / no): ").strip().lower()
if answer != "yes":
print("Aborted.")
sys.exit(1)
def delete_inactive_users():
candidates_count = db.execute(
"SELECT COUNT(*) FROM users WHERE last_login < NOW() - INTERVAL '1 year'"
).scalar()
print(f"About to delete {candidates_count} users from PRODUCTION database.")
confirm("Are you absolutely sure?")
confirm("Type 'yes' again to confirm (this is irreversible)")
db.execute("DELETE FROM users WHERE last_login < NOW() - INTERVAL '1 year'")
db.commit()
ポイント:
y/Yでなくyesフルタイプを要求(誤入力防止)- 重大操作は 2 段階確認
- 件数が想定範囲外(例: 10 万件超)なら自動 abort
安全機構 3: transaction + rollback(実行後の確認まで commit しない)
目的: 削除実行 → 結果確認 → 問題なければ commit、想定外なら rollback します。
def delete_inactive_users():
with db.begin() as tx: # BEGIN TRANSACTION
result = tx.execute(
"DELETE FROM users WHERE last_login < NOW() - INTERVAL '1 year'"
)
deleted_count = result.rowcount
print(f"DELETED {deleted_count} rows (not yet committed)")
print(f"Remaining users: {tx.execute('SELECT COUNT(*) FROM users').scalar()}")
confirm("Commit this transaction?")
# ここで confirm すれば commit、abort なら rollback
# with ブロックを抜けると自動 commit
ポイント:
- 削除直後に 件数 + 残データ件数を表示 します
- 想定外(10 倍多い / 10 倍少ない)なら ctrl+C で rollback します
- 本番 DB は必ず transaction で囲みます
安全機構 4: audit log(操作前後の状態を別 table に記録)
目的: 何が・誰が・いつ・何件削除したか を後から追えるようにします。
def delete_inactive_users(operator):
candidates = db.execute(
"SELECT id, email, last_login FROM users WHERE last_login < NOW() - INTERVAL '1 year'"
).fetchall()
# 1. 削除前にスナップショットを別 table に保存
db.execute(
"INSERT INTO audit_user_deletions (user_id, email, last_login, operator, deleted_at) "
"SELECT id, email, last_login, %s, NOW() "
"FROM users WHERE last_login < NOW() - INTERVAL '1 year'",
[operator]
)
# 2. 本削除
db.execute("DELETE FROM users WHERE last_login < NOW() - INTERVAL '1 year'")
db.commit()
# 3. ログに記録
logger.info(f"Operator={operator} deleted {len(candidates)} inactive users")
保管期間: 監査ログは 最低 1 年、可能なら 7 年 保管します。ランサム / 内部不正 / 訴訟対応で証拠となります。
安全機構 5: backup verify(操作前にバックアップが復旧可能か確認)
目的: 削除前に「最新バックアップが実際に復旧できる」ことを確認します。
def assert_backup_restorable():
latest_backup = get_latest_backup()
if latest_backup.age > timedelta(hours=24):
raise Exception(f"Latest backup is too old: {latest_backup.age}")
if latest_backup.size < 100 * 1024 * 1024: # 100 MB 未満は破損疑い
raise Exception(f"Latest backup is suspiciously small: {latest_backup.size}")
# ステージング環境にリストアして row count 確認
staging_db = restore_to_staging(latest_backup)
if staging_db.user_count < db.user_count * 0.9: # 10% 以上差があれば中断
raise Exception("Restore count mismatch")
print("Backup is verified as restorable")
def delete_inactive_users():
assert_backup_restorable() # 削除前に必ず実行
# ... 削除処理 ...
運用: 本番削除前のスクリプトに 必ず backup verify を組み込みます。月次でも自動実行し、日常的に検証します。
安全機構 6: soft delete(物理削除でなく flag 更新)
目的: 復旧可能性を物理レイヤで担保し、deleted_at で論理削除します。
# スキーマに deleted_at カラムを追加
# ALTER TABLE users ADD COLUMN deleted_at TIMESTAMP NULL;
def delete_inactive_users():
# 物理削除でなく soft delete
db.execute(
"UPDATE users SET deleted_at = NOW() "
"WHERE last_login < NOW() - INTERVAL '1 year' AND deleted_at IS NULL"
)
db.commit()
# 通常 query は deleted_at IS NULL でフィルタ
def get_active_users():
return db.execute("SELECT * FROM users WHERE deleted_at IS NULL").fetchall()
# 別 cron で 30 日後に物理削除(撤回期間あり)
def physical_delete_old_soft_deleted():
db.execute(
"DELETE FROM users "
"WHERE deleted_at < NOW() - INTERVAL '30 days'"
)
db.commit()
ポイント:
- soft delete なら 30 日以内なら復旧可能です (UPDATE で
deleted_at = NULL) - ただし 個情法上の「削除権 (right to erasure)」対応 では物理削除が必要な場合があるため、設計時に法務と合意します
deleted_atカラムに index が必須です (フィルタが遅くなるため)
6 機構の優先順位(中堅企業向け)
| 優先 | 機構 | 実装コスト | 効果 |
|---|---|---|---|
| 1 | transaction + rollback | 低(数行追加) | 即時誤操作復旧 |
| 2 | dry-run mode | 中(フラグ + 表示処理) | 削除前に想定確認 |
| 3 | interactive confirm | 低(input 関数) | 最後の砦 |
| 4 | soft delete | 中(スキーマ変更 + query 変更) | 30 日復旧期間 |
| 5 | audit log | 中(別 table + INSERT) | 事後追跡可能 |
| 6 | backup verify | 高(リストア検証ロジック) | 真の保険 |
優先 1-3 は全 destructive 操作で必須、4-5 はビジネス重要度 high な table、6 は四半期に 1 回の運用 routine とします。
バックアップが復旧してくれない 5 シーン
「バックアップ取っている = 安全」は最大の誤解です。実際に復旧できないシーンを 5 つ整理します。
シーン 1: バックアップ自体が取れていない(cron 失敗 / disk full)
典型: 1 ヶ月前から cron が失敗していたのに、誰も気づいていなかったケースです。pg_dump のログを誰も見ておらず、disk full で write 失敗もサイレントになります。
対策:
- バックアップ成功通知を Slack / メール に送信、3 日連続で来なければアラート
- バックアップサイズが前日比 ±20% を超えたらアラート
- 監視ツール (Mackerel / Datadog) で「バックアップファイルの mtime」を監視
シーン 2: バックアップは取れているが、リストアできない(破損 / フォーマット不整合)
典型: pg_dump の出力形式とリストア時の PostgreSQL バージョンが違う、文字コードが違う、ストレージ転送中にビット欠落、といったケースです。
対策:
- 月次で 実際にリストアテスト (ステージング環境にフルリストア)
- 復旧時間を計測、想定 RTO 内に収まるか確認
- 失敗したらアラート → 緊急対応
シーン 3: バックアップが暗号化されているが鍵を紛失(GitOps + Secret 管理失敗)
典型: バックアップは暗号化していて安全ですが、暗号化鍵を保管している S3 バケットが消えた / 担当者退職で誰も鍵を持っていない、というケースです。
対策:
- 暗号化鍵は 最低 2 名・3 拠点 (本社 / 物理金庫 / クラウド KMS) に保管
- 鍵のローテーション手順を文書化、年 1 回演習
- AWS KMS / GCP KMS / Azure Key Vault 等の マネージド鍵管理サービス を使う
シーン 4: バックアップが古すぎる(取得頻度が業務 RPO を超えている)
典型: 月 1 回しかバックアップしていないシステムで月末に消失すると、1 ヶ月分のデータ消失となります。
対策:
- 業務影響評価 (BIA) を実施、各システムの RPO を経営層合意で確定
- 推奨頻度: 重要 DB は 1-4 時間、社内システムは日次
- WAL アーカイブ (PostgreSQL) / binlog (MySQL) で 連続バックアップ を実装
シーン 5: バックアップがランサムウェアで暗号化された
典型: ランサム感染で本番 DB が暗号化され、バックアップサーバも同じネットワークにあったため一緒に暗号化された、というケースです。
対策:
- オフラインバックアップ (テープ / 別アカウントの cloud) を 1 つ持つ
- WORM (Write Once Read Many) ストレージ (S3 Object Lock / Azure Immutable Blob) を採用
- バックアップサーバ自体への 書き込みアクセスを最小限の IAM ロール に限定
5 シーンの優先対応
| シーン | 発生頻度 | 対策コスト | 優先 |
|---|---|---|---|
| 1 (cron 失敗) | 高 | 低 | 1 |
| 2 (リストア失敗) | 中 | 中 | 2 |
| 4 (古すぎる) | 中 | 中 | 3 |
| 5 (ランサム) | 中 (増加中) | 高 | 4 |
| 3 (鍵紛失) | 低 | 中 | 5 |
3-2-1 ルールと中堅企業実装(NIST SP 800-34 / CISA)
3-2-1 ルールの定義
データ保護の世界標準として、米国 CISA (Cybersecurity and Infrastructure Security Agency) や NIST が推奨する 3-2-1 ルール:
- 3 つのコピー(本番 + バックアップ × 2)
- 2 種類の異なるメディア / プロバイダー
- 1 つはオフサイト(地理的・論理的に分離)
参考: CISA「Data Backup Options」 / NIST SP 800-34 Rev 1
中堅企業実装パターン
パターン A: クラウド中心 (典型的 SaaS / EC)
| コピー | 場所 | 種類 |
|---|---|---|
| #1 (本番) | AWS RDS Tokyo region | SSD / 同期レプリカ |
| #2 (バックアップ) | AWS S3 Tokyo region | オブジェクトストレージ / 暗号化 |
| #3 (オフサイト) | AWS S3 Osaka region or 別 cloud provider | バージョニング ON |
コスト: 月 5-20 万円(容量・転送量による)
パターン B: ハイブリッド (オンプレ + クラウド)
| コピー | 場所 | 種類 |
|---|---|---|
| #1 (本番) | 社内データセンター | RAID 10 / 同期レプリカ |
| #2 (バックアップ) | 社内テープライブラリ | LTO テープ / 物理金庫 |
| #3 (オフサイト) | AWS S3 Glacier or Azure Cool Blob | 暗号化 / 月 1 回同期 |
コスト: 初期 100-500 万円、運用月 3-10 万円
パターン C: ランサム特化 (3-2-1-1-0)
最新の拡張版として 3-2-1-1-0 があります:
- 3 つのコピー / 2 種類のメディア / 1 つはオフサイト
- +1: 1 つは オフライン or イミュータブル (改変不可)
- +0: 復旧時のエラーは 0 件(リストアテスト必須)
中堅企業向けには パターン A + S3 Object Lock で実質的に 3-2-1-1 を達成し、年 1 回演習で 0 を確認します。
バックアップ運用の必須 5 チェック
- バックアップ取得通知が Slack / メールに届く(毎日)
- バックアップサイズの推移グラフがある(週次レビュー)
- 月次でリストアテスト ステージング環境で実施
- オフサイトバックアップが暗号化済 + 鍵管理プロセス 文書化
- 年 1 回 災害復旧演習(DR Drill)実施 + 振り返り
年 1 回 本物リストア演習の作り方
机上 BCP は 実機で動かさないと意味がありません。年 1 回、本物のリストア演習を必ず実施します。
演習設計(中堅企業向け 6 時間版)
事前準備 (実施 1 週間前)
- 演習日時の決定 (土日 or 平日夜推奨)
- 参加者の役割分担 (情シス / 関連部署 / 経営層オブザーバー)
- ステージング環境のクリア
- 想定シナリオ作成 (例: 「金曜 23:00 にランサム感染で全本番 DB 暗号化、現時点で月曜朝 9 時から事業継続が必要」)
演習当日(6 時間構成)
| 時間 | 内容 |
|---|---|
| 00:00-00:30 | 開始、シナリオ説明、初動チーム編成 |
| 00:30-02:00 | バックアップ取得元の特定、リストア開始 |
| 02:00-04:00 | リストア進行、データ整合性確認 |
| 04:00-05:00 | アプリ起動 + smoke test (ログイン / データ表示 / 主要操作) |
| 05:00-06:00 | 振り返り会議、課題抽出、BCP 改訂点リスト化 |
演習後(実施 1 週間以内)
- 振り返りレポート作成
- 課題チケット化 (Issue / Jira)
- BCP 文書改訂 (A4 1 枚 + 詳細版)
- 経営層への報告
演習で必ず計測する 7 指標
- 検知から初動チーム編成までの時間 (目標: 15 分以内)
- バックアップ取得元特定の時間 (目標: 10 分以内)
- リストア完了までの時間 (目標: RTO 内)
- データ整合性確認の所要時間 (目標: 30 分以内)
- アプリ smoke test の合格率 (目標: 100%)
- チームメンバーの障害手順理解度 (アンケート、目標: 8/10 以上)
- BCP 改訂候補項目数 (改善余地がない演習は意味なし、目標: 5-15 件)
演習を「やらない」リスク
- 計算上の RTO と現実の復旧時間が 数倍以上ズレます
- バックアップが「ある」と「使える」の差が 本番事故で初めて顕在化します
- インシデント時に 誰が何をするか が不明になり、対応の混乱で被害が拡大します
- 経営層が 「うちは大丈夫」 と誤認し、必要な投資が承認されません
「演習で 1 回でも実際に動いたか」が、BCP の本気度を測る唯一の基準です。
ハッキング / 操作 / 設計の起因マトリクス
データ消失の起因を 3 分類で整理します。それぞれの対策ベクトルが異なります。
起因別 統計(Verizon DBIR / IPA 集計より概観)
| 起因 | 全体割合 (概観) | 中堅企業での頻度 | 代表事案 |
|---|---|---|---|
| 操作起因 (人為ミス) | 30-50% | 高 | GitLab 2017 / マイナンバー 2023 |
| 設計起因 (バグ / 設定ミス) | 20-40% | 高 (バイブコーディングで急増) | 全銀ネット 2023 / Salesforce 2019 |
| ハッキング起因 (ランサム / 内部不正) | 10-30% | 中 (増加中) | 各種ランサム事案 |
| インフラ起因 (cloud 障害 / 災害) | 5-15% | 低 | Google Cloud UniSuper 2024 |
参考: Verizon DBIR / IPA 情報セキュリティ 10 大脅威
起因別 対策ベクトル
操作起因への対策
- dry-run / confirm / transaction (本記事 安全機構 1-3)
- 本番作業の 2 名体制 (1 名がコマンド入力、1 名が画面確認)
- 本番作業時間の 記録 + 事前申請ワークフロー
- ChatOps / IaC (Infrastructure as Code) で 手作業を最小化
設計起因への対策
- コードレビュー必須 (AI 生成コードも例外なし)
- テストカバレッジ (単体 / 統合 / E2E)
- カナリアリリース (10% トラフィックで先行確認)
- ロールバック手順 をデプロイ手順とセットで整備
ハッキング起因への対策
- EDR / MDR (CrowdStrike / Defender / SentinelOne)
- バックアップの オフライン保管 (テープ / Object Lock)
- 認証の MFA 必須化
- インシデント対応訓練 (連載第 6 回で深堀)
インフラ起因への対策
- マルチ region 構成
- マルチ cloud provider バックアップ (UniSuper パターン)
- DR (Disaster Recovery) サイト 設計
- cloud provider の SLA + 補償条件理解
起因別 投資配分の目安(中堅企業)
| 起因 | 投資配分 | 投資内訳 |
|---|---|---|
| 操作起因 | 40% | スクリプト改善 + 2 名体制 + 教育 |
| 設計起因 | 30% | テスト整備 + コードレビュー + IaC |
| ハッキング起因 | 20% | EDR + バックアップ強化 + MFA |
| インフラ起因 | 10% | マルチ region + DR 設計 |
操作起因 + 設計起因が 70% = バイブコーディング起因リスクの本丸です。
既存システムの「今すぐ」やる緊急 5 項目
「90 日プランは分かった、でも来週何をすればよいのか」という経営者向けに、今週中にやる 5 項目を整理します:
緊急 1: 最新バックアップが取れているか + サイズ確認 (30 分)
# 最新バックアップの mtime + サイズ確認
ls -la /backup/db/ | head -5
# バックアップサイズが前日と大きく違う(±20% 超え)= 異常
- 取れていない → 即時 cron 設定 + Slack 通知導入
- サイズ異常 → 内容を確認し、空ファイル / 破損なら緊急対応
緊急 2: ステージング環境にリストアテスト (2-3h)
- 最新バックアップを clean なステージング DB にリストアします
- アプリ起動 + ログイン + 主要画面表示を確認します
- データ件数を本番と比較 し、欠損があれば緊急対応します
緊急 3: 本番 DB への destructive コマンド禁止 ガード追加 (1-2h)
# .bashrc / .zshrc に追加 (本番サーバの全ユーザー)
alias psql_prod="echo 'WARNING: Use psql_prod_safe instead' && false"
function psql_prod_safe() {
echo "Connecting to PRODUCTION DB. All DELETE/DROP/TRUNCATE will require confirmation."
psql -h prod-db.internal -U readonly_user "$@" # まず read-only 接続
}
- 本番 DB への直接 SQL 実行を デフォルト禁止 / read-only 接続を強制
- 書き込みが必要な場合のみ、明示的に admin user で接続 (audit log 必須)
緊急 4: 全 destructive スクリプトに dry-run / confirm を追加 (2-4h)
- 既存の DELETE / DROP / TRUNCATE /
rm -rfスクリプトを grep で抽出 - 最低 dry-run + confirm を全スクリプトに追加(本記事 安全機構 1-2)
- CI / CD でも
--dry-runを default に、--executeフラグでのみ本実行
緊急 5: バックアップ通知を Slack に飛ばす (30 分)
# 既存の cron 末尾に通知を追加
0 3 * * * pg_dump -U postgres mydb | gzip > /backup/db/mydb-$(date +\%Y\%m\%d).sql.gz && \
curl -X POST -H 'Content-type: application/json' \
--data '{"text":"Backup OK: '$(date)' '$(ls -lh /backup/db/mydb-$(date +%Y%m%d).sql.gz | awk "{print \$5}")'"}' \
https://hooks.slack.com/services/YOUR/WEBHOOK/URL
- 毎日バックアップ成功通知が Slack に届きます
- 3 日連続で来なければ即時調査します
5 項目で見つかったら、72h 以内にやる
- バックアップ取得不能 → 即時 cron + 監視設定
- リストア不能 → SIer / 外部 CTO 緊急相談
- destructive コマンド 危険状態 → read-only 接続 + 2 名体制ルール
- dry-run なし → 全スクリプトに即時追加
- バックアップ通知なし → Slack webhook 設定
よくある質問(FAQ 12 問)
Q1. soft delete と物理削除、どちらが正解でしょうか?
A. 両方併用が現実解です。デフォルト soft delete (deleted_at) とし、30 日経過後に物理削除する cron を別途用意します。ただし 個情法上の削除権 (right to erasure) や 保管期限超過データ は物理削除が必要なため、設計時に法務と合意します。
Q2. AI に「delete スクリプト書いて」と頼んだら何が抜けやすいでしょうか?
A. 圧倒的に (1) dry-run、(2) confirm、(3) transaction の 3 セット です。AI は「動く」コードを優先するため、安全機構は明示的に「dry-run / confirm / transaction を含めて」と指示しないと抜けてしまいます。
Q3. バックアップを世代管理する場合、何世代が中堅企業の標準でしょうか?
A. 「7-30-365 ルール」が標準です:
- 過去 7 日: 日次フル
- 過去 30 日: 週次フル + 日次差分
- 過去 365 日: 月次フル
- 法的保管義務がある場合: 7 年 (税法 / 個情法)
Q4. クラウド DB (AWS RDS / GCP Cloud SQL / Azure Database) は自動バックアップで十分でしょうか?
A. 自動バックアップは「最初の保険」であり、3-2-1 ルールには不十分です。AWS RDS の自動バックアップは同 region 内に保管されるため、region 障害 / アカウント侵害で消える可能性があります。別 region or 別 cloud provider への手動バックアップ を月 1 回でも実施します。
Q5. ランサムに耐えるバックアップの最低構成はどうすればよいでしょうか?
A. オフライン or イミュータブル ストレージ を 1 つ含めます。具体的には以下のとおりです:
- S3 Object Lock (Compliance Mode)
- Azure Immutable Blob
- LTO テープ (物理金庫)
- 別アカウント / 別組織の cloud (IAM 分離)
「同じネットワーク + 同じ IAM」にあるバックアップは ランサムで一緒に暗号化される 確率が高くなります。
Q6. リストアテストはステージング環境でやって意味があるのでしょうか?
A. 意味があります。ただし本番と同等構成が前提です。本番が PostgreSQL 16 / 100GB なら、ステージングも同じにします。サイズが 1GB の clean DB にリストアして「動いた」では、本番事故時の所要時間が予測できません。
Q7. データ消失が発覚した場合、すぐ復旧と原因調査のどちらが先でしょうか?
A. 影響が拡大している場合は復旧優先、止まっているなら原因調査優先です。判断基準は以下のとおりです:
- 顧客影響 + 進行中: 即時復旧 (止血)
- 進行停止 + 内部影響のみ: 原因調査 + 全関係者通知 + 影響範囲特定 → 復旧手順を計画してから実行
慌てて復旧して、さらに被害拡大、は典型パターンです。
Q8. データ消失で個情法上の対応はどうすればよいでしょうか?
A. 改正個人情報保護法 (2022 年 4 月施行) で、個人データの漏えい / 滅失 / 毀損が発生した場合は以下のとおりです:
- 速やかに個人情報保護委員会に 速報 (3-5 日以内目安)
- 詳細を 確報 (30 日以内、悪意ある第三者によるものは 60 日以内)
- 本人通知 (連絡可能な場合)
「滅失」にデータ消失も含まれるため、対応漏れは行政指導の対象です。参考: 個人情報保護委員会
Q9. データ消失からの復旧後、再発防止策で必ずやるべきことは何でしょうか?
A. 以下の 7 項目です:
- 公式 incident report 作成 (社内 + 必要に応じ顧客向け)
- 該当スクリプトの dry-run / confirm 追加
- 本番作業ワークフロー見直し (2 名体制等)
- バックアップ機構の verify テスト全件実施
- BCP 改訂 (実演習結果を反映)
- 同種リスクの全社横展開 (他チームの delete スクリプトも監査)
- 経営層 + 該当チームへの振り返り会議
Q10. AI に「再発防止策を考えて」と聞けば良いのでしょうか?
A. ヒント集として使えますが鵜呑みは禁物です。AI は事案の文脈・組織構造を理解しきれない場合があり、抽象的な「監視を強化する」「テストを書く」で終わってしまいます。人間が業務文脈を加味して具体化 する必要があります。
Q11. データ消失予防の予算配分、中堅企業の目安はどれくらいでしょうか?
A. 年間 IT 予算の 5-10% が目安です:
- バックアップストレージ + 監視: 100-300 万円
- リストア演習 (外部支援): 50-150 万円
- スクリプト改善 + 教育: 100-200 万円
合計年 250-650 万円です。消失リスク (数億円規模) と比べれば極めて安い保険といえます。
Q12. 「データ消失なんて起きない」と思っている経営層をどう説得すればよいでしょうか?
A. 数字 + 公開事案 + 自社シミュレーション の 3 点セットです:
- GitLab / 全銀ネット / UniSuper 等の公開事案を 1 ページに整理
- 「もし自社で起きたら」のシミュレーション (年商 / 業務影響 / 復旧時間)
- 「年 300 万の保険 vs 数億の事故」の ROI
机上で説明 → 90 日プランの予算承認 → 演習で実証 → 経営層が腹落ち、の段階を踏みます。
参考一次ソース
本記事の事実認定で参照した一次ソース一覧です:
GitLab.com 2017 関連
- GitLab.com Database Incident Post-mortem (2017-02-10)
- GitLab.com Real-time Incident Document (2017-01-31)
全銀ネット 2023 関連
Salesforce 2019 関連
マイナンバー 2023 関連
Google Cloud UniSuper 2024 関連
国際標準 / 政府ガイドライン
- NIST SP 800-34 Rev 1 (Contingency Planning)
- NIST SP 800-61 Rev 2 (Computer Security Incident Handling)
- CISA「Data Backup Options」
- 内閣府「事業継続ガイドライン」
- 中小企業庁「中小企業 BCP 策定運用指針」
国内公的機関
統計レポート
クラウド事業者
CWE
- CWE-1265 Unintended Reentrant Invocation of Non-reentrant Code
- CWE-404 Improper Resource Shutdown or Release
まとめ:「バックアップ取っている」を、信じる時代は終わった
本記事の要点を 7 行でまとめます:
- GitLab.com 2017 = 1 人の
rm -rf+ 5 段階バックアップ全不全 で 6 時間データ消失。「複数バックアップ」だけでは守れません - 公開報道済 5 件 (GitLab / 全銀 / Salesforce / マイナンバー / UniSuper) は 操作 / 設計 / インフラ 全起因が混在しています
- AI 生成スクリプトが書かない 6 機構 = dry-run / confirm / transaction / audit log / backup verify / soft delete。全 destructive 操作で必須です
- バックアップ復旧失敗 5 シーン (cron 失敗 / リストア破損 / 鍵紛失 / 古すぎ / ランサム暗号化) は 検証していないと顕在化しません
- 3-2-1 ルール + ランサム時代の 3-2-1-1-0 が NIST / CISA 推奨の最低線です
- 年 1 回 本物リストア演習 が BCP の本気度を測る唯一の基準です
- 緊急 5 項目 で今週から動き出せます。年 250-650 万円の保険で数億円リスクを抑制可能です
「動いている」「取っている」「クラウドだから」の 3 つの油断こそが、AI 時代の中堅企業の最大リスクです。
次回(連載第 6 回)は 気づかない 6 ヶ月:ランサムウェアと自社開発 を取り上げ、大阪急性期総合医療センター / 名古屋港の事案から、バイブコーディング環境での検知盲点と中堅 EDR / MDR 選択基準を整理します。
関連記事
- 第 1 回 バイブコーディング危機 概論 + 7 リスク類型 + チェックリスト 10 項目
- 第 2 回 SQL Injection の現実 5 パターン
- 第 3 回 認可漏れの現実 5 シーン
- 第 4 回 サービス停止の財務影響:江崎グリコ 4 ヶ月の教訓
「うちのバックアップ、本当に復旧する?」と思ったら
GXO の バイブコーディング監査 + データ保護設計支援サービス では、中堅企業向けに以下を提供します:
- バックアップ機構の verify テスト (本記事 5 シーンを専門家が代行、3-5 営業日)
- 3-2-1 ルール実装支援 (クラウド / ハイブリッド両構成対応)
- destructive スクリプトの監査 + 6 機構実装 (dry-run / confirm / transaction 等)
- 年 1 回 リストア演習 進行 (シナリオ作成 + 振り返り + BCP 改訂)
- インシデント発生時 緊急対応 (改正個情法 速報 / 確報対応 + 復旧支援)
著者: GXO株式会社 初回公開: 2026 年 5 月 25 日 最終更新: 2026 年 5 月 25 日 連載: バイブコーディング危機 第 5 回(全 20 回)







