0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Day 18:CloudTrail / Config による変更監査と Drift 検出

Last updated at Posted at 2025-12-17

この記事は AWS Lambda 実践入門 Advent Calendar 2025 18日目の記事です。

はじめに

Lambda を本番運用する上で絶対に必要な能力があります。

「誰が・いつ・何を変更したか」を説明できること。

これができないと、障害調査もコンプライアンスも破綻します。
また、Day17 の Inspector で「脆弱性が出た」時も同じで、

  • いつ Layer / 依存ライブラリが更新されたのか
  • 誰の操作(or どの CI/CD ロール)だったのか
  • 変更前後で何が変わったのか

を説明できないと、対策(修正・ロールバック・再発防止)が進みません
この “変更の事実” を支えるのが CloudTrail(操作履歴)AWS Config(設定監査) です。

CloudTrail:API 操作の完全監査ログ

CloudTrail は AWS の API 呼び出しをイベントとして記録し、
「いつ」「誰が(どのロールで)」「どこから」「何を」 を追跡できます。Lambda も CloudTrail と統合されており、コンソール操作も API 呼び出しとして記録されます。 (AWS ドキュメント)

記録例(イメージ):

{
  "eventName": "UpdateFunctionConfiguration",
  "userIdentity": { "type": "AssumedRole" },
  "requestParameters": { "timeout": 300 }
}

CloudTrail で分かること:

  • 誰が更新したか(AssumedRole / IAM User / AWS Service など)
  • どの API を叩いたか(UpdateFunctionCode / UpdateFunctionConfiguration など)
  • いつ実行したか、どこから実行したか(IP など)
  • 変更リクエストのパラメータ(requestParameters)

Lambda 運用で “見に行く頻度が高い” CloudTrail イベント

障害や事故調査の現場でよく見るのは、次の系統です。

  • コード変更UpdateFunctionCode(イメージ更新含む) (AWS ドキュメント)
  • 設定変更UpdateFunctionConfiguration(環境変数・タイムアウト・メモリ・VPC 等)
  • 権限/公開範囲AddPermission(リソースベースポリシー変更) (AWS ドキュメント)
  • 運用上の上限制御PutFunctionConcurrency(予約同時実行など) (AWS ドキュメント)

ここを押さえるだけでも、「突然遅くなった」「突然失敗する」「突然呼ばれなくなった」の調査が進みます。

注意:eventName が “微妙に違う” ことがある

Lambda の CloudTrail は、イベント名に日付・バージョン情報が付くことがあります(例:AddPermission20150331v2)。
パーサーやアラートの条件式で eventName を固定一致していると取りこぼすので、プレフィックス一致や正規化を推奨します。 (AWS ドキュメント)

“改ざんされていないログ” にする(監査の地盤固め)

CloudTrail は「記録されている」だけでは不十分で、監査では 改ざん耐性も問われます。

CloudTrail には ログファイル整合性検証(Log file integrity validation) があり、配信後にログが変更・削除されていないかを検知できます(SHA-256 ハッシュと署名を使う仕組み)。 (AWS ドキュメント)

実務の落とし穴は、「ログはあるが、保持・改ざん対策・参照権限が曖昧」という状態です。
監査に耐える最小ラインは以下です。

  • CloudTrail を S3 に集約(保管・長期保持の土台)
  • 整合性検証を有効化
  • 閲覧権限を運用ロールに限定(“見られない人が見られない”ことも統制)

CloudTrail Lake:検索性を上げる選択肢

「S3 に溜まったログを Athena で…」でも可能ですが、運用で頻出する “いつ誰が何を” を高速に追うなら、CloudTrail Lake のイベントデータストアで SQL クエリできる構成も選択肢になります(管理イベント/データイベント等を格納してクエリ)。 (AWS ドキュメント)

※本記事の主旨は「監査能力の獲得」なので、まずは CloudTrail 基盤を固め、必要に応じて Lake を追加する理解で十分です。

AWS Config:設定の現在値と変更履歴を追跡

AWS Config は、サポート対象リソースについて 作成・変更・削除を検知し、構成アイテム(CI)として継続記録します。 (AWS ドキュメント)
つまり CloudTrail が「操作ログ」なら、Config は「設定状態の時系列」です。

なぜ Config が強力なのか

  • 設定の変更点が追える(いつ何がどう変わったか)
  • 過去状態を比較できる(変更前の構成を再現しやすい)
  • “あるべき状態” をルールで定義し、非準拠を検知できる (AWS ドキュメント)

