如何实现AWS IAM用户3次登录失败后锁定并定时解锁?
IAM用户连续登录失败锁定方案审核与改进
现有方案的问题点
1. IAM策略问题
- 直接
Deny *过于严格,会禁止该用户所有AWS操作(包括已授权的资源访问),风险过高,应仅限制登录相关操作。 - 条件
aws:MultiFactorAuthAge针对已完成MFA验证的会话,与目标的「未使用MFA的用户」场景不匹配,属于无效条件。 aws:FailedLoginAttempts的逻辑依赖AWS内部的失败次数统计,但该值并非实时累计的连续失败次数,无法准确触发预期规则。
2. Lambda函数问题
- 未处理重复触发场景:用户第4次登录失败时,会重复执行
attach_user_policy,导致同一策略多次附加(属于冗余操作)。 - 缺少自动解锁逻辑:仅实现锁定,无法满足「5分钟后自动解锁」的需求。
- 未添加异常处理:若事件中
userName字段缺失或IAM调用失败,Lambda会直接报错终止。
3. CloudWatch事件规则问题
- 仅捕获单次登录失败事件,无法实现「60秒内3次失败」的统计触发逻辑,会导致每次失败都调用Lambda,而非累计到3次才触发。
改进后的成熟实现方案
1. 优化后的IAM锁定策略(仅限制登录操作)
{ "Version": "2012-10-17", "Statement": [ { "Sid": "DenyConsoleLogin", "Effect": "Deny", "Action": [ "sts:GetSessionToken", "sts:GetFederationToken", "iam:ListAccountAliases", "signin:Login" ], "Resource": "*" } ] }
说明:仅禁止控制台登录、获取会话令牌等核心登录操作,不影响用户已授权的资源访问(如S3、EC2等)。
2. 完善后的Lambda函数(含锁定+定时解锁)
import boto3 import os from datetime import datetime, timedelta import json iam = boto3.client('iam') events = boto3.client('events') LOCK_POLICY_ARN = os.environ['LOCK_POLICY_ARN'] LOCK_DURATION_MINUTES = 5 def lambda_handler(event, context): try: # 提取用户名 username = event['detail']['userIdentity']['userName'] # 检查是否已附加锁定策略,避免重复操作 attached_policies = iam.list_attached_user_policies(UserName=username) policy_exists = any(policy['PolicyArn'] == LOCK_POLICY_ARN for policy in attached_policies['AttachedPolicies']) if not policy_exists: iam.attach_user_policy( UserName=username, PolicyArn=LOCK_POLICY_ARN ) print(f"已锁定用户: {username}") # 配置5分钟后自动解锁的定时事件 unlock_time = datetime.utcnow() + timedelta(minutes=LOCK_DURATION_MINUTES) rule_name = f"UnlockUser-{username}-{int(datetime.utcnow().timestamp())}" events.put_rule( Name=rule_name, ScheduleExpression=f"at({unlock_time.strftime('%Y-%m-%dT%H:%M:%S')})", State='ENABLED' ) events.put_targets( Rule=rule_name, Targets=[ { 'Id': '1', 'Arn': context.invoked_function_arn.replace('lock', 'unlock'), 'Input': json.dumps({'username': username, 'rule_name': rule_name}) } ] ) else: print(f"用户 {username} 已处于锁定状态,无需重复操作") except Exception as e: print(f"处理失败: {str(e)}") raise e # 解锁专用Lambda函数 def unlock_user_handler(event, context): try: username = event['username'] rule_name = event['rule_name'] iam.detach_user_policy( UserName=username, PolicyArn=LOCK_POLICY_ARN ) print(f"已解锁用户: {username}") # 删除临时解锁规则 events.remove_targets(Rule=rule_name, Ids=['1']) events.delete_rule(Name=rule_name) except Exception as e: print(f"解锁失败: {str(e)}") raise e
说明:
- 通过环境变量配置策略ARN,提高可维护性。
- 锁定前检查策略是否已附加,避免冗余操作。
- 利用CloudWatch Events定时触发解锁逻辑,实现5分钟自动解锁。
- 添加异常捕获与日志输出,便于问题排查。
3. CloudWatch Alarm(实现60秒内3次失败触发)
基于CloudTrail的
ConsoleLogin失败事件创建Metric Filter:- 过滤规则:
{$.eventName = "ConsoleLogin" && $.responseElements.ConsoleLogin = "Failure"} - 命名空间:
IAM/LoginFailures - 指标名称:
FailedLoginAttempts - 维度:
userName
- 过滤规则:
创建CloudWatch Alarm:
- 指标:
IAM/LoginFailures/FailedLoginAttempts(按userName维度) - 统计周期:60秒
- 阈值:>=3
- 触发动作:调用锁定Lambda函数
- 指标:
额外优化建议
- 针对使用MFA的用户,可在策略中添加例外规则,避免影响已启用MFA的安全用户。
- 记录锁定/解锁操作到CloudTrail,便于审计追溯。
- 配置SNS通知,当用户被锁定时发送告警邮件给管理员。
内容的提问来源于stack exchange,提问作者Mohamad
相关产品推荐
相关产品推荐

