IAMポリシーの直接アタッチを調査するLambdaFunctionをつくってみた

2017.07.11

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

ご機嫌いかがでしょうか、豊崎です。

今回、IAMユーザの権限について調査を行うLambdaFunctionを作成したので、ご紹介させていただきます。

前提

ここではIAMポリシーの管理ルールとして以下の前提条件があるとします。

  • IAMユーザへの直接のポリシー付与は認められていない
  • IAMグループからの権限付与のみを許可している

準備

以下表のIAMユーザ、グループを作成しました。

ユーザ IAMグループ インラインポリシー AWS管理ポリシー
demo-user01 demo-group あり なし
demo-user02 demo-group なし あり
demo-user03 - あり あり
demo-user04 demo-group なし なし

また、通知用のSNSTopicは別途作成をしています。

LambdaFunctionの動作

全てのIAMユーザに対して以下をチェックする

  • IAMユーザ自体にインラインポリシーがアタッチされていないこと
  • IAMユーザ自体にAWS管理ポリシーがアタッチされていないこと
  • IAMユーザがIAMグループに所属していること(野良ユーザじゃないこと)

上記に該当するIAMユーザがいた場合にはSNS通知を行う。 *demo-user01,02,03が該当するため、検知される想定です。

LambdaFunction

言語:Python3.6 タイムアウト:1分

import boto3

c_iam = boto3.client('iam')
r_iam = boto3.resource('iam')
sns = boto3.client('sns')

def check_inline(list_names):
    list_inline_policy_user = []
    for name in list_names:
        list_inline_policy = []
        user = r_iam.User(name)
        inline_policy = user.policies.all()

        for policy in user.policies.all():
            list_inline_policy.append(policy.name)

        if len(list_inline_policy) > 0:
            list_inline_policy_user.append(name)

    return list_inline_policy_user

def check_managed(list_names):
    list_managed_policy_user = []
    for name in list_names:
        list_managed_policy = []
        user = r_iam.User(name)

        for managed_policy in user.attached_policies.all():
            list_managed_policy.append(managed_policy.policy_name)

        if len(list_managed_policy) > 0:
            list_managed_policy_user.append(name)

    return list_managed_policy_user

def check_solo(list_names):
    list_solo_user = []
    for name in list_names:
        user = c_iam.list_groups_for_user(UserName=name)

        if len(user['Groups']) == 0:
            list_solo_user.append(name)

    return list_solo_user

def sns_publish(list_inline_policy_user,list_managed_policy_user,list_solo_user):
    mes = f" IAMユーザに問題が見つかりました。\n\
    内容を確認して修正してください。\n\n\n\
    インラインポリシーが設定されているIAMユーザ:{list_inline_policy_user}\n\
    AWS管理ポリシーが設定されているIAMユーザ:{list_managed_policy_user}\n\
    IAMグループに所属していないIAMユーザ:{list_solo_user}\n"

    sns.publish(
        TopicArn='arn:aws:sns:ap-northeast-1:XXXXXXXXXXXX:demo-sns',
        Message=mes,
        Subject="IAM User's rule violation."
    )

def lambda_handler(event,context):
    # IAMユーザの一覧を取得
    list_users = c_iam.list_users()
    list_names = [user_name['UserName'] for user_name in list_users['Users']]

    # IAMユーザ自体にインラインポリシーがアタッチされていないことをcheck
    list_inline_policy_user = check_inline(list_names)

    # IAMユーザ自体にAWS管理ポリシーがアタッチされていないことをcheck!
    list_managed_policy_user = check_managed(list_names)

    # IAMユーザがIAMグループに所属していること(野良ユーザじゃないこと)をchek!
    list_solo_user = check_solo(list_names)

    # 問題があった時にSNSで通知
    sns_publish(list_inline_policy_user,list_managed_policy_user,list_solo_user)

    response = {
        "UserWithInlinePolicy": list_inline_policy_user,
        "UserWithManagedPolicy": list_managed_policy_user,
        "SoloUser": list_solo_user
    }

    return response

結果の出力とSNS通知

結果としては無事想定の通りに出力されました。

{
  "UserWithInlinePolicy": [
    "demo-user01",
    "demo-user03"
  ],
  "UserWithManagedPolicy": [
    "demo-user02",
    "demo-user03"
  ],
  "SoloUser": [
    "demo-user03"
  ]
}

該当のIAMユーザがいたため、SNSの通知も送信されています。

mail

さいごに

IAMユーザ毎に、ポリシーをアタッチすることは可能ですが管理が煩雑になりがちです。 可能であればIAMグループ経由でポリシーの付与を行う方が綺麗に管理できることが多いです。 本記事には前提がありますが、似た環境であれば少し修正して活用いただけるのではないかと思います。 誰かのお役に立てば幸いです。