AWS Configルールを利用し、認証情報が一定期間未利用のIAMユーザーを無効化する前に事前通知する仕組み

AWS Configルールを利用し、認証情報が一定期間未利用のIAMユーザーを無効化する前に事前通知する仕組み

2025.08.01

はじめに

セキュリティ対策として、長期間使用されていないIAMユーザーの認証情報を定期的に無効化することは重要です。

AWS Configルール(iam-user-unused-credentials-check)とAWS Systems Manager オートメーションを利用することで、一定期間認証情報(アクセスキー・コンソールパスワード)が未利用のIAMユーザーの認証情報を自動で無効化できます。

https://dev.classmethod.jp/articles/automation-revoke-unused-iam-user-credentials/

https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/iam-user-unused-credentials-check.html

一般的な運用として、例えば、90日以上未利用だった場合に無効化するケースが考えられます。
この場合、突然無効化されると利用者が困ってしまうため、事前に通知したい場合もあるでしょう。

本記事では、無効化の数日前に利用者や管理者に通知する方法を解説します。

システム構成

構成は以下のとおりです。

cm-hirai-screenshot 2025-07-30 16.36.58

今回は、無効化予定日の7日前と14日前に段階的に通知したいと仮定します。この要件を実現するため、異なる日数パラメータを設定した2つのConfigルールを作成します。

2つのルールが必要な理由は、EventBridgeが準拠から非準拠への変更時に1回だけトリガーされるためです。つまり、各通知タイミング(7日前、14日前)で確実に1回ずつ通知するには、それぞれ専用のルールが必要になります。

ルールが非準拠となった場合、AWS Configのコンプライアンスステータス変更をトリガーに、EventBridge経由でAWS Step Functionsを起動し、Amazon SNSでメール通知を行います。

通知方法の選択肢

今回はSNSトピックで固定のメールアドレスに通知しますが、以下のような方法も可能です。

  • IAMユーザーごとに個別通知:Amazon DynamoDBにIAMユーザー名と通知先メールアドレスを保存し、ステートマシンからAmazon SESなどで個別にメール送信
  • 少数のユーザーの場合:ステートマシン内で直接ユーザーごとの通知先を定義

今回、SNSトピックは作成済みとします。

AWS Configルール作成

AWS Configルールを作成します。

AWSマネージド型ルールであるiam-user-unused-credentials-checkというルールを利用します。

cm-hirai-screenshot 2025-07-30 16.14.10

ルール名をiam-credential-expiry-check-1にし、パラメータmaxCredentialUsageAge83に設定します。このパラメータは、指定した日数内に使用されていないパスワードまたはアクティブなアクセスキーがあるかどうかを確認します。つまり、いずれかの認証情報が83日以上非アクティブの場合、非準拠となります。

cm-hirai-screenshot 2025-07-30 16.18.12

これで1つ目のルールが作成できました。

同様に、パラメータmaxCredentialUsageAge76に設定したルール名iam-credential-expiry-check-2を作成します。

cm-hirai-screenshot 2025-07-30 16.24.59

cm-hirai-screenshot 2025-07-30 16.25.03

これで2つのAWS Configルールが作成できました。

ステートマシン作成

以下のステートマシンを作成します。

cm-hirai-screenshot 2025-07-30 16.47.14

maxUnusedDaysで90日での自動無効化期間を設定しています。

SNSトピックARNであるTopicArnは各自変更してください。

