「退職者ID」は最強のバックドアである:自動化で封じ込めるIDライフサイクルの鉄則
現場で死線をくぐり抜けてきた人間から一つだけ忠告させてもらう。侵入テストやインシデント対応で見かける「最も安上がりで、かつ最も防ぎやすい」攻撃の入り口は、残存する元社員のアカウントだ。
「退職者のアクセス権削除」を属人的な手作業(チケット駆動や口頭連絡)に依存している組織は、既に敗北していると言っていい。人事システム(HRIS)とID管理システム(IdP)が乖離した瞬間、そこには悪意ある攻撃者が喉から手が出るほど欲しい「正当な権限を持った足場」が出来上がる。
今日は、この「IDの死角」を物理的に消し去るための実装論を叩き込む。
—
なぜ「手動運用」は必ず破綻するのか
攻撃者は、退職者が多い企業を狙う。なぜなら、退職手続きの不備でアカウントが残っている可能性が高いからだ。
彼らは、OSの lastlog やクラウドの IAM Access Advisor を見て、活動がないIDをターゲットにする。IDは生きているが、監視の目からは外れている。ここからVPN経由で社内LANへ横展開(Lateral Movement)し、特権昇格を行う。これが、昨今のランサムウェア被害の定石だ。
これを防ぐ唯一の解は「ソース・オブ・トゥルース(信頼できる唯一の情報源)」である人事システムを起点とした自動デプロビジョニングである。
—
実装:人事システムと連携した即時無効化のメカニズム
理想は SCIM(System for Cross-domain Identity Management)プロトコルだが、小規模な環境やオンプレミスと混在する環境では、Webhookを利用したプッシュ型の自動化が現実的だ。
以下は、人事システム(またはAPI)からのイベントをトリガーに、クラウドのIAMやローカルのLinuxサーバーでアカウントを無効化するPythonの構成例だ。
1. アカウント無効化用のバックエンド処理 (Python)
import os
import subprocess
# セキュリティ上の注意: このスクリプトはIAMロールまたは適切な権限を持つサービスアカウントで実行すること
def disable_user_account(username):
"""
指定されたユーザーを無効化する。
Linux環境であれば、パスワードをロックし、シェルを無効にする。
"""
try:
# パスワードをロックし、ログインシェルを/sbin/nologinに変更
subprocess.run(["sudo", "usermod", "-L", username], check=True)
subprocess.run(["sudo", "usermod", "-s", "/sbin/nologin", username], check=True)
# 実行中のセッションを強制終了
subprocess.run(["sudo", "pkill", "-u", username], check=False)
print(f"INFO: ユーザー {username} のアクセス権を即時無効化しました。")
except subprocess.CalledProcessError as e:
print(f"CRITICAL: ユーザー無効化中にエラーが発生: {e}")
# HRISからのWebhookを受け取るエンドポイント(Flask等)を想定
def handle_termination_event(data):
username = data.get("employee_id")
if username:
disable_user_account(username)
2. クラウドインフラ(AWS IAM)での制御
クラウド環境では、プログラムでの削除よりも「ポリシーの強制的なアタッチ」が安全だ。アカウントを削除すると監査ログが消える可能性があるため、Deny All ポリシーを付与して「存在はするが、何もできない」状態にするのがプロの定石である。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:PrincipalTag/Status": "Terminated"
}
}
}
]
}
※このタグを自動付与するLambda関数を人事システムの退職フラグと連動させるだけで、即座に全権限を剥奪できる。
—
現場で守るべき「監査」の鉄則
自動化を構築したとしても、それが正しく動いているかを確認する「監査ループ」を回さなければ意味がない。
1. 生存確認(Keep-alive)の逆引き:
人事データベースの在籍者リストと、LDAP/Active Directory/IAMの有効アカウントリストを毎日午前2時に突き合わせる(Diffを取る)。差分が出た瞬間にSlack等へアラートを飛ばすこと。
2. OSレベルのハーデニング:
Linuxサーバーであれば、/etc/passwd や /etc/shadow を監視するのではなく、PAM(Pluggable Authentication Modules)レベルで特定グループ以外のアカウントログインを禁止する設計にする。
3. 不要なサービスの停止:
systemctl で telnet, ftp, rlogin 等のレガシープロトコルは即座に停止・アンインストールする。これらはIDの管理がずさんになりがちな古いシステムで頻繁に悪用される。
—
最後に:セキュリティは「性悪説」で設計せよ
「あの人は真面目だったから大丈夫」という甘えが、どれほど多くのエンジニアのキャリアを壊してきたか。退職者IDの管理は、技術的な難易度は高くない。しかし、「人事の退職プロセスと、サーバーのアクセス権管理を直結させる」という組織的な規律が何よりも難しい。
今日紹介したコードは、あくまでトリガーに過ぎない。重要なのは、退職の辞令が出た瞬間、誰の操作も介さず「システムが自動的に扉を閉ざす」仕組みを、君たちが責任を持って設計することだ。
もし今の環境で「退職者の削除は手動です」という答えが返ってきたら、その日のうちに上司に改善案を叩きつけてほしい。それが、プロのエンジニアの仕事というものだ。
コメント