IAM: Allow CF to delete InstanceProfile with existing role (#7431)
This commit is contained in:
parent
8178cbde1a
commit
95e183b6af
@ -957,7 +957,9 @@ class InstanceProfile(CloudFormationModel):
|
|||||||
account_id: str,
|
account_id: str,
|
||||||
region_name: str,
|
region_name: str,
|
||||||
) -> None:
|
) -> 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:
|
def delete_role(self, role_name: str) -> None:
|
||||||
self.roles = [role for role in self.roles if role.name != role_name]
|
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
|
self.instance_profiles[name] = instance_profile
|
||||||
return 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)
|
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(
|
raise IAMConflictException(
|
||||||
code="DeleteConflict",
|
code="DeleteConflict",
|
||||||
message="Cannot delete entity, must remove roles from instance profile first.",
|
message="Cannot delete entity, must remove roles from instance profile first.",
|
||||||
|
@ -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
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import json
|
import json
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
import boto3
|
import boto3
|
||||||
import pytest
|
import pytest
|
||||||
@ -8,6 +9,8 @@ from botocore.exceptions import ClientError
|
|||||||
from moto import mock_aws
|
from moto import mock_aws
|
||||||
from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID
|
from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID
|
||||||
from tests import EXAMPLE_AMI_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 = """
|
TEMPLATE_MINIMAL_ROLE = """
|
||||||
AWSTemplateFormatVersion: 2010-09-09
|
AWSTemplateFormatVersion: 2010-09-09
|
||||||
@ -1609,3 +1612,46 @@ def test_iam_roles():
|
|||||||
if resource["ResourceType"] == "AWS::IAM::Role"
|
if resource["ResourceType"] == "AWS::IAM::Role"
|
||||||
]
|
]
|
||||||
assert {r["PhysicalResourceId"] for r in role_resources} == set(role_names)
|
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)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user