{
  "Comment": "IAMユーザー認証情報の自動無効化アラート通知ワークフロー - Config Rule評価結果に基づいて対象ユーザーにSNS通知を送信",
  "QueryLanguage": "JSONata",
  "StartAt": "Initialize Configuration",
  "States": {
    "Initialize Configuration": {
      "Type": "Pass",
      "Comment": "初期設定値を定義:AWSアカウントID、Config Rule名、最大未使用日数を設定",
      "Assign": {
        "awsAccountId": "{% $states.input.detail.awsAccountId %}",
        "configRuleName": "{% $states.input.detail.configRuleName %}",
        "maxUnusedDays": "{% 90 %}"
      },
      "Next": "Calculate Days"
    },
    "Calculate Days": {
      "Type": "Pass",
      "Comment": "ConfigRule名に基づいて残り日数を計算:check-1なら7日、check-2なら14日",
      "Assign": {
        "remainingDays": "{% $configRuleName = \"iam-credential-expiry-check-1\" ? 7 : $configRuleName = \"iam-credential-expiry-check-2\" ? 14 %}"
      },
      "Next": "Calculate Disable Deadline"
    },
    "Calculate Disable Deadline": {
      "Type": "Pass",
      "Comment": "無効化予定日を計算:現在日時 + 残り日数から YYYY/MM/DD 形式の文字列を生成",
      "Assign": {
        "disableDeadline": "{% (\n  $remainingDays := (\n    $configRuleName = \"iam-credential-expiry-check-1\" ? 7 :\n    $configRuleName = \"iam-credential-expiry-check-2\" ? 14\n  );\n  $targetDate := $toMillis($now()) + ($remainingDays * 24 * 60 * 60 * 1000);\n  $dateStr := $substring($fromMillis($targetDate), 0, 10);\n  $replace($replace($dateStr, \"-\", \"/\"), /^(\\d{4})\\/(\\d{2})\\/(\\d{2})$/, \"$1/$2/$3\")\n) %}"
      },
      "Next": "ListUsers"
    },
    "ListUsers": {
      "Comment": "全ユーザー一覧を取得し、ユーザーID(resourceId)に該当するユーザーの名前を特定",
      "Arguments": {},
      "Assign": {
        "userName": "{% $states.result.Users[UserId=$states.input.detail.resourceId].UserName[0] %}"
      },
      "Next": "SNS Publish",
      "Resource": "arn:aws:states:::aws-sdk:iam:listUsers",
      "Type": "Task"
    },
    "SNS Publish": {
      "Arguments": {
        "TopicArn": "arn:aws:sns:ap-northeast-1:AWSアカウントID:cm-hirai",
        "Subject": "{% 'IAM認証情報無効化通知 - ' & $userName %}",
        "Message": "{% 'IAMユーザー「' & $userName & '」の認証情報(コンソールパスワード or アクセスキー)が' & $string($remainingDays) & '日後(' & $disableDeadline & ')に自動無効化されます。\n\n▼ 継続利用される場合の対応方法\n・AWSマネジメントコンソールへのログイン\n・アクセスキーを使用したAWS操作の実行\n\n※' & $string($maxUnusedDays) & '日間未使用の認証情報は、セキュリティ対策として自動無効化されます。\n\n■ 対象情報\n- AWSアカウントID: ' & $awsAccountId & '\n- IAMユーザー名: ' & $userName & '\n- 無効化予定日: ' & $disableDeadline & '\n- 残り日数: ' & $string($remainingDays) & '日\n\n本メールは自動送信されています。' %}"
      },
      "End": true,
      "Resource": "arn:aws:states:::sns:publish",
      "Type": "Task"
    }
  }
}

ステートマシンの動作は以下のとおりです。

  • AWS ConfigルールからEventBridge経由で受け取ったイベントから、AWSアカウントIDとConfigルール名を取得
  • Configルール名に基づいて残り日数を計算(check-1なら7日、check-2なら14日)
  • 無効化予定日を計算してYYYY/MM/DD形式で生成
  • IAM ListUsers APIを実行してリソースIDからユーザー名を特定
  • SNS経由でメール通知を送信

ステートマシン作成時、IAMロールと一部のIAMポリシーも自動作成されます。

cm-hirai-screenshot 2025-07-30 15.32.17

自動作成されないIAMポリシーは手動で作成し、IAMロールにアタッチします。

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

