Back to Checks
AWS account root user has not been used in the last day
iam_avoid_root_usage
Service: iamSeverity: high
OfficialBuilt-inVerified
Categories:identity-access
Resource Type:AwsIamUser
AWS IAM root user activity is assessed by inspecting last-used timestamps for the root password and access keys. The finding indicates when the root identity has been used recently for console or programmatic access.
Risk
Recent root usage expands blast radius:
- Data exfiltration (confidentiality)
- Policy/key tampering (integrity)
- Resource deletion and billing changes (availability) Routine use reduces anomaly visibility and eases account takeover impact.
Run this check with Prowler
Run in Prowler CloudRun
prowler aws --checks iam_avoid_root_usageRecommendation
Minimize root usage by applying least privilege with admin roles or federated SSO and temporary credentials.
- Enforce MFA on root
- Avoid or remove root access keys
- Require multi-person approval
- Monitor and alert on any root sign-in
- Use org guardrails for defense in depth
Remediation
Other
1Sign in to the AWS Management Console as the root user
2In the top-right, click your account name > Security credentials
3Under Access keys for the root user, delete all existing keys
4Sign out of the root user and do not use it again
5Wait 24 hours (until the root user has not been accessed for a full day) for the check to pass
Check Code
import datetime
import pytz
from dateutil import parser
from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.iam.iam_client import iam_client
maximum_access_days = 1
class iam_avoid_root_usage(Check):
def execute(self) -> Check_Report_AWS:
findings = []
response = iam_client.credential_report
for user in response:
if user["user"] == "<root_account>":
report = Check_Report_AWS(metadata=self.metadata(), resource=user)
report.region = iam_client.region
report.resource_id = user["user"]
report.resource_arn = user["arn"]
if (
user["password_last_used"] != "no_information"
or user["access_key_1_last_used_date"] != "N/A"
or user["access_key_2_last_used_date"] != "N/A"
):
if user["password_last_used"] != "no_information":
days_since_accessed = (
datetime.datetime.now(pytz.utc)
- parser.parse(user["password_last_used"])
).days
elif user["access_key_1_last_used_date"] != "N/A":
days_since_accessed = (
datetime.datetime.now(pytz.utc)
- parser.parse(user["access_key_1_last_used_date"])
).days
elif user["access_key_2_last_used_date"] != "N/A":
days_since_accessed = (
datetime.datetime.now(pytz.utc)
- parser.parse(user["access_key_2_last_used_date"])
).days
if maximum_access_days >= days_since_accessed:
report.status = "FAIL"
report.status_extended = f"Root user in the account was last accessed {days_since_accessed} days ago."
else:
report.status = "PASS"
report.status_extended = f"Root user in the account wasn't accessed in the last {maximum_access_days} days."
else:
report.status = "PASS"
report.status_extended = f"Root user in the account wasn't accessed in the last {maximum_access_days} days."
findings.append(report)
return findings