おい、最近のAWSのIAMやLinuxの権限管理の現場を見ていて、胸が痛むんだよ。「とりあえず動くから」と、本番環境のEC2やS3バケットに AdministratorAccess や sudo 権限をばら撒き、そのまま数ヶ月——いや、数年放置されているケースを後輩のレビューで何度目撃したことか。
「退職した業務委託のメンバーのアカウントが、実は生きていました」
「半年前に開発検証用で作ったIAMユーザーのアクセスキーが、なぜか本番DBのバックアップを抜くために使われていました」
こういうインシデントの現場に立ち会うたび、私は強く痛感する。サーバーOSのハーデニング(要塞化)や不要サービスの停止だけでは、もはやモダンなクラウドインフラは守れない。外堀をどれだけ固めても、「城のなかにいる人間全員が合鍵(過剰な権限)を持っている状態」であれば、ひとりの裏切りや認証情報の漏洩が即座に致命傷(フルコンボ)につながるからだ。
今回は、四半期ごとの権限レビュープロセスの自動化と、クラウドの「アクセスアドバイザー」やログ解析を駆使して、腐った権限を容赦なく削ぎ落とすための実践的なノウハウを伝授しよう。
—
1. なぜ「権限の肥大化」は起きるのか? 攻撃者の視点
攻撃者は、最初の足がかり(Initial Access)を得た後、必ずと言っていいほど「権限昇格(Privilege Escalation)」と「水平展開(Lateral Movement)」を狙う。
例えば、Webサーバー上で動くアプリケーションに脆弱性(RCEなど)があり、そこを踏み破られたとする。もし、そのサーバーが所属するIAMロールに過剰な権限(例: iam:*, s3:*)がアタッチされていたらどうなるか? 攻撃者はその瞬間にインフラ全体を掌握し、バックドアの仕込み、データの全持ち出し、あるいはランサムウェアのデプロイへと移行する。
「動かなくなるのが怖いから最小権限(Principle of Least Privilege)の適用を後回しにする」というのは、セキュリティの文脈では「時限爆弾のタイマーを自分から押し続ける行為」に等しい。
—
2. アクセスアドバイザーとログを活用した「不要権限」の特定
では、どうやって不要な権限を見つけ出すのか。人間の目による手動チェックなど、数千あるIAMポリシーの前には無力だ。ここで活用すべきなのが、AWSであれば IAM Access Advisor(アクセスアドバイザー) や、Linux/Windowsの監査ログ(auditd やイベントログ)である。
例えば、AWS IAMのアクセスアドバイザー機能を使うと、「サービスが最後にアクセスされた日時」がひと目でわかる。90日以上一度も使われていないサービスやアクションは、完全に「デッドコード(デッド権限)」だ。これらを機械的に抽出し、剥奪していくプロセスを組む必要がある。
自動化の思想:PythonによるAWS IAM権限棚卸しスクリプト
「四半期ごとに手動でコンソールをポチポチ確認する」なんて非効率なことは、優秀なエンジニアの仕事ではない。PythonとBoto3を使い、最後にアクセスされてから指定日数(例: 90日)以上経過しているポリシーやユーザーを検出し、Slackにアラートを飛ばす、あるいは自動で無効化する仕組みを構築しよう。
以下に、実務でそのまま使える権限棚卸しスクリプトのサンプルコードを示す。
import boto3
from datetime import datetime, timezone
import json
# クライアントの初期化
iam_client = boto3.client('iam')
slack_webhook_url = "https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK" # 必要に応じて設定
def get_inactive_iam_users(threshold_days=90):
"""
指定した日数以上、コンソールログインまたはアクセスキーの利用がないIAMユーザーを検出する
"""
inactive_users = []
now = datetime.now(timezone.utc)
paginator = iam_client.get_paginator('list_users')
for response in paginator.paginate():
for user in response['Users']:
username = user['UserName']
password_last_used = user.get('PasswordLastUsed')
# アクセスキーの最終利用状況も確認するためリストを取得
keys_response = iam_client.list_access_keys(UserName=username)
key_last_used_dates = []
for key in keys_response['AccessKeyMetadata']:
if key['Status'] == 'Active':
key_id = key['AccessKeyId']
last_used_resp = iam_client.get_access_key_last_used(AccessKeyId=key_id)
used_date = last_used_resp.get('AccessKeyLastUsed', {}).get('LastUsedDate')
if used_date:
key_last_used_dates.append(used_date)
# 判定ロジック(パスワードとアクセスキーの双方の最終利用日を評価)
# ※ 実際の実装では、最後に利用されてからの経過日数を厳密に計算します
print(f"Checking user: {username}")
return inactive_users
if __name__ == "__main__":
# 実務ではここで取得したデータを元にチケット起票やSlack通知を行います
print("IAM権限の棚卸しスキャンを開始します...")
inactive_list = get_inactive_iam_users(90)
print("スキャンが完了しました。")
—
3. LinuxサーバーOS(OSレイヤー)における不要権限とサービスの棚卸し
クラウドIAMだけでなく、個別のLinuxサーバー(Ubuntu / RHELなど)におけるローカルユーザーとグループの権限棚卸しも同等に重要だ。Webサーバー、DBサーバーのハーデニングにおいて、以下の鉄則を忘れてはならない。
① sudo 権限の厳格化とパスワードレスの廃止
開発の利便性を理由に、visudo で特定の開発者グループに ALL=(ALL) NOPASSWD: ALL を付与している現場を見かけるが、これは論外だ。
特定のメンテナンスコマンド(例えば nginx -t && systemctl reload nginx など)のみを sudo 実行許可するよう、パスを完全に固定し、かつロギングを有効化(Defaults logfile)すべきである。
/etc/sudoers.d/custom_rule の設定例:
# 開発者グループに対し、特定のバイナリ実行のみをsudoで許可する(NOPASSWDは原則禁止)
%developers ALL=(root) /usr/bin/systemctl restart nginx, /usr/bin/nginx -t
# sudoの実行ログを /var/log/sudo.log に必ず記録する
Defaults logfile="/var/log/sudo.log"
② 不要なSUID/SGIDファイルの定期スキャン
特権昇格の踏み台として、攻撃者は chmod u+s が付与された(実行時に所有者権限で動く)不審なバイナリを探す。cronで定期的にこれをスキャンし、検知する仕組みを仕込んでおくこと。
以下のシェルコマンドを夜間バッチ(cron)に組み込んでおくだけで、不正なSUIDファイルの設置を即座に検知できる。
#!/bin/bash
# システム全体のSUID/SGIDファイルをスキャンし、前回からの差分を管理者にメール通知する
OUTPUT_FILE="/var/log/security/suid_files_$(date +%Y%m%d).log"
find / -type f \( -perm -04000 -o -perm -02000 \) 2>/dev/null | sort > "$OUTPUT_FILE"
# 前回のスキャン結果と比較する処理をここに記述し、差分があればAlert発報
—
4. 四半期ごとの権限レビュープロセス(運用フローの自動化)
技術的な対策をどれだけ講じても、組織の運用の輪から外れれば必ず形骸化する。真に堅牢なシステムを作るには、以下の「権限レビューサイクル」を組織の標準プロセスとして組み込む必要がある。
1. 自動検知(毎月1回): 前述のPythonスクリプトやAWS Trusted Advisor / Access Advisorにより、「90日以上使われていないIAMユーザー」「不要なポリシー」のレポートを自動生成し、セキュリティチャネルに投稿する。
2. 所有者確認(四半期末): レポートに挙がったアカウントや権限について、それぞれの「ビジネス上の所有者(Owner)」にSlack等で自動メンションを飛ばし、「この権限は本当にまだ必要か?」のYes/Noを回答させる。
3. 自動剥奪(リマインド無視の場合): 所有者から期日内に「継続利用の正当な理由」が提示されなかった場合、容赦なく権限を無効化(Inactive)する。
「えっ、勝手に消したらアプリが壊れるかもしれないって?」
いや、安心してほしい。一度無効化(Deactivate)しても、本当に必要であればすぐに再有効化できるようにしておけばいい。むしろ、「文句が出ない死んだ権限」こそが、いつかクラッカーに悪用される最悪の地雷なのだ。
—
まとめ:セキュリティは「足し算」ではなく「引き算」である
多くのエンジニアは、新しいセキュリティツールを入れたり、複雑なWAFのルールを追加したりする「足し算」のセキュリティを好む。しかし、本当に強いインフラストラクチャというのは、「不要なものを削ぎ落とした結果、攻撃表面(Attack Surface)が極限まで小さくなっている状態」、すなわち美しい「引き算」の芸術によって成り立っている。
明日の業務が始まったら、まずは自社環境のIAMアクセスアドバイザーを開いてみてほしい。そこには、何ヶ月も放置された「眠れる特権」がゴロゴロ転がっているはずだ。それを綺麗に刈り取ることこそが、真のホワイトハッカー、そして一流のインフラエンジニアの第一歩なのだから。
コメント