【実務・中級編】 クラウド環境におけるサーバーレス関数(Lambda)の権限昇格 – オフェンシブセキュリティ & リバースエンジニアリング防御ガイド

クラウドの盲点:Lambda関数が「特権ID」を握る日 ― 権限昇格のメカニズムと防御の要諦

こんにちは。現場の最前線でインフラとセキュリティの境界線を守り続けているエンジニアです。

皆さんは「サーバーレスだから安全」という幻想を抱いていないだろうか? AWS Lambdaのような関数実行環境は、確かにサーバー管理の手間を省いてくれるが、それは同時に「境界防御」の概念が希薄になることを意味する。攻撃者は、あなたの書いたたった数行の脆弱なコードを足がかりに、Lambdaに付与されたIAMロールを乗っ取り、AWS環境全体を掌握しようと虎視眈々と狙っている。

今日は、Lambda環境における「権限昇格」のリアルな攻撃手法と、それを封じ込めるための防御術を、現場の泥臭い教訓を交えて解説する。

—

Lambdaが乗っ取られる「その瞬間」

攻撃者がLambdaを狙う際、真っ先に探索するのが「環境変数」だ。Lambdaは実行環境の構成情報を環境変数として保持する。ここに、DB接続情報、APIキー、あるいは一時的なセキュリティトークンが平文で置かれているケースがいまだに後を絶たない。

攻撃シナリオ:RCEからの権限奪取

1. 侵入: アプリケーションのコード(例えばNode.jsの依存ライブラリの脆弱性や、OSコマンドインジェクション)を突き、任意のコード実行(RCE)を成功させる。
2. 偵察: 実行環境に入り込んだ攻撃者は、/proc/self/environ を読み取り、環境変数をダンプする。
3. 昇格: Lambda実行環境には、IAMロールによって提供される AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN が自動的にセットされている。攻撃者はこれらを盗み出し、自身のローカル端末でAWS CLIを叩き、そのLambdaが持つ「権限の範囲内」で環境を蹂躙する。

Lambdaに「AdministratorAccess」のような強力な権限を与えていれば、ゲームセットだ。

—

防御の最前線:最小権限と実行環境の隔離

この攻撃を無力化するには、「関数が動くために必要最小限の権限」以外を徹底的に剥奪することだ。

1. IAMポリシーの「超」最小化

LambdaのIAMロールには、ワイルドカード(*)を絶対に記述してはならない。リソース単位で厳格に制限をかける。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject"
      ],
      "Resource": "arn:aws:s3:::my-secure-bucket/data/*" 
      // 指定したバケットの特定のパスのみにアクセスを限定する
    }
  ]
}

2. 環境変数の暗号化と「外出し」

環境変数に機密情報を直接書くのは禁止だ。AWS Systems Manager Parameter StoreやSecrets Managerを活用し、実行時にランタイムで取得する設計に切り替えよう。

Pythonによるセキュアな値取得の実装例

import boto3
import os

def get_secret(secret_name):
    # AWS SDKを使用して、動的に秘匿情報を取得する
    client = boto3.client('ssm')
    response = client.get_parameter(
        Name=secret_name,
        WithDecryption=True
    )
    return response['Parameter']['Value']

def lambda_handler(event, context):
    # 環境変数にはキー名だけを保存し、値そのものは持たせない
    db_password = get_secret(os.environ['DB_PASSWORD_PARAM'])
    
    # ここにメインロジック...
    return {"status": "success"}

—

現場で役立つ防御のTips

一時ファイルシステムの活用とクリーンアップ

Lambdaの /tmp ディレクトリは512MB〜10GBまで利用可能だが、この領域は関数の実行インスタンス間で「残り続ける」ことがある。機密データを処理した後は、必ず明示的に削除する癖をつけよう。

const fs = require('fs');
const path = '/tmp/sensitive_data.txt';

try {
  // 処理後に必ずファイルを削除する
  if (fs.existsSync(path)) {
    fs.unlinkSync(path);
  }
} catch (err) {
  console.error("削除失敗:", err);
}

ネットワーク境界の設定

LambdaをVPC内に配置し、セキュリティグループを適用してアウトバウンド通信を制御せよ。インターネットへの全開放(0.0.0.0/0)は、攻撃者がC&Cサーバーへ通信するためのゲートウェイになる。NATゲートウェイやVPCエンドポイントを適切に設定し、特定の通信先のみを許可するホワイトリスト構成が鉄則だ。

—

まとめ:セキュリティは「設定」ではなく「規律」

Lambdaの権限昇格を防ぐことは、実は難しい技術を要するわけではない。「必要以上の権限を渡さない」「機密を環境変数に直書きしない」「実行環境を使い回さない」という、極めて基本的な規律を徹底できるかどうかの問題だ。

皆さんの開発するシステムが、クラウドという広大な戦場で生き残るための強固な砦となることを願っている。もしコードレビューの段階で「これ、権限広すぎないか?」と違和感を覚えたら、その直感こそが最大の防御の第一歩だ。現場からは以上だ。

コメント

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