MFA設定しないIAMユーザを自動で無効化

本記事は TechHarmony Advent Calendar 2025 12/21付の記事です

皆さんこんにちは。UGです。

クリスマスが今年もやってくるということで、サンタクロースはなぜ赤い服を着ているのでしょうか?
と今ではサンタクロースよりもカーネル・サンダースという白髭を好む私はふと疑問に思いました。

カーネルサンダースも思えば白と赤だなぁ?というのはおいておいて、サンタクロースの服が赤というのは、サンタクロースのモデルとされるセント・ニコラスが生前、教会の儀式の際に着ていた服の色がもとになったと言われているみたいです。
あとはコカ・コーラの宣伝によるものらしいです。

ちなみに私のチャッピー君は「20世紀初頭の印刷技術で赤が最も再現しやすかったから」と教えてくれましたが、調べても出てこなかったので問い詰めたところ嘘と白状しました。。。

皆さんもハルシネーションには気を付けましょう。

さて本題ですが、今回は新規作成したIAMユーザのMFA設定を自動でチェックし、設定されていなければ自動で無効化する仕組みを実装してみたのでご紹介出来たらなと思います!

結論

まず先に構成やコードを載せておきますので、説明よりも早く実装したいという方は参考にしていただければと思います。

前提:CloudTrailが有効化されていること
構成:EventBrige + Step Functions
注意点:バージニア北部(us-east-1)で構築すること
EventBridgeルール:

{
  "source": ["aws.iam"],
  "detail-type": ["AWS API Call via CloudTrail"],
  "detail": {
    "eventName": ["CreateUser"]
  }
}

Step Functions ASL:

{
  "Comment": "A description of my state machine",
  "StartAt": "Wait",
  "States": {
    "Wait": {
      "Type": "Wait",
      "Seconds": 86400,
      "Next": "ListMFADevices",
      "Assign": {
        "UserName.$": "$.detail.requestParameters.userName"
      }
    },
    "ListMFADevices": {
      "Type": "Task",
      "Parameters": {
        "UserName.$": "$UserName"
      },
      "Resource": "arn:aws:states:::aws-sdk:iam:listMFADevices",
      "Next": "GetMfaDeviceCount"
    },
    "GetMfaDeviceCount": {
      "Type": "Pass",
      "Next": "CheckMFA",
      "Parameters": {
        "MfaDeviceCount.$": "States.ArrayLength($.MfaDevices)"
      }
    },
    "CheckMFA": {
      "Type": "Choice",
      "Choices": [
        {
          "Next": "成功",
          "Variable": "$.MfaDeviceCount",
          "NumericGreaterThan": 0
        }
      ],
      "Default": "DeleteLoginProfile"
    },
    "DeleteLoginProfile": {
      "Type": "Task",
      "Parameters": {
        "UserName.$": "$UserName"
      },
      "Resource": "arn:aws:states:::aws-sdk:iam:deleteLoginProfile",
      "Next": "Disabled Notification"
    },
    "Disabled Notification": {
      "Type": "Task",
      "Resource": "arn:aws:states:::sns:publish",
      "Parameters": {
        "TopicArn": "<トピックARN>",
        "Message.$": "States.Format('User {} did not set MFA and was disabled.', $UserName)",
        "Subject": "IAM User MFA Not Set"
      },
      "End": true
    },
    "成功": {
      "Type": "Succeed"
    }
  },
  "QueryLanguage": "JSONPath"
}こ

※SNSはおまけなので、削除するか通知させたければ”TopicArn”の部分をご自身で作成したものに変更してください。

 

背景

どこの環境でもMFAを設定することはセキュリティを担保するために必須なものとなっているかと思います。
とは言えMFAを設定するのはめんどくさいですし、純粋に設定し忘れていたという問題もあります。
(狙ったわけではないですが、思えば前回MFAめんどくさいでProtonのブログ書いてました笑)

そのための対策として、MFAを設定しないとリソースを操作することができないIAMポリシーを設定しているところも多いのではないでしょうか?

しかし、IAMポリシー対策はリソース操作はできないものの、マネージメントコンソールにアクセスすることは可能です。
そういったリスクも回避したいといった場合に、MFAを設定していないIAMユーザーを無効化してしまうというのも1つの対策となります。

ただMFAが設定されているのかを確認して設定されていなければ無効化、なんてことを手動でやっていたら大変です。。。
なので手動が大変なら自動化してしまえ!ということで自動化させてみました。

 

前提

前提事項として、CloudTrailが有効化されている必要があります。
理由としては、CloudTrailで記録される「CreateUser」というIAMユーザーが作成された時のイベントをトリガーに今回の自動化フローは動くためです。

