Back to Checks
aws

Amazon Bedrock long-term API key has expired

bedrock_api_key_no_long_term_credentials
Service: bedrockSeverity: high
OfficialBuilt-inVerified
Categories:secretsgen-ai
Resource Type:AwsIamUser

AWS recommends Amazon Bedrock long-term API keys only for exploration; production workloads should use short-term API keys (session-scoped, valid up to 12 hours). This check fails for any active long-term Bedrock API key, escalating to critical severity when configured to never expire. Already-expired keys pass — they can no longer authenticate.

Risk

Long-term Bedrock API keys persist beyond a session until their stored expiration, and keys set to never expire grant indefinite access until manually revoked, enabling unauthorized inference, uncontrolled usage and spend, and activity that continues past timely revocation.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler aws --checks bedrock_api_key_no_long_term_credentials

Recommendation

Use short-term Amazon Bedrock API keys for any non-exploratory workload — they are bound to the IAM principal's session, valid for at most 12 hours, scoped to a single Region, and can be auto-refreshed by the SDK. For existing long-term keys, delete the underlying IAM service-specific credential. If a long-term key must be retained for an exploration scenario, set an explicit short expiration and never select never expire.

Remediation

CLI

aws iam delete-service-specific-credential --user-name <username> --service-specific-credential-id <credential-id>

Other

1Sign in to the AWS Management Console and open IAM
2Go to Users > select the IAM user backing the Bedrock API key > Security credentials
3In "API keys for Amazon Bedrock", select the active long-term key and click Delete
4For workloads that still need Bedrock access, generate a short-term API key from the Bedrock console (Short-term API keys tab), or call the Bedrock API with short-term credentials issued by AWS STS

Check Code

from datetime import datetime, timezone

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

# Days threshold above which a Bedrock long-term API key is considered effectively non-expiring.
NEVER_EXPIRES_THRESHOLD_DAYS = 10000


class bedrock_api_key_no_long_term_credentials(Check):
    """Amazon Bedrock long-term API keys should not be used outside of exploration.

    AWS recommends short-term Bedrock API keys (session-scoped, valid up to 12 hours)
    for any non-exploratory workload. ``ListServiceSpecificCredentials`` only enumerates
    long-term keys, so every key inspected here is by definition a long-term credential.

    PASS when the long-term key has already expired (it can no longer authenticate).
    FAIL (critical) when the key is configured to never expire.
    FAIL (high) for any other active long-term key.
    """

    def execute(self):
        findings = []
        for api_key in iam_client.service_specific_credentials:
            if api_key.service_name != "bedrock.amazonaws.com":
                continue
            if not api_key.expiration_date:
                continue

            report = Check_Report_AWS(metadata=self.metadata(), resource=api_key)
            now = datetime.now(timezone.utc)

            if api_key.expiration_date <= now:
                report.status = "PASS"
                report.status_extended = (
                    f"Bedrock long-term API key {api_key.id} in user "
                    f"{api_key.user.name} has already expired and can no longer "
                    f"authenticate."
                )
            elif (api_key.expiration_date - now).days > NEVER_EXPIRES_THRESHOLD_DAYS:
                report.status = "FAIL"
                report.check_metadata.Severity = Severity.critical
                report.status_extended = (
                    f"Bedrock long-term API key {api_key.id} in user "
                    f"{api_key.user.name} is configured to never expire. Use "
                    f"short-term Bedrock API keys (session-scoped, valid up to "
                    f"12 hours) for non-exploratory workloads instead."
                )
            else:
                days_until_expiration = (api_key.expiration_date - now).days
                report.status = "FAIL"
                report.status_extended = (
                    f"Bedrock long-term API key {api_key.id} in user "
                    f"{api_key.user.name} is active and will expire in "
                    f"{days_until_expiration} days. Use short-term Bedrock API "
                    f"keys (session-scoped, valid up to 12 hours) for "
                    f"non-exploratory workloads instead."
                )

            findings.append(report)

        return findings