Initializing Enclave...

Fixing IAM User Console Login 'Access Denied' After Password Policy Change in AWS

Threat/Impact Level: HIGH | Exploitability/Downtime Risk: HIGH | Time to Fix: 5–15 mins

TL;DR

  • What broke: An IAM account-level password policy was tightened (stricter length, complexity, or HardExpiry=true), and existing user passwords that predate the new policy are now rejected or force-expired on next login attempt — producing a silent Access Denied or an immediate forced-reset loop that blocks console access entirely.
  • How to fix it: Identify the specific policy field causing the rejection, either roll back that field temporarily or force a one-time admin password reset for affected users, then re-communicate the rotation requirement via a controlled change window.
  • Fast path: Use our Client-Side Sandbox above to paste your current IAM password policy JSON and get an auto-refactored policy with the conflicting fields highlighted and corrected.

The Incident (What Does the Error Mean?)

The user hits https://<account-id>.signin.aws.amazon.com/console, enters valid credentials, and receives:

Access Denied
Your request included invalid authentication credentials for the AWS Management Console.
Please try again.

or, on some policy configurations, is immediately redirected to a forced password-change screen that rejects every new password the user submits — because the new policy's complexity rules are not clearly surfaced in the UI error message.

Immediate consequence: The IAM user is effectively locked out of the console. If HardExpiry is set to true, the account is hard-blocked — no API calls, no console, no CLI using long-term credentials — until an IAM administrator resets the password. This is not a soft warning. The account is dead until manual intervention.

Raw policy state that triggers this (example):

{
  "MinimumPasswordLength": 14,
  "RequireSymbols": true,
  "RequireNumbers": true,
  "RequireUppercaseCharacters": true,
  "RequireLowercaseCharacters": true,
  "MaxPasswordAge": 1,
  "PasswordReusePrevention": 24,
  "HardExpiry": true
}

MaxPasswordAge: 1 combined with HardExpiry: true means any password older than 24 hours hard-locks the account. If this policy was pushed on a Friday afternoon, every user who didn't log in over the weekend is locked out Monday morning.


The Attack Vector / Blast Radius

This is a self-inflicted availability attack with a secondary security risk surface:

1. Mass lockout blast radius: A single update-account-password-policy call applies to every IAM user in the account simultaneously. There is no staged rollout. If your account has 200 IAM users and HardExpiry=true with MaxPasswordAge=1, you've just scheduled a mass lockout event. In organizations without SSO/IdP federation, this means 200 support tickets at 9 AM.

2. Privilege escalation window: When administrators scramble to fix lockouts, they frequently grant temporary AdministratorAccess or reset passwords without MFA verification — creating a social engineering opportunity. An attacker who knows a policy change is in flight can call the help desk impersonating a locked-out executive.

3. Break-glass account exposure: Teams often respond to mass lockouts by using a shared break-glass root or admin account. If that account's credentials are not rotated and properly vaulted, the incident itself becomes the attack vector.

4. HardExpiry is irreversible from the user side: Unlike a soft expiry (which prompts a password change on login), HardExpiry: true returns Access Denied with no recovery path for the user. Only an IAM principal with iam:UpdateLoginProfile can unlock them. If your only admin is also locked out, you are escalating to root account recovery.


How to Fix It (The Solution)

Basic Fix — Emergency Unlock a Specific User

If a single user is locked out, reset their password immediately via CLI:

aws iam update-login-profile \
  --user-name <locked-username> \
  --password "TempP@ssw0rd!2024" \
  --password-reset-required

This forces a password change on next login and bypasses the hard expiry block. Requires iam:UpdateLoginProfile permission on the calling principal.


Enterprise Best Practice — Fix the Root Policy

The actual fix is correcting the policy that caused the lockout. The two most dangerous fields are HardExpiry and an unrealistically short MaxPasswordAge.

