インフラエンジニアの皆さん、システム内の構成管理資料や設計書を100%信頼していますでしょうか?
「ドキュメントにこう書いてあるから」「関係者に確認して承諾を得たから」――その前提だけで本番環境のオブジェクトを削除するのは、極めて危険な行為です。
先日、私は本番環境のOracleデータベースにおいて、稼働中の機能が使用しているスキーマを誤って削除するという重大インシデントを引き起こしてしまいました。
幸いにもデータの消失という最悪の事態は免れましたが、システム運用における深い教訓を得ることとなりました。
本記事では、そのインシデントの全貌と原因を隠さず公開するとともに、人の記憶やドキュメントに頼らない、システム的な実証データを用いた2大再発防止策、そしてより安全な運用のための「段階的廃止」のプロセスについて解説します。
インシデントの全貌と原因分析
事の発端は、長年稼働していたシステム内の「機能A」の廃止に伴う、関連リソースのクリーンアップ作業でした。
私は、機能A専用として定義されていたOracleの特定スキーマ(以下、TARGETスキーマ)の削除作業を本番環境で実施しました。
しかし、削除コマンド(DROP USER TARGET_SCHEMA CASCADE;)を実行した直後、別チームから「現在稼働中の機能Bで、データベース接続エラーが多発している」との緊急連絡が入りました。血の気が引く瞬間でした。
根本原因:要件定義・確認フェーズでの盲点
なぜこのような誤削除が起きてしまったのか。原因を調査したところ、以下の3つの問題が重なっていることが判明しました。
構成管理資料(設計書)の記述漏れ
社内で管理されていたシステム全体の構成管理資料には、TARGETスキーマの用途として「機能Aが利用」とのみ記載されており、稼働中の「機能B」でもデータ参照用として利用されている旨の記述が完全に漏れていました。
思い込みによる確認漏れ
ドキュメントの記載を鵜呑みにし、「これは機能A専用のスキーマだ」と思い込んでしまいました。
ステークホルダー確認の不足
機能Aの管理者には削除して問題ないことを事前に確認し承認を得ていましたが、ドキュメントに名前のなかった機能Bの管理者には確認のプロセス自体が行われていませんでした。
「ドキュメントと人の記憶は間違える。信じるべきはシステムの実態(証跡)のみである」というのが、このインシデントから得た最大の教訓です。
不幸中の幸いだった復旧の舞台裏
今回のTARGETスキーマは、幸いにも「機能Bが他スキーマのデータを参照するためだけ」の専用スキーマであ
り、自身の中にテーブル実データ(永続データ)を保持していませんでした。そのため、インポートやポイントインタイムリカバリ(PITR)といった大規模な復旧作業は不要でした。
同名のユーザーを作成し、必要なビューやシノニム、権限(SELECT権限など)を再付与するだけで、速やかにサービスを復旧することができました。もしこれがデータ保持スキーマであれば、大規模なシステム停止に発展していたところでした。
二度と繰り返さないための「変更管理プロセス」刷新
「次は気をつけます」という精神論の再発防止策は、再び同じミスを呼びます。そのため、私たちは人間の記憶や嘘をつくドキュメントを介在させない、仕組みによる変更管理プロセスへとルールを刷新しました。
【対策1】客観的なシステム証跡の取得義務化
スキーマを削除・停止する場合、事前に「対象スキーマが現在全く利用されていない(アクセスがない)こと」を示す、システムから出力した客観的な証跡の添付を必須としました。
【対策2】変更管理プロセスの見直し(承認条件の厳格化)
承認フローにおいて、承認者は申請書にシステム的な証跡(ログやSQLの実行結果)が添付されていない限り、どれだけ「確認済み」と書かれていても絶対に作業を承認しない運用に変更しました。
証跡を取得するための2大技術的アプローチ
では、実際に「スキーマが使われていないこと」を証明するために採用した、具体的な実機での確認方法を2つ紹介します。
アプローチA:dba_users の LAST_LOGIN 列による確認
Oracle 12c以降(11gでも一部機能に制限あり)では、dba_users ビューでユーザーが最後にログインした日時を確認することができます。最も手軽に現状を把握できる方法です。
SET LINESIZE 150
COL USERNAME FOR A20
COL ACCOUNT_STATUS FOR A15
COL LAST_LOGIN FOR A30
SELECT
username,
account_status,
TO_CHAR(last_login, 'YYYY-MM-DD HH24:MI:SS') AS last_login
FROM
dba_users
WHERE
username = 'TARGET_SCHEMA'
ORDER BY
last_login;
※ LAST_LOGIN が長期間(数ヶ月以上)空欄、あるいは過去の日付であれば、使われていない可能性が高いと判断できます。ただし、月次バッチなどで突発的にログインするケースもあるため、これ単体で100%の安全を担保するのではなく、次述の監査設定と組み合わせるのが確実です。
アプローチB:標準監査(audit_trail)による確実なログ取得
対象スキーマへの接続イベントをデータベース層で明示的に記録し、本当にアクセスがないかを「一定期間」監視します。
監査パラメータの確認(DBA権限)
SHOW PARAMETER AUDIT_TRAIL;
-- 値が 'DB' または 'DB,EXTENDED'、'OS' であることを確認します
対象スキーマへの接続を監査対象に設定
AUDIT SESSION BY TARGET_SCHEMA;
-- これにより、対象スキーマがログインを試みるたびに監査ログへ記録されます
監査ログ(dba_audit_trail)の確認SQL
SET LINESIZE 180
COL USERNAME FOR A15
COL TIMESTAMP FOR A20
COL OS_USERNAME FOR A15
COL TERMINAL FOR A15
COL ACTION_NAME FOR A15
SELECT
username,
TO_CHAR(timestamp, 'YYYY-MM-DD HH24:MI:SS') AS timestamp,
os_username,
terminal,
action_name,
returncode
FROM
dba_audit_trail
WHERE
username = 'TARGET_SCHEMA'
ORDER BY
timestamp DESC;
この監査設定を本番環境で最低でも1〜2ヶ月稼働させ、上記の確認SQLでレコードが1件も出力されないことをもって「利用されていない証跡」とします。
最も安全な代替案:「段階的廃止(Gradual Deprecation)」の推奨
今回、システム的な証跡を取得する仕組みを構築しましたが、それでも「年に1回しか走らない超レアな年次バッチ」などの接続までは、1ヶ月程度の監視では補足しきれないリスクが残ります。
そこで、最も安全なアプローチとして強く推奨したいのが、いきなり DROP USER を実行するのではなく、「段階的にアカウントの権限を絞り、様子を見る」という段階的廃止のプロセスです。
ステップ1:アカウントのロック(ACCOUNT LOCK)
まず対象スキーマをロックし、新規のログインを拒否します。これにより、もし未把握の機能からのアクセスがあれば、その瞬間にエラー(ORA-28000)が発生して検知できます。
ALTER USER TARGET_SCHEMA ACCOUNT LOCK;
ステップ2:冷却期間(様子見期間)の確保
ロックした状態で1〜3ヶ月ほどシステムを運用します。もしどこかから悲鳴(エラー報告)が上がれば、即座に ALTER USER … ACCOUNT UNLOCK; で復旧できるため、システムを完全に壊すリスクを最小限に抑えられます。
ステップ3:スキーマの完全削除
冷却期間中に1件のエラーも報告されず、システム監視でも異常が見られないことを確認して初めて、安全にDROP USER TARGET_SCHEMA CASCADE; を実行します。
まとめ:信じるべきは「本番環境の実態」
本番環境における「不要リソースの削除」は、一見すると簡単なメンテナンス作業に思えますが、実は新規構築と同じかそれ以上に高いリスクを伴います。なぜなら、システムは生き物であり、ドキュメントの更新が追いついていないケースが多々あるからです。
今回のインシデントを通じて、私たちは運用のルールを「システムが証明する証跡ベース」へ変革し、さらに「段階的廃止」という安全弁を設けることにしました。
この記事が、同じように古いシステムのクリーンアップやスキーマ廃止を担当するエンジニアの皆さんの身を守る参考になれば幸いです。