Back to Checks
alibabacloud

Access keys are rotated every 90 days or less

ram_rotate_access_key_90_days
Service: ramSeverity: medium
OfficialBuilt-inVerified
Categories:secrets
Resource Type:ALIYUN::RAM::User

Alibaba Cloud RAM access keys consist of an access key ID and a secret, which are used to sign programmatic requests. RAM users need their own access keys to make programmatic calls from SDKs, CLIs, or direct API calls. It is recommended that all access keys be regularly rotated every 90 days or less to reduce the window of opportunity for compromised keys to be used.

Risk

Access keys might be compromised by being left in code, configuration files, or cloud storage and then stolen by attackers. Without regular access key rotation, a compromised key can remain valid indefinitely, allowing persistent unauthorized access. This threatens the confidentiality, integrity, and availability of all resources accessible via those credentials.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler alibabacloud --checks ram_rotate_access_key_90_days

Recommendation

Rotate all RAM user access keys every 90 days or less to limit the impact of compromised credentials.

Remediation

CLI

aliyun ram CreateAccessKey --UserName <ram_user> && aliyun ram UpdateAccessKey --UserAccessKeyId <old_access_key_ID> --Status Inactive --UserName <ram_user> && aliyun ram DeleteAccessKey --UserAccessKeyId <old_access_key_ID> --UserName <ram_user>

Other

1Create a new **AccessKey pair** for rotation.
2Update all applications and systems to use the new AccessKey pair.
3*Disable** the original AccessKey pair.
4Confirm that your applications and systems are working.
5*Delete** the original AccessKey pair.

Check Code

from datetime import datetime, timedelta, timezone

from prowler.lib.check.models import Check, CheckReportAlibabaCloud
from prowler.providers.alibabacloud.services.ram.ram_client import ram_client


class ram_rotate_access_key_90_days(Check):
    """Check if access keys are rotated every 90 days or less."""

    def execute(self) -> list[CheckReportAlibabaCloud]:
        findings = []
        # Use UTC timezone-aware datetime for consistent comparison
        now = datetime.now(timezone.utc)
        ninety_days_ago = now - timedelta(days=90)

        for user in ram_client.users:
            if user.access_keys:
                for access_key in user.access_keys:
                    # Only check active access keys
                    if access_key.status == "Active":
                        report = CheckReportAlibabaCloud(
                            metadata=self.metadata(), resource=user
                        )
                        report.region = ram_client.region
                        report.resource_id = access_key.access_key_id
                        report.resource_arn = f"acs:ram::{ram_client.audited_account}:user/{user.name}/accesskey/{access_key.access_key_id}"

                        if access_key.create_date:
                            # Ensure create_date is timezone-aware for comparison
                            create_date = access_key.create_date
                            if create_date.tzinfo is None:
                                # If naive, assume UTC
                                create_date = create_date.replace(tzinfo=timezone.utc)

                            if create_date < ninety_days_ago:
                                report.status = "FAIL"
                                days_old = (now - create_date).days
                                report.status_extended = (
                                    f"Access key {access_key.access_key_id} for user {user.name} "
                                    f"has not been rotated in {days_old} days (more than 90 days)."
                                )
                            else:
                                report.status = "PASS"
                                days_old = (now - create_date).days
                                report.status_extended = (
                                    f"Access key {access_key.access_key_id} for user {user.name} "
                                    f"was created {days_old} days ago (within 90 days)."
                                )
                        else:
                            report.status = "PASS"
                            report.status_extended = (
                                f"Access key {access_key.access_key_id} for user {user.name} "
                                f"creation date is not available."
                            )

                        findings.append(report)

        return findings