EventBridge作成

EventBridgeルールを作成し、AWS Configのコンプライアンス変更イベントをトリガーとしてステートマシンを起動します。

イベントパターンは以下のように設定します。

{
  "detail-type": ["Config Rules Compliance Change"],
  "source": ["aws.config"],
  "detail": {
    "configRuleName": ["iam-credential-expiry-check-1", "iam-credential-expiry-check-2"],
    "messageType": ["ComplianceChangeNotification"],
    "newEvaluationResult": {
      "complianceType": ["NON_COMPLIANT"]
    }
  }
}

ステータスが準拠から非準拠に変わった場合にトリガーされます。一度トリガーされた後もConfigルールで毎日チェックしますが、継続して非準拠の状態が続いても再度トリガーされることはありません。

EventBridgeルールのターゲット先は、先ほど作成したステートマシンに設定します。

作成の順番

EventBridgeルールとステートマシンを先に作成し、その後AWS Configルールを作成すると、76日や83日以上非アクティブのIAMユーザーが即座に非準拠となり、通知されてしまいます。

そのため、AWS Configルールを先に作成することをお勧めします。先にConfigルールを作成すると非準拠となりますが、その後EventBridgeルールとステートマシンを作成することで、EventBridgeはトリガーされません。その後、準拠から非準拠に変わったIAMユーザーのみがトリガーされ、通知されます。

作成する順番にはご注意ください。

実際に試してみる

実際に動作確認を行ったところ、以下のとおり通知されました。

cm-hirai-screenshot 2025-07-30 16.22.14

cm-hirai-screenshot 2025-07-30 16.22.01

ステートマシンが正常に動作し、期待どおりの通知メールが送信されていることが確認できました。

参考として、ステートマシンに渡されるEventBridgeイベントの例は以下のとおりです。

{
  "version": "0",
  "id": "3262a2d6-39ab-714f-158e-00d29af1402f",
  "detail-type": "Config Rules Compliance Change",
  "source": "aws.config",
  "account": "アカウントID",
  "time": "2025-07-30T07:21:24Z",
  "region": "ap-northeast-1",
  "resources": [],
  "detail": {
    "resourceId": "AIDATCKAQT2XMYOT37SQY",
    "awsRegion": "ap-northeast-1",
    "awsAccountId": "アカウントID",
    "configRuleName": "iam-credential-expiry-check-2",
    "recordVersion": "1.0",
    "configRuleARN": "arn:aws:config:ap-northeast-1:アカウントID:config-rule/config-rule-ydinvr",
    "messageType": "ComplianceChangeNotification",
    "newEvaluationResult": {
      "evaluationResultIdentifier": {
        "evaluationResultQualifier": {
          "configRuleName": "iam-credential-expiry-check-2",
          "resourceType": "AWS::IAM::User",
          "resourceId": "AIDATCKAQT2XMYOT37SQY",
          "evaluationMode": "DETECTIVE"
        },
        "orderingTimestamp": "2025-07-30T07:20:49.600Z"
      },
      "complianceType": "NON_COMPLIANT",
      "resultRecordedTime": "2025-07-30T07:21:24.168Z",
      "configRuleInvokedTime": "2025-07-30T07:20:53.047Z"
    },
    "notificationCreationTime": "2025-07-30T07:21:24.867Z",
    "resourceType": "AWS::IAM::User"
  }
}

最後に

AWS Configルール、EventBridge、Step Functionsを組み合わせることで、IAMユーザーの認証情報無効化前の事前通知システムを構築できました。

この仕組みにより、利用者や管理者に対して十分な猶予期間を持って通知でき、突然のアクセス停止を防ぐことが可能です。セキュリティとユーザビリティの両方を考慮した運用が実現できます。

この記事をシェアする

facebookのロゴhatenaのロゴtwitterのロゴ

© Classmethod, Inc. All rights reserved.