IAM: Allow CF to delete InstanceProfile with existing role (#7431)

This commit is contained in:
Bert Blommers 2024-03-06 22:22:00 +00:00 committed by GitHub
parent 8178cbde1a
commit 95e183b6af
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 81 additions and 4 deletions

View File

@ -957,7 +957,9 @@ class InstanceProfile(CloudFormationModel):
account_id: str,
region_name: str,
) -> None:
iam_backends[account_id]["global"].delete_instance_profile(resource_name)
iam_backends[account_id]["global"].delete_instance_profile(
resource_name, ignore_attached_roles=True
)
def delete_role(self, role_name: str) -> None:
self.roles = [role for role in self.roles if role.name != role_name]
@ -2370,9 +2372,11 @@ class IAMBackend(BaseBackend):
self.instance_profiles[name] = instance_profile
return instance_profile
def delete_instance_profile(self, name: str) -> None:
def delete_instance_profile(
self, name: str, ignore_attached_roles: bool = False
) -> None:
instance_profile = self.get_instance_profile(name)
if len(instance_profile.roles) > 0:
if len(instance_profile.roles) > 0 and not ignore_attached_roles:
raise IAMConflictException(
code="DeleteConflict",
message="Cannot delete entity, must remove roles from instance profile first.",

View File

@ -1 +1,28 @@
# This file is intentionally left blank.
import os
from functools import wraps
from moto import mock_aws
def iam_aws_verified(func):
"""
Function that is verified to work against AWS.
Can be run against AWS at any time by setting:
MOTO_TEST_ALLOW_AWS_REQUEST=true
If this environment variable is not set, the function runs in a `mock_aws` context.
"""
@wraps(func)
def pagination_wrapper():
allow_aws_request = (
os.environ.get("MOTO_TEST_ALLOW_AWS_REQUEST", "false").lower() == "true"
)
if allow_aws_request:
return func()
else:
with mock_aws():
return func()
return pagination_wrapper

View File

@ -1,4 +1,5 @@
import json
from uuid import uuid4
import boto3
import pytest
@ -8,6 +9,8 @@ from botocore.exceptions import ClientError
from moto import mock_aws
from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID
from tests import EXAMPLE_AMI_ID
from tests.test_iam import iam_aws_verified
from tests.test_iam.test_iam import MOCK_STS_EC2_POLICY_DOCUMENT
TEMPLATE_MINIMAL_ROLE = """
AWSTemplateFormatVersion: 2010-09-09
@ -1609,3 +1612,46 @@ def test_iam_roles():
if resource["ResourceType"] == "AWS::IAM::Role"
]
assert {r["PhysicalResourceId"] for r in role_resources} == set(role_names)
template_with_instance_profile = """
Parameters:
InputRole:
Type: String
Default: "test-emr-role"
Resources:
emrEc2InstanceProfile:
Type: 'AWS::IAM::InstanceProfile'
Properties:
Path: /
Roles:
- !Ref InputRole
"""
@iam_aws_verified
def test_delete_instance_profile_with_existing_role():
region = "us-east-1"
iam = boto3.client("iam", region_name=region)
iam_role_name = f"moto_{str(uuid4())[0:6]}"
iam.create_role(
RoleName=iam_role_name, AssumeRolePolicyDocument=MOCK_STS_EC2_POLICY_DOCUMENT
)
try:
cf = boto3.client("cloudformation", region_name=region)
cf.create_stack(
StackName="teststack",
TemplateBody=template_with_instance_profile,
Parameters=[{"ParameterKey": "InputRole", "ParameterValue": iam_role_name}],
Capabilities=["CAPABILITY_NAMED_IAM"],
)
# Just verify that we can delete the InstanceProfile
cf.delete_stack(StackName="teststack")
# The role still exists at this point
iam.get_role(RoleName=iam_role_name)
finally:
iam.delete_role(RoleName=iam_role_name)