Initializing Enclave...

Fixing AWS AssumeRole 'DurationSeconds Exceeds 1 Hour Limit' for Console Federation Sessions

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


TL;DR

  • What broke: Your AssumeRole call (console federation or sts:AssumeRole API) passed DurationSeconds > 3600. AWS enforces a hard 1-hour ceiling for console sessions regardless of the role's MaxSessionDuration setting.
  • How to fix it: Set DurationSeconds to ≤ 3600 in the federation call, or switch to a programmatic (non-console) flow where MaxSessionDuration up to 43200 is honored.
  • Fast path: Use our Client-Side Sandbox below to auto-refactor this — paste your federation script or Terraform block and get corrected code without leaking ARNs.

The Incident (What Does the Error Mean?)

Raw error output:

An error occurred (ValidationError) when calling the AssumeRole operation:
The requested DurationSeconds exceeds the 1 hour limit for roles assumed by
federated users or assumed via the console.

Immediate consequence: The AssumeRole call returns HTTP 400. No temporary credentials are issued. The federated user sees an access-denied or blank console screen. If this is inside an automation pipeline bootstrapping console access for break-glass accounts or SAML federation, the entire login flow is dead until the parameter is corrected.

This is not a permissions error. IAM policy evaluation never runs. STS rejects the request at parameter validation before any policy is consulted.


The Attack Vector / Blast Radius

This misconfiguration surfaces in two failure modes:

1. Operational outage: Any SAML/OIDC federation broker, custom identity portal, or aws sts assume-role wrapper that hardcodes DurationSeconds=43200 (or any value > 3600) for console sign-in URLs will fail 100% of the time. Break-glass runbooks that rely on extended sessions will be non-functional precisely when you need them most — during an incident.

2. Security policy bypass attempt (insider threat surface): Attackers or misconfigured automation attempting to generate long-lived console sessions via federation are silently trying to extend the blast radius of a compromised identity. A session token valid for 12 hours instead of 1 hour gives an adversary a dramatically wider window to exfiltrate data, pivot to other services, or establish persistence (rogue IAM users, Lambda backdoors) before the credential expires. AWS's 1-hour console cap is a deliberate security control — misconfiguring it to attempt bypass is a red flag in CloudTrail.

CloudTrail fingerprint of the failed attempt:

{
  "eventName": "AssumeRole",
  "errorCode": "ValidationError",
  "errorMessage": "The requested DurationSeconds exceeds the 1 hour limit...",
  "requestParameters": {
    "durationSeconds": 43200
  }
}

This event is logged. If you see it repeatedly from an unexpected principal, treat it as a probing attempt.


How to Fix It (The Solution)

Basic Fix — Cap DurationSeconds at 3600

If you are generating a console sign-in URL via the federation endpoint (https://signin.aws.amazon.com/federation), the AssumeRole call feeding it must use DurationSeconds ≤ 3600.

import boto3

client = boto3.client('sts')

response = client.assume_role(
    RoleArn='arn:aws:iam::123456789012:role/MyFederatedRole',
    RoleSessionName='ConsoleSession',
-   DurationSeconds=43200
+   DurationSeconds=3600
)

Enterprise Best Practice — Enforce MaxSessionDuration Correctly Per Flow Type

The confusion arises because MaxSessionDuration on the IAM role (up to 43200 seconds) applies only to programmatic/CLI AssumeRole calls, not console federation. Separate your role definitions by use case and enforce this in your IaC.

Terraform:

resource "aws_iam_role" "console_federated_role" {
  name = "console-federated-role"
  assume_role_policy = data.aws_iam_policy_document.trust.json

- max_session_duration = 43200  # Wrong: misleads engineers into passing 43200 to STS for console
+ max_session_duration = 3600   # Correct: signals this role is console-only; enforce via tagging convention
}

resource "aws_iam_role" "programmatic_automation_role" {
  name = "automation-role"
  assume_role_policy = data.aws_iam_policy_document.trust_automation.json

+ max_session_duration = 43200  # Correct: programmatic flows can use extended duration
}

Trust policy — add a condition to block console federation on long-duration roles:

{
  "Effect": "Allow",
  "Principal": { "Federated": "arn:aws:iam::123456789012:saml-provider/MyIdP" },
  "Action": "sts:AssumeRoleWithSAML",
  "Condition": {
+   "NumericLessThanEquals": {
+     "saml:sub_type": "persistent"
+   },
+   "NumericLessThanEquals": {
+     "sts:DurationSeconds": "3600"
+   }
  }
}

💡 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

1. Checkov — block DurationSeconds > 3600 in IaC:

Add a custom Checkov check or use the built-in CKV_AWS_61 (IAM role max session duration). For inline STS calls in Lambda/scripts, add a checkov custom policy:

# .checkov/custom_checks/assume_role_duration.yaml
metadata:
  name: "CUSTOM_STS_01"
  id: "CKV2_AWS_CUSTOM_01"
  category: "IAM"
definition:
  and:
    - cond_type: "attribute"
      resource_types: ["aws_iam_role"]
      attribute: "max_session_duration"
      operator: "less_than_or_equal"
      value: 3600
      # Scope this check only to roles tagged for console use

2. OPA/Rego — Conftest policy for Terraform plans:

package terraform.iam

deny[msg] {
  role := input.resource_changes[_]
  role.type == "aws_iam_role"
  role.change.after.max_session_duration > 3600
  role.change.after.tags.use_case == "console"
  msg := sprintf(
    "Role '%v' is tagged for console use but max_session_duration=%v exceeds 3600.",
    [role.name, role.change.after.max_session_duration]
  )
}

3. CloudTrail Alarm — alert on repeated ValidationError for AssumeRole:

aws cloudwatch put-metric-filter \
  --log-group-name CloudTrail/DefaultLogGroup \
  --filter-name AssumeRoleDurationViolation \
  --filter-pattern '{ ($.eventName = "AssumeRole") && ($.errorCode = "ValidationError") && ($.errorMessage = "*DurationSeconds*") }' \
  --metric-transformations \
    metricName=AssumeRoleDurationErrors,metricNamespace=Security/IAM,metricValue=1

Wire this metric to an SNS alarm. Three hits in five minutes from the same principal warrants immediate investigation.

4. Tag-based enforcement convention:

Tag all console-federation roles with use_case=console and enforce in your pipeline that any role with this tag has max_session_duration ≤ 3600. This creates a self-documenting guardrail that survives engineer turnover.

Related Diagnostics

"Part of the Security Utility Matrix."

View all 140 Security Tools →