【実務・中級編】 クラウド環境におけるIAM権限の過剰付与と特権昇格 – オフェンシブセキュリティ & リバースエンジニアリング防御ガイド

クラウドの「鍵」を盗む者たち:IAM権限昇格の現実と、防衛のための実戦的アプローチ

現場で多くの事故対応を行っていると、必ずと言っていいほど直面するのが「IAM権限の設計ミス」だ。開発者は「とりあえず動くように」と AdministratorAccess を割り当てがちだが、それは強盗に家の全室の合鍵を渡しているのと同じこと。

今日は、攻撃者がクラウド環境でどのように権限昇格を行い、我々エンジニアがそれをどう防ぐべきか、現場の視点で深掘りする。

—

1. 攻撃者が狙う「盲点」:IAM権限昇格のロジック

攻撃者は、侵害したEC2インスタンスやLambda関数に割り当てられた「最小限の権限」から、組織全体のコントロールを奪い取るための「階段」を探している。その代表格が iam:PassRole 権限の悪用だ。

もし、あるIAMユーザーやサービスロールが、EC2インスタンスを作成する権限と、自分自身に別のロールを割り当てる iam:PassRole 権限を持っている場合、攻撃者は以下のように動く。

1. 悪意あるスクリプトを仕込んだEC2を起動する。
2. そのEC2に、管理者権限を持つ「高権限ロール」を付与する(PassRole)。
3. 起動したEC2内でメタデータサービス(IMDSv2)から管理者用の一時トークンを取得する。
4. これで、攻撃者は組織のクラウド環境を掌握完了だ。

これは決して映画の話ではない。設定ファイルやコードのレビューで iam:PassRole が広範囲に許可されているのを見つけたら、それは「いつでも乗っ取ってください」と言っているようなものだ。

—

2. 防御の鉄則:最小権限の原則をコードで実装する

「最小権限」とは、単に権限を絞るだけではない。「そのアクションを、どのリソースに対して許可するか」を明確に定義することだ。

不適切なポリシー例(NG)

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["iam:PassRole", "ec2:RunInstances"],
      "Resource": "*" 
    }
  ]
}

*解説:Resource: "*" は禁忌だ。これでは、どのロールでもどのインスタンスにも渡せてしまう。*

セキュアなポリシー例(OK)

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "iam:PassRole",
      "Resource": "arn:aws:iam::123456789012:role/Production-Specific-App-Role",
      "Condition": {
        "StringEquals": { "iam:PassedToService": "ec2.amazonaws.com" }
      }
    }
  ]
}

*解説:Resourceを特定のロールに限定し、Conditionで「EC2サービスに対してのみパスできる」という制約を加えている。これだけで攻撃の連鎖は断ち切れる。*

—

3. アプリケーションコードからの流出を防ぐ

インフラだけでなく、アプリケーション側の実装ミスも権限漏洩の入り口になる。特に、環境変数やクレデンシャルを誤って出力してしまうケースだ。Pythonでのセキュアな設計例を見てみよう。

PythonによるセキュアなAWS接続(boto3)

認証情報をコードに直書きせず、IAMロール(Instance Profile)に依存させるのが鉄則だ。

import boto3
from botocore.exceptions import ClientError

def get_s3_client():
    # クレデンシャルをコード内にハードコードしてはいけない!
    # AWS_ACCESS_KEY_IDなどは環境変数やIAMロールから自動取得させる
    try:
        session = boto3.Session()
        s3 = session.client('s3')
        return s3
    except Exception as e:
        # エラー時に詳細な情報をログに出しすぎない(攻撃のヒントになる)
        print("認証プロバイダーへの接続に失敗しました。")
        return None

# リソースへのアクセスは最小限のスコープで
s3 = get_s3_client()
if s3:
    response = s3.list_objects_v2(Bucket='my-secure-bucket')

—

4. 現場のエンジニアへ送る「チェックリスト」

最後に、明日から現場で使えるアクションプランをまとめた。

  • IAM Access Analyzerを活用する: 外部公開されているリソースや、過剰な権限がないかを自動で検知する。
  • IMDSv2の強制: EC2のメタデータサービスは、必ず HttpTokens=required を設定してセッション認証を強制すること(SSRF対策の要)。
  • 権限の棚卸し: 90日間使われていないIAMユーザーや、使用されていない権限(Access Advisorで確認可能)は容赦なく削除する。

セキュリティは「完成」のないマラソンだ。しかし、今回紹介したような「リソースの限定」と「最小権限の徹底」という積み重ねが、致命的なインシデントと、あなたのキャリアを救う最後の砦になる。

「なんとなく動く」から「意図して動かす」へ。それが、プロフェッショナルなエンジニアへの第一歩だ。次は、君たちがその砦を守る番だよ。

コメント

タイトルとURLをコピーしました