# aws iam update-account-password-policy (effective policy diff)

 {
   "MinimumPasswordLength": 14,
   "RequireSymbols": true,
   "RequireNumbers": true,
   "RequireUppercaseCharacters": true,
   "RequireLowercaseCharacters": true,
-  "MaxPasswordAge": 1,
+  "MaxPasswordAge": 90,
-  "PasswordReusePrevention": 24,
+  "PasswordReusePrevention": 12,
-  "HardExpiry": true
+  "HardExpiry": false
 }

Why these specific changes:

  • MaxPasswordAge: 90 — aligns with NIST SP 800-63B guidance (periodic rotation is less important than breach detection; 90 days is the enterprise compliance floor for most frameworks including SOC 2 and ISO 27001).
  • PasswordReusePrevention: 12 — 24 previous passwords is excessive and causes users to cycle through trivial variations; 12 is the PCI-DSS requirement and a defensible audit position.
  • HardExpiry: falsenever set this to true in production without a tested, automated unlock workflow in place. Soft expiry prompts a change on login; hard expiry kills the account silently.

Apply via CLI:

aws iam update-account-password-policy \
  --minimum-password-length 14 \
  --require-symbols \
  --require-numbers \
  --require-uppercase-characters \
  --require-lowercase-characters \
  --max-password-age 90 \
  --password-reuse-prevention 12 \
  --no-hard-expiry

Verify the applied policy:

aws iam get-account-password-policy

💡 Tired of pasting proprietary configs into ChatGPT? Generic AI tools log your company's ARNs, DB strings, and private keys. StackEngine is a zero-backend, pure Client-Side WASM utility. Drop your failing config into the sandbox above. We redact your secrets locally in the browser and auto-generate the refactored code using your own API key.


Prevention in CI/CD

Password policy changes should never be a manual aws iam update-account-password-policy call in production. Treat this as infrastructure.

1. Enforce via Terraform with guardrails

# terraform/iam_password_policy.tf

 resource "aws_iam_account_password_policy" "strict" {
   minimum_password_length        = 14
   require_symbols                = true
   require_numbers                = true
   require_uppercase_characters   = true
   require_lowercase_characters   = true
   max_password_age               = 90
   password_reuse_prevention      = 12
-  hard_expiry                    = true
+  hard_expiry                    = false
 }

2. Block dangerous policy values with Checkov

Add a custom Checkov check or use the built-in CKV_AWS_9 (password policy expiry) and CKV_AWS_10 (minimum length). Add a custom policy for hard_expiry:

# .checkov/custom_checks/no_hard_expiry.yaml
metadata:
  name: "IAM password policy must not set hard_expiry to true"
  id: "CKV2_AWS_CUSTOM_001"
  severity: HIGH
scope:
  provider: aws
definition:
  and:
    - cond_type: attribute
      resource_types: ["aws_iam_account_password_policy"]
      attribute: hard_expiry
      operator: equals
      value: false

3. Gate policy changes with AWS Config Rule

Enable the managed Config rule iam-password-policy and configure it with your required parameter values. Any drift from the approved policy triggers a finding in Security Hub within minutes — before the lockout wave hits.

aws configservice put-config-rule --config-rule '{
  "ConfigRuleName": "iam-password-policy",
  "Source": {
    "Owner": "AWS",
    "SourceIdentifier": "IAM_PASSWORD_POLICY"
  },
  "InputParameters": "{\"MaxPasswordAge\":\"90\",\"MinimumPasswordLength\":\"14\",\"RequireSymbols\":\"true\",\"HardExpiry\":\"false\"}"
}'

4. Change management rule (non-negotiable)

Before any update-account-password-policy call in production:

  1. Run aws iam generate-credential-report and identify all users with passwords older than the new MaxPasswordAge.
  2. Send forced-reset notifications to those users before applying the policy.
  3. Apply the policy during a maintenance window, not ad hoc.
  4. Have a runbook pre-written for iam:UpdateLoginProfile bulk resets if the rollout fails.

Related Diagnostics

"Part of the Security Utility Matrix."

View all 140 Security Tools →