Config の基本コンポーネント(用語を最短で押さえる)

  • Configuration Recorder:何を記録するか(対象リソース)を決める
  • Delivery Channel:記録した CI を S3/SNS 等へ配送する経路
  • Rules:準拠判定(例:特定タグ必須、公開禁止、暗号化必須…)

まずは「Recorder が動いていないと何も始まらない」を覚えておくと詰まりにくいです。

Drift 検出:IaC 時代の必須機能(誤解しやすいポイントを整理)

ここは混同が多いので、実務目線で整理します。

1) CloudFormation の Drift Detection(スタックの期待値 vs 実体)

SAM でデプロイしているなら、裏側は CloudFormation スタックです。
CloudFormation は テンプレートで定義された期待値実際の設定を比較して、ドリフトを検出できます。 (AWS ドキュメント)

例:

  • 環境変数がコンソールから手動変更された
  • タイムアウトが手で変更された
  • IAM ポリシーが一部差し替えられた

こうした「IaC 外での変更」を “差異” として扱えるのが Drift Detection です。

2) AWS Config は “継続監査” と “非準拠管理” が主戦場

AWS Config 単体は「あなたの Git の template.yaml」を直接読んで差分を取るというより、
記録とルール評価で継続監査します。 (AWS ドキュメント)

ただし、CloudFormation のドリフトについては、AWS Config 側に cloudformation-stack-drift-detection-check というマネージドルールがあり、スタックが DRIFTED なら NON_COMPLIANT として扱えます。 (AWS ドキュメント)

まとめると

  • “差分を検出する機能” は CloudFormation が担当
  • “検出結果を運用(通知・準拠管理・集計)に乗せる” のが Config の価値

という分担が分かりやすいです。

CloudTrail × Config:事故調査の実務フロー(最短手順)

障害が起きたとき、現場で欲しいのは「再現性のある調査手順」です。

Step 1:CloudTrail で「誰が・いつ・どの API」を叩いたか特定

Lambda は CloudTrail に統合されているため、まず CloudTrail で変更イベントを追います。 (AWS ドキュメント)
特に UpdateFunctionCode / UpdateFunctionConfiguration / AddPermission あたりから当たるのが定石です。 (AWS ドキュメント)

Step 2:Config で「現在の設定」と「過去の設定」を比較

CloudTrail は “操作” の記録、Config は “状態” の記録です。
今の環境変数は何か、先週は何だったかのような比較は Config が得意です。 (AWS ドキュメント)

Step 3:IaC 運用なら CloudFormation Drift Detection も走らせる

「手でいじられた」を疑うなら、スタックの Drift Detection を実行して差異を確定させます。 (AWS ドキュメント)
継続監視したいなら Config のマネージドルールで “非準拠” として拾う設計が実務的です。 (AWS ドキュメント)

図解:CloudTrail / Config / CloudFormation Drift の役割分担

まとめ

運用チームはこの 2(+ CloudFormation)をセットで扱えると、障害調査・監査・再発防止が一段ラクになります。


付録A:最小構成の設計例

A. CloudTrail の“最低限”チェックリスト

  • 証跡(Trail)を作り、S3 に配信
  • 整合性検証を有効化 (AWS ドキュメント)
  • (必要なら)CloudWatch Logs へも出して EventBridge/SIEM 連携

B. Config の“最低限”チェックリスト

  • Recorder を有効化し、記録対象を選ぶ(全リソース or 必要なタイプのみ) (AWS ドキュメント)
  • Delivery Channel を設定し、S3/SNS に配送できるようにする (AWS ドキュメント)
  • CloudFormation のドリフトを “非準拠” に落とすなら cloudformation-stack-drift-detection-check を追加 (AWS ドキュメント)

C. 変更が起きたら即通知(例:UpdateFunctionConfiguration を SNS へ)

「ログを見に行く」のではなく、変化が起きた瞬間に通知されると運用は安定します。
(EventBridge で CloudTrail イベントを拾って SNS へ、という構成が典型です)

補足:この付録は “最小構成の考え方” を示すものです。
実運用ではアカウント分離(監査用アカウントへ集約)や閲覧権限設計も合わせて検討してください。

付録B:Deploy Marker の GIT_SHA と CloudTrail の eventTime を突合する運用(Day14 接続)

Day14 の Deploy Marker は「この SHA がいつデプロイされたか」を示す“運用側の真実”です。
一方 CloudTrail は「誰が・どのロールで・どの API を叩いたか」の“監査側の真実”です。
この2つを突合できると、障害調査が一気に速くなります。

