diff --git a/moto/iam/models.py b/moto/iam/models.py index 5346d652a..023bcb493 100644 --- a/moto/iam/models.py +++ b/moto/iam/models.py @@ -84,9 +84,17 @@ def mark_account_as_visited( ) -> None: account = iam_backends[account_id] if access_key in account["global"].access_keys: - account["global"].access_keys[access_key].last_used = AccessKeyLastUsed( + key = account["global"].access_keys[access_key] + key.last_used = AccessKeyLastUsed( timestamp=utcnow(), service=service, region=region ) + if key.role_arn: + try: + role = account["global"].get_role_by_arn(key.role_arn) + role.last_used = utcnow() + except IAMNotFoundException: + # User assumes a non-existing role + pass else: # User provided access credentials unknown to us pass @@ -1082,6 +1090,7 @@ class AccessKey(CloudFormationModel): self.status = status self.create_date = utcnow() self.last_used: Optional[datetime] = None + self.role_arn: Optional[str] = None @property def created_iso_8601(self) -> str: diff --git a/moto/sts/models.py b/moto/sts/models.py index 5423761c5..b465b0039 100644 --- a/moto/sts/models.py +++ b/moto/sts/models.py @@ -108,6 +108,7 @@ class STSBackend(BaseBackend): duration, external_id, ) + access_key.role_arn = role_arn account_backend = sts_backends[account_id]["global"] account_backend.assumed_roles.append(role) return role diff --git a/tests/test_iam/test_iam_access_integration.py b/tests/test_iam/test_iam_access_integration.py index 70a8c03fe..b977fb8aa 100644 --- a/tests/test_iam/test_iam_access_integration.py +++ b/tests/test_iam/test_iam_access_integration.py @@ -1,5 +1,9 @@ +import datetime + import boto3 -from moto import mock_ec2, mock_iam +from moto import mock_ec2, mock_iam, mock_sts, settings +from moto.iam.models import iam_backends, IAMBackend +from tests import DEFAULT_ACCOUNT_ID @mock_ec2 @@ -23,3 +27,36 @@ def test_invoking_ec2_mark_access_key_as_used(): assert "LastUsedDate" in last_used assert last_used["ServiceName"] == "ec2" assert last_used["Region"] == "us-east-2" + + +@mock_iam +@mock_sts +def test_mark_role_as_last_used(): + role_name = "role_name_created_jan_1st" + iam = boto3.client("iam", "us-east-1") + sts = boto3.client("sts", "us-east-1") + + role_arn = iam.create_role(RoleName=role_name, AssumeRolePolicyDocument="example")[ + "Role" + ]["Arn"] + + creds = sts.assume_role(RoleArn=role_arn, RoleSessionName="temp_session")[ + "Credentials" + ] + + iam2 = boto3.client( + "iam", + "us-east-1", + aws_access_key_id=creds["AccessKeyId"], + aws_secret_access_key=creds["SecretAccessKey"], + aws_session_token=creds["SessionToken"], + ) + + iam2.create_role(RoleName="name", AssumeRolePolicyDocument="example") + + role = iam.get_role(RoleName=role_name)["Role"] + assert isinstance(role["RoleLastUsed"]["LastUsedDate"], datetime.datetime) + + if not settings.TEST_SERVER_MODE: + iam: IAMBackend = iam_backends[DEFAULT_ACCOUNT_ID]["global"] + assert iam.get_role(role_name).last_used is not None diff --git a/tests/test_iam/test_iam_resets.py b/tests/test_iam/test_iam_resets.py index 0422a0ec7..49a2397c4 100644 --- a/tests/test_iam/test_iam_resets.py +++ b/tests/test_iam/test_iam_resets.py @@ -6,8 +6,8 @@ from moto import mock_iam # Test IAM User Inline Policy def test_policies_are_not_kept_after_mock_ends(): - iam_client = boto3.client("iam", "us-east-1") with mock_iam(): + iam_client = boto3.client("iam", "us-east-1") role_name = "test" assume_role_policy_document = { "Version": "2012-10-17",