IAMのパスワードポリシーをLambda(Python3)から変更する

2022.03.08

LambdaからIAMのパスワードポリシーを変更したので、サンプルとしてコードを置いておきます。ご自由にお使いください。

サンプルコード

先にLambdaで利用するコードを載せておきます。

  • LambdaのランタイムはPython3.8で動作確認をしています
  • ログの出力や変更後のリソースチェックはしていますが、あくまでサンプルとしてご利用ください
  • パスワードポリシーはSecurity Hubの「AWS の基本的なセキュリティのベストプラクティス標準」を満たすように設定しています

IAMのパスワードポリシーを変更する

import json
import boto3
import logging

logger = logging.getLogger()
logger.setLevel(logging.INFO)

PASSWORD_POLICY = {
    "MinimumPasswordLength": 8,
    "RequireSymbols": True,
    "RequireNumbers": True,
    "RequireUppercaseCharacters": True,
    "RequireLowercaseCharacters": True,
    "AllowUsersToChangePassword": True,
}

def update_password_policy():
    iam = boto3.client("iam")
    iam.update_account_password_policy(
        MinimumPasswordLength=PASSWORD_POLICY['MinimumPasswordLength'],
        RequireSymbols=PASSWORD_POLICY['RequireSymbols'],
        RequireNumbers=PASSWORD_POLICY['RequireNumbers'],
        RequireUppercaseCharacters=PASSWORD_POLICY['RequireUppercaseCharacters'],
        RequireLowercaseCharacters=PASSWORD_POLICY['RequireLowercaseCharacters'],
        AllowUsersToChangePassword=PASSWORD_POLICY['AllowUsersToChangePassword'],
    )

def check_password_policy():
    results = {
        'minimum_password_length': False,
        'require_symbols': False,
        'require_numbers': False,
        'require_uppercase_characters': False,
        'require_lowercase_characters': False,
        'allow_users_to_change_password': False,
    }

    iam = boto3.client("iam")
    res_password_policy = iam.get_account_password_policy()["PasswordPolicy"]

    results['minimum_password_length'] = res_password_policy['MinimumPasswordLength'] == PASSWORD_POLICY['MinimumPasswordLength']
    if not results['minimum_password_length']:
        logger.error(
            f'MinimumPasswordLength is not equal. {PASSWORD_POLICY["MinimumPasswordLength"]} expect but {res_password_policy["MinimumPasswordLength"]} ')

    results['require_symbols'] = res_password_policy['RequireSymbols'] == PASSWORD_POLICY['RequireSymbols']
    results['require_numbers'] = res_password_policy['RequireNumbers'] == PASSWORD_POLICY['RequireNumbers']
    results['require_uppercase_characters'] = res_password_policy['RequireUppercaseCharacters'] == PASSWORD_POLICY['RequireUppercaseCharacters']
    results['require_lowercase_characters'] = res_password_policy['RequireLowercaseCharacters'] == PASSWORD_POLICY['RequireLowercaseCharacters']
    results['allow_users_to_change_password'] = res_password_policy['AllowUsersToChangePassword'] == PASSWORD_POLICY['AllowUsersToChangePassword']

    return results

def lambda_handler(event, context):

    update_password_policy()

    is_resources = {
        'password_policy': False
    }

    check_results = check_password_policy()

    is_resources['password_policy'] = all(check_results.values())

    if not all(is_resources.values()):
        logger.error("Failed to update password policy")
        logger.error(json.dumps(check_results))
        logger.error(
            f"is_resources: {is_resources}"
        )
        raise Exception('Fail to check reource')

    logger.info("Succeeded in updating IAM password policy")
    logger.info(
        f"is_resources: {is_resources}"
    )
    return {
        "is_resources": is_resources
    }

やってみる

Lambdaを実行する

デフォルトでは以下の項目で設定されているので、これを変更していきます。

  • パスワードの最小長は8文字、最大長は128文字です。
  • 次の文字タイプの組み合わせのうち少なくとも3つ:大文字、小文字、数字、記号! @ # $ % ^ & * ( ) _ + - = [ ] { } | '
  • AWSアカウント名またはメールアドレスと同一ではありません
    参考:デフォルトのパスワードポリシー

上記の設定を更新して以下の5項目へ変更します。

  • パスワードの最小文字数は 8 文字
  • 1 文字以上のアルファベット大文字 (A~Z) を必要とする
  • 1 文字以上のアルファベット小文字 (a~z) を必要とする
  • 少なくとも 1 つの数字が必要
  • 少なくとも 1 つの英数字以外の文字が必要 (! @ # $ % ^ & * ( ) _ + - = { } | ')
  • ユーザーにパスワードの変更を許可する

コードを貼り付けてDeployした状態です。(LambdaのIAMロールや実行時間は適宜調整してください。)テストイベントはデフォルトのまま実行します。

実行が完了すると、以下のようにレスポンスや実行ログが出力されます。

Responseにはリソースの状態が出力されます。成功していればpassword_policyの値にtrueが入っているはずです。

Function Log には有効化が成功したことを示すログを出力しています。

コンソールを確認すると、想定した通りのパスワードポリシーが設定されていることが確認できました。

パスワードの最小文字数 12 文字に変更してみる

8文字ではなく12文字を最小文字数に設定したい場合は、以下の定数を定義している部分を変更してください。

import json
import boto3
import logging

logger = logging.getLogger()
logger.setLevel(logging.INFO)

PASSWORD_POLICY = {
    "MinimumPasswordLength": 12,
    "RequireSymbols": True,
    "RequireNumbers": True,
    "RequireUppercaseCharacters": True,
    "RequireLowercaseCharacters": True,
    "AllowUsersToChangePassword": True,
}
...

上記のように変更してLambdaへデプロイして実行すると、12文字が最小文字数として設定できました。

おわりに

LambdaからIAMのパスワードポリシーを更新してみました。別のパスワードポリシーへ変更したい場合にも、ある程度参考にできる部分はあるかと思います。

Control Tower環境であれば以下の仕組みと組み合わせることで、アカウント発行時の自動化フローを作成できます。活用方法の1つとしてご検討ください。