Back to Checks
aws

Regular Bedrock access ensures IAM users retain only actively used permissions

iam_user_access_not_stale_to_bedrock
Service: iamSeverity: medium
OfficialBuilt-inVerified
Categories:identity-accessgen-ai
Resource Type:AwsIamUser

IAM users granted Bedrock permissions are evaluated for recent service usage.

Users whose last Bedrock access exceeds the configured threshold (default 60 days) or that have never accessed Bedrock are flagged, indicating stale permissions that should be reviewed.

Risk

Stale Bedrock permissions widen the blast radius of a credential compromise.

An attacker who gains access to a user with unused Bedrock permissions can invoke foundation models, exfiltrate data through model responses, or incur significant costs — all without triggering expected usage patterns.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler aws --checks iam_user_access_not_stale_to_bedrock

Recommendation

Apply the principle of least privilege by regularly reviewing IAM Access Advisor data and revoking Bedrock permissions that are no longer actively used.

Establish a periodic access review process and automate alerts for stale permissions to maintain a minimal attack surface.

Remediation

Other

1Open the IAM console and select the user
2Review the **Access Advisor** tab to confirm Bedrock has not been accessed recently
3Remove or detach any policies granting Bedrock permissions that are no longer needed
4If the user still requires Bedrock access, verify usage and reduce scope to least privilege

Check Code

from datetime import datetime, timezone
from typing import Optional

from dateutil.parser import parse

from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.iam.iam_client import iam_client


class iam_user_access_not_stale_to_bedrock(Check):
    """Detect IAM users with stale Bedrock permissions.

    This check evaluates whether IAM users with Bedrock service permissions
    have actively used those permissions within the configured threshold
    (default 60 days).

    - PASS: The user has accessed Bedrock within the allowed period.
    - FAIL: The user has Bedrock permissions but has not used them within
      the allowed period or has never used them.
    """

    def execute(self) -> list[Check_Report_AWS]:
        """Execute the Bedrock access staleness check for IAM users.

        Iterates over IAM users, inspecting service last accessed data for
        the ``bedrock`` namespace. Users whose last Bedrock access exceeds
        the configured threshold are reported as non-compliant.

        Returns:
            A list of reports containing the result of the check.
        """
        findings = []
        max_unused_bedrock_days = iam_client.audit_config.get(
            "max_unused_bedrock_access_days", 60
        )

        for user in iam_client.users:
            last_accessed_services = iam_client.last_accessed_services.get(
                (user.name, user.arn), []
            )
            bedrock_service = self._find_bedrock_service(last_accessed_services)
            if bedrock_service is None:
                continue

            report = Check_Report_AWS(metadata=self.metadata(), resource=user)
            report.region = iam_client.region

            self._evaluate_bedrock_staleness(
                report,
                bedrock_service,
                max_unused_bedrock_days,
                user.name,
                "User",
            )
            findings.append(report)

        return findings

    @staticmethod
    def _find_bedrock_service(
        last_accessed_services: list[dict],
    ) -> Optional[dict]:
        """Return the Bedrock entry from a service last accessed list."""
        for service in last_accessed_services:
            if service.get("ServiceNamespace") == "bedrock":
                return service
        return None

    @staticmethod
    def _evaluate_bedrock_staleness(
        report: Check_Report_AWS,
        bedrock_service: dict,
        max_days: int,
        identity_name: str,
        identity_type: str,
    ) -> None:
        """Populate a check report based on Bedrock access recency."""
        last_authenticated = bedrock_service.get("LastAuthenticated")
        if last_authenticated is None:
            report.status = "FAIL"
            report.status_extended = (
                f"IAM {identity_type} {identity_name} has Bedrock permissions "
                f"but has never used them."
            )
            return

        if isinstance(last_authenticated, str):
            last_authenticated = parse(last_authenticated)

        days_since_access = (datetime.now(timezone.utc) - last_authenticated).days

        if days_since_access > max_days:
            report.status = "FAIL"
            report.status_extended = (
                f"IAM {identity_type} {identity_name} has not accessed Bedrock "
                f"in {days_since_access} days (threshold: {max_days} days)."
            )
        else:
            report.status = "PASS"
            report.status_extended = (
                f"IAM {identity_type} {identity_name} accessed Bedrock "
                f"{days_since_access} days ago (threshold: {max_days} days)."
            )