1) Deploy Marker に最低限入れておくフィールド

例(JSON 1行、どこかに保存する想定):

{"env":"prod","component":"lambda:receipt-pdf-to-jpeg","git_sha":"a1b2c3d","deployed_at":"2025-12-14T08:12:34Z","actor":"circleci","workflow":"deploy-prod","job":"sam-deploy"}

ポイントは deployed_at を UTC(Z)で統一することです。CloudTrail の eventTime も UTC のため、時刻ズレで迷子になりにくくなります。

2) CloudTrail で「その時刻前後の Lambda 変更」を引く

Deploy Marker の deployed_at を中心に、±5〜10分で CloudTrail を検索します。

aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=EventName,AttributeValue=UpdateFunctionCode \
  --start-time 2025-12-14T08:05:00Z \
  --end-time   2025-12-14T08:20:00Z

lookup-events は直近の管理イベント検索に使える公式手段です。 (AWS ドキュメント)

実務では UpdateFunctionConfiguration(環境変数/メモリ/タイムアウト等)も同様に見ます。
「Deploy Marker はあるのに CloudTrail が出ない」場合は、変更経路が CloudFormation(SAM)経由であることが多いので、スタック更新に関するイベントも併せて確認すると筋が通ります。

3) “誰の変更か” を確定させる(RoleSessionName を見る)

CI/CD ロールで実行されていれば、CloudTrail 上で AssumedRole のセッション名まで追えます。
これが次の「命名規約」につながります(Day11 接続)。

付録C:AssumedRole セッション名の命名規約(CircleCI job / workflow を埋める)(Day11 接続)

CloudTrail で「誰が変更したか」を追う際、CI/CD の場合は userIdentity が AssumedRole になります。
ここで効くのが RoleSessionName です。RoleSessionName は CloudTrail に露出し、誰の何の実行かを識別するために使える、と明示されています。 (AWS ドキュメント)

制約(ここだけは守る)

RoleSessionName には制約があります。

  • 長さ:2〜64 文字
  • 使える文字:英数字・アンダースコア・+=,.@-(スペース不可) (AWS ドキュメント)

CircleCI の aws-cli/setuprole_session_name を指定できます。 (CircleCI)

推奨フォーマット(短く、確実に 64 文字以内)

長くしすぎると壊れるので、“短いが追跡できる” に寄せます。

  • ci-<env>-<wf>-<job>-<sha7>
  • 例:ci-prod-deploy-prod-sam-deploy-a1b2c3d

※ job 名に / や空白が混ざる可能性があるなら、- に置換してから使うのが安全です。

CircleCI 設定例(BASH_ENV で組み立てて渡す)

steps:
  - run:
      name: Build role session name
      command: |
        WF="${CIRCLE_WORKFLOW_ID:0:8}"
        JOB="${CIRCLE_JOB//\//-}"
        SHA="${CIRCLE_SHA1:0:7}"
        echo "export ROLE_SESSION_NAME=ci-${ENV_NAME}-${WF}-${JOB}-${SHA}" >> "$BASH_ENV"

  - aws-cli/setup:
      role_arn: ${AWS_ROLE_ARN}
      region: ${AWS_REGION}
      role_session_name: ${ROLE_SESSION_NAME}
      session_duration: "900"

これで CloudTrail 側から見たときに、

  • 「prod の deploy workflow の sam-deploy job が」
  • 「どの SHA をデプロイした操作なのか」

RoleSessionName だけで即座に分かる状態になります。

さらに監査を強くする(任意)

「セッション名の命名規約を守らせる」なら、信頼ポリシーで sts:RoleSessionName 条件キーにより強制できます(運用統制として有効)。 (AWS ドキュメント)

付録D:CloudTrail Lake で RoleSessionName と Deploy Marker を “同一クエリ” で追う(Day19 接続)

「Deploy Marker の deployed_atgit_sha」と、「CloudTrail の eventTimeRoleSessionName」を同じ SQL で突合できると、監査・障害調査が“検索ゲーム”から“再現手順”になります。

CloudTrail Lake では、イベントデータストア(EDS)は 1つのイベントカテゴリしか持てません(Management と Integration を混在できない)。その代わり、複数 EDS を SQL JOIN で横断クエリできます。 (AWS ドキュメント)

