IAM ユーザーのログイン失敗を検知して複数回失敗すると権限を剥奪する仕組みを作ってみた

5 回ログイン失敗すると対象の IAM ユーザーの全権限を拒否する仕組みを作ってみました
2024.05.25

こんにちは、AWS 事業本部の平木です!

AWS における PCIDSS v3.2.1を見た時に要件 8 を参照するとアカウントロックに関する要件があります。

現状、執筆時点では IAM ユーザーで連続してログイン失敗してしまったとしてもアカウントをロックできる仕様はありません。

ただ、AWS 公式のコンプライアンスガイドを見ると以下のように記述されていました。

PCI DSS 審査の適用範囲内であると判断された IAM ユーザーには、8.1.6 および 8.1.7 のアカウントロックに関する要件を満たす追加の仕組みが必要です。お客様がこれを達成するには、AWS CloudTrail、Amazon DynamoDB、AWS Lambda、Amazon CloudWatch を組み合わせて連続したログイン失敗を追跡して、ログイン失敗がしきい値である 6 回連続で発生した場合に制限を強めた IAM ポリシーを付け加えることが必要です。

こちらを見てなるほどと思ったため、今回は公式で言っている構成を実際に構築してみました。

やってみた

構成図を作図してみると下記のような構成となります。

各種コンポーネントは以下です。

  • CoudTrail
    • サインインイベントを収集する
    • 構築はせず既存のものを活用します
  • EventBridge ルール(サインイン失敗イベント検知用)
    • CloudTrail で収集したサインインイベントの中から失敗のイベントを検知します
  • EventBridge カスタムイベントバス
    • 後続の Lambda をトリガーするための EventBridge の橋渡しの役目
  • EventBridge ルール(イベント連携用)
    • 実際の処理を行う Lambda にイベントをトリガーする
  • Lambda
    • 失敗した回数を保管する DynamoDB にレコードを PUT する機構と 5 回分記録されている場合に対象の IAM ユーザに全てのアクションを拒否するポリシーを付与します
  • DynamoDB
    • サインインが失敗した回数をユーザー毎にカウントし、TTL により 1 時間後にはレコードが削除されるようになっています

なぜバージニア北部以外のリージョンにも EventBridge が必要か

構成図を見ていただくとバージニア北部以外にも特定のリージョンに EventBridge を配置しています。

こちらには理由があり、AWS のサインイン時の URL を見ていただくと分かりますがログインをするURLはレイテンシーによってログイン先のエンドポイントが異なります。

IAM ユーザーでサインインかつ Cookie が存在する場合には、下記 3 リージョンのいずれかのエンドポイントが使用されます。

  • オハイオリージョン(us-east-2)
  • ストックホルムリージョン(eu-north-1)
  • シドニーリージョン(ap-southeast-2)

そのため日本に住んでいる方は基本シドニーリージョンのエンドポイントが使用されるかと思います。

また root ユーザーでサインインまたは IAM ユーザーかつ Cookie が存在しない場合には、バージニア北部リージョン(us-east-1)のエンドポイントが使用されます。

AWS 公式ドキュメントにも記載がありますのでご参照ください。
AWS Management Console サインインイベント - AWS CloudTrail

そのためサインインイベントを正確に検知するために各リージョンに配置しています。

本題

では各コンポーネントを構築します。

各コンポーネントを構築するために CloudFormation テンプレートを GitHub に用意しました。

2 種類あり、バージニア北部用 (loginfailure.yml) とその他のリージョン用 (loginfailure_other_region.yml) です。

デプロイは割愛しますので実際にログインを失敗してみます。

検証

まず 1 回失敗してみると、

バージニア北部に作成された Loginfailures という DynamoDB テーブルにミスしたユーザー名とミスした回数、TTL 値のレコードが追加されます。

続いて 2 回目失敗してみると、

先ほどのレコードの FailureCount の値が 1 から 2 に変わりました。

では一気に飛んで 6 回ミスしてみると

同様に 6 と記録され、

対象の IAM ユーザーにDenyAllActionsという全てのアクションを拒否するインラインポリシーが追加されました。 これでもし悪意のあるユーザーがログインに成功してしまったとしても何もアクション出来ない状態にできます。

おわりに

今回は、IAM ユーザーのログイン失敗を検知して複数回失敗すると権限を剥奪する仕組みを作ってみました。

今回はユーザー種別問わずに全てアクションを拒否するような仕組みを取りましたが、システム用に使うパスワードを保持しないユーザー名が知られてしまった場合にあえてパスワードをミスしシステムに影響を出してしまうことも可能となるので実際に実装する場合にはパスワードを持つインタラクティブなユーザーのみこの仕組みの対象にするなど考慮いただくと良いかと思います。

この記事がどなたかの役に立つと嬉しいです。