みなさん問題はないかと思いますが、CloudTrailは有効化必須のサービスなので、もし有効化されていないので、本ブログ内容関係なくすぐ有効化しましょう!

 

構成説明

今回の自動化のざっくり流れは

  1. 新規IAMユーザーを作成 ※こちらは手動
  2. EventBrigeでIAMユーザの作成イベントを検出してStep Functionsを起動 ←ここから自動
  3. Step Functionsのフロー内で、一定時間待ったのちMFAの設定有無を確認、設定されていなければ無効化

となっており、EventBrigeとStep Functionsのみで実現することができます。
では詳しくご紹介していきます。

IAMユーザ作成をトリガーとして Step Functions を起動

前提の節でも触れましたが、IAMユーザーが作成されると「CreateUser」イベントが記録されます。
このイベントをEventBridgeルールで検出し、Step Functionsを開始します。

EventBridgeルール:

{
  "source": ["aws.iam"],
  "detail-type": ["AWS API Call via CloudTrail"],
  "detail": {
    "eventName": ["CreateUser"]
  }
}

Step Functions のステートマシン構成

Step Functionsのステートマシンの構成は以下のようになっています。

Step Fuctionsステート

細かい設定の説明は後回しにして、先に役割単位でまとめて説明していきます。

まず、「Wait」でMFA登録有無の確認までの時間を設定しています。
例えば、IAMユーザー作成が24時間以内にMFAを設定することといったルールの場合は、Waitに86400秒を設定します。

次に、「IAM: ListMFADevices」「Pass state」「Choice state」の部分で、IAMユーザーのMFAの設定有無の確認を行っています。

設定されているのであれば、「Succeed state」に遷移し、特に何も行いません。


設定されていなければ、「DeleteLoginProfile」でIAMユーザーの無効化をします。

「SNS: Publish」はおまけですが、「無効化しましたよ」の通知用となります。

ざっくりだと以上のようになっていて、各ステートごとの細かい設定についても説明します。

まず、「Wait」では待機時間の秒数とともに、EventBrigeからの入力値である”detail.requestParameters.userName”を変数へ格納しています。
“detail.requestParameters.userName”は作成されたIAMユーザーの名前となっており、他のステートで利用するため最初に変数へ格納しています。

次に、「IAM: ListMFADevices」でIAMユーザーのMFAデバイスリストを取得してきています。

MFA設定がされていない場合の出力結果:

{
  "IsTruncated": false,
  "MfaDevices": []
}

しかし、「IAM: ListMFADevices」の出力結果からでは、「Choice state」で分岐をさせることができません。
そのため、「Pass state」の中で”States.ArrayLength($.MfaDevices)”によってパラメーターの変換を行っています。

パラメータ変換後:

{
  "MfaDeviceCount": 0
}

これにより、MFAの登録デバイスを数値で表せるようにして、「Choice state」にて”$.MfaDeviceCount > 0″の条件でMFAの登録有無の分岐を実現しています。


そして、MFA登録がされていなければ、「DeleteLoginProfile」でIAMユーザーを無効化しています。

 

注意点

最後に注意点ですが、今回ご紹介した構成はバージニア北部(us-east-1)で構築する必要がございます。

と言いますのも、「CreateUser」イベントはバージニア北部リージョンに記録されるためです。
そのため、そのほかのリージョンのEventBrigeで検出しようとしても、検出されず、となってしまいます。

公式ドキュメントにも⚠重要と明記されていましたが、自分もこの仕様を知らず、最初に東京リージョンに作成して、なんで動かないんだ?とつまづきました笑

今回のメインサービスであるIAMがグローバルサービスなので、バージニア北部リージョンで実装することに大きな問題はないかと思いますが、ご注意いただければと思います。

 

まとめ

ということでMFA設定をしていなければ自動で無効化をご紹介させていただきました。
MFAが本当に役に立っているのか?みたいな話もありますが、昨今大きなセキュリティ問題も発生しており、セキュリティの意識や要望は強くなってくると思われます。
そんな中でこんなのもあるんだな~と本ブログが一助になればよいかな~と。

最後までお読みいただきありがとうございました!!

著者について

毛が少し生えてきたかもしれないAWS素人です。
周りにエンジニアっぽくないですねと言われ、自分でもそう思うのにエンジニアをやっている自分って一体...

ANGEL Dojo 2024:ベストアーキテクチャ賞 2位
2025 Japan All AWS Certifications Engineers

尾身優治をフォローする

クラウドに強いによるエンジニアブログです。

SCSKクラウドサービス(AWS)は、企業価値の向上につながるAWS 導入を全面支援するオールインワンサービスです。AWS最上位パートナーとして、多種多様な業界のシステム構築実績を持つSCSKが、お客様のDX推進を強力にサポートします。

AWS運用・監視
シェアする
タイトルとURLをコピーしました