1) 構成(EDS を 2 つ用意する)

  • EDS_A(CloudTrail Management イベント用)
    Lambda の UpdateFunctionCode / UpdateFunctionConfiguration 等を格納
  • EDS_B(Integration イベント用 / ActivityAuditLog)
    Deploy Marker を “カスタムイベント” として格納(CI から投入)

Integration(外部イベント)を取り込むには、CloudTrail Lake の Integration(チャネル) を作り、PutAuditEvents(AWS CLI なら cloudtrail-data put-audit-events)でイベントを投入します。 (AWS ドキュメント)

2) CI/CD から Deploy Marker を CloudTrail Lake に投入する(例)

CircleCI の deploy job の最後に、Deploy Marker を Integration EDSへ送ります(例:eventSource を自前ドメインにする)。

aws cloudtrail-data put-audit-events \
  --region ap-northeast-1 \
  --channel-arn "$CHANNEL_ARN" \
  --audit-events \
  id="$(date +%s)-${CIRCLE_SHA1:0:7}",eventData='{
    "version":"0.01",
    "eventTime":"'"${DEPLOYED_AT_UTC}"'",
    "eventSource":"deploymarker.example.internal",
    "eventName":"DeployMarker",
    "userIdentity":{
      "type":"CustomUserIdentity",
      "principalId":"circleci"
    },
    "requestParameters":{
      "env":"'"${ENV_NAME}"'",
      "component":"lambda:'"${COMPONENT}"'",
      "git_sha":"'"${CIRCLE_SHA1}"'",
      "workflow":"'"${CIRCLE_WORKFLOW_ID}"'",
      "job":"'"${CIRCLE_JOB}"'"
    }
  }'

PutAuditEvents の投入仕様(1リクエスト最大 100 イベント/最大 1MB、チャネル ARN が必要など)は公式手順に沿います。 (AWS ドキュメント)

3) CloudTrail Lake の “同一クエリ” で突合する(EDS JOIN)

CloudTrail Lake は Trino SQL をサポートし、EDS ID をテーブル名として JOINできます。 (AWS ドキュメント)
以下は、Deploy Marker(Integration EDS)を起点に、±10分の範囲で Lambda 変更イベント(Management EDS)を突合し、**AssumedRole のセッション名(RoleSessionName 相当)**まで引く例です。

使い方:EDS_MGMTEDS_MARKER をあなたの EDS ID に置換

WITH markers AS (
  SELECT
    eventTime                         AS deployed_at,
    element_at(requestParameters,'env')       AS env,
    element_at(requestParameters,'component') AS component,
    element_at(requestParameters,'git_sha')   AS git_sha
  FROM EDS_MARKER
  WHERE eventSource = 'deploymarker.example.internal'
    AND eventName   = 'DeployMarker'
    AND eventTime  >= now() - INTERVAL '7' DAY
),
lambda_changes AS (
  SELECT
    eventTime,
    eventName,
    eventSource,
    userIdentity.arn AS actor_arn,
    -- arn:aws:sts::<acct>:assumed-role/<RoleName>/<SessionName>
    split_part(userIdentity.arn, '/', 3) AS role_session_name,
    recipientAccountId
  FROM EDS_MGMT
  WHERE eventSource = 'lambda.amazonaws.com'
    AND eventName IN ('UpdateFunctionCode','UpdateFunctionConfiguration','AddPermission')
    AND eventTime >= now() - INTERVAL '7' DAY
)
SELECT
  m.env,
  m.component,
  m.git_sha,
  m.deployed_at,
  c.eventTime          AS api_time,
  c.eventName,
  c.role_session_name,
  c.actor_arn
FROM markers m
JOIN lambda_changes c
  ON c.eventTime BETWEEN m.deployed_at - INTERVAL '10' MINUTE
                    AND m.deployed_at + INTERVAL '10' MINUTE
ORDER BY m.deployed_at DESC, c.eventTime DESC
LIMIT 200;

この突合ができると、障害調査で次が一撃になります。

  • 「この git_sha をデプロイした CI 実行はどれか」
  • 「同じ時間帯に UpdateFunctionConfiguration を叩いたのは誰(どのセッション名)か」
  • 「手動変更が混ざっていないか(想定外の role_session_name がいないか)」

4) Day19 への繋ぎ(“検知・通知” に落とす)

  • CloudTrail Lake のクエリを 定期実行(CLI の start-query / get-query-results)し、結果があれば SNS/Slack へ通知
  • あるいは「想定外の role_session_name が出た」「Deploy Marker があるのに変更イベントが無い」などを 検知条件にする (AWS ドキュメント)
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?