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
AssumeRolecall (console federation orsts:AssumeRoleAPI) passedDurationSeconds > 3600. AWS enforces a hard 1-hour ceiling for console sessions regardless of the role'sMaxSessionDurationsetting. - How to fix it: Set
DurationSecondsto≤ 3600in the federation call, or switch to a programmatic (non-console) flow whereMaxSessionDurationup 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.