Skip to content

Commit 9d38018

Browse files
author
Taniya Mathur
committed
updated cleanup steps
1 parent 4160eee commit 9d38018

File tree

3 files changed

+70
-131
lines changed

3 files changed

+70
-131
lines changed

scripts/sdlc/cfn/codepipeline-s3.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,10 @@ Resources:
155155
- export IDP_CFN_PREFIX=$(make cfn-prefix) || { echo "CFN prefix generation failed"; exit 1; }
156156
- make install -e IDP_CFN_PREFIX=$IDP_CFN_PREFIX
157157
- make smoketest -e IDP_CFN_PREFIX=$IDP_CFN_PREFIX
158-
- make uninstall -e IDP_CFN_PREFIX=$IDP_CFN_PREFIX
158+
post_build:
159+
commands:
160+
- echo "Running cleanup regardless of build result..."
161+
- make uninstall -e IDP_CFN_PREFIX=$IDP_CFN_PREFIX || echo "Cleanup failed but continuing"
159162
160163
DeploymentPipeline:
161164
Type: 'AWS::CodePipeline::Pipeline'

scripts/sdlc/idp-cli/src/idp_cli/service/install_service.py

Lines changed: 23 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -196,46 +196,6 @@ def cleanup_failed_stack(self, stack_name):
196196
logger.error(f"Failed to cleanup stack {stack_name}: {e}")
197197
return False
198198

199-
def get_service_role_arn(self):
200-
"""
201-
Check if CloudFormation service role stack exists and return its ARN.
202-
203-
Returns:
204-
str: The ARN of the existing service role, or None if not found
205-
"""
206-
service_role_stack_name = f"{self.cfn_prefix}-cloudformation-service-role"
207-
208-
try:
209-
describe_cmd = [
210-
'aws', 'cloudformation', 'describe-stacks',
211-
'--region', self.region,
212-
'--stack-name', service_role_stack_name,
213-
'--query', 'Stacks[0].Outputs[?OutputKey==`ServiceRoleArn`].OutputValue',
214-
'--output', 'text'
215-
]
216-
217-
process = subprocess.run(
218-
describe_cmd,
219-
check=True,
220-
text=True,
221-
stdout=subprocess.PIPE,
222-
stderr=subprocess.PIPE
223-
)
224-
225-
service_role_arn = process.stdout.strip()
226-
if service_role_arn and service_role_arn != "None":
227-
logger.info(f"Found existing service role: {service_role_arn}")
228-
return service_role_arn
229-
else:
230-
return None
231-
232-
except subprocess.CalledProcessError:
233-
logger.debug(f"Service role stack {service_role_stack_name} not found")
234-
return None
235-
except Exception as e:
236-
logger.error(f"Error checking for existing service role: {e}")
237-
return None
238-
239199
def deploy_service_role(self):
240200
"""
241201
Deploy the CloudFormation service role stack.
@@ -247,12 +207,6 @@ def deploy_service_role(self):
247207
service_role_template = 'iam-roles/cloudformation-management/IDP-Cloudformation-Service-Role.yaml'
248208

249209
try:
250-
# Check if the service role is managed by a different stack
251-
existing_stack_name = self._find_managing_stack()
252-
if existing_stack_name and existing_stack_name != service_role_stack_name:
253-
logger.info(f"Service role managed by different stack: {existing_stack_name}. Using existing stack for deployment.")
254-
service_role_stack_name = existing_stack_name
255-
256210
# Verify template file exists
257211
template_path = os.path.join(self.abs_cwd, service_role_template)
258212
if not os.path.exists(template_path):
@@ -284,7 +238,7 @@ def deploy_service_role(self):
284238
if process.stderr:
285239
logger.debug(f"Service role deploy stderr: {process.stderr}")
286240

287-
# Get the service role ARN - use the actual deployed stack name
241+
# Get the service role ARN from the deployed stack
288242
service_role_arn = self._get_service_role_arn_from_stack(service_role_stack_name)
289243
if service_role_arn:
290244
logger.info(f"Successfully deployed service role: {service_role_arn}")
@@ -309,50 +263,6 @@ def deploy_service_role(self):
309263
logger.error(f"Unexpected error during service role deployment: {e}")
310264
return None
311265

312-
def _find_managing_stack(self):
313-
"""
314-
Find which CloudFormation stack manages the IDPAcceleratorCloudFormationServiceRole.
315-
316-
Returns:
317-
str: Stack name that manages the service role, or None if not found
318-
"""
319-
try:
320-
# List all stacks that might contain the service role
321-
list_stacks_cmd = [
322-
'aws', 'cloudformation', 'list-stacks',
323-
'--region', self.region,
324-
'--stack-status-filter', 'CREATE_COMPLETE', 'UPDATE_COMPLETE',
325-
'--query', 'StackSummaries[?contains(StackName, `cloudformation-service-role`)].StackName',
326-
'--output', 'text'
327-
]
328-
329-
process = subprocess.run(
330-
list_stacks_cmd,
331-
check=True,
332-
text=True,
333-
stdout=subprocess.PIPE,
334-
stderr=subprocess.PIPE
335-
)
336-
337-
stack_names = process.stdout.strip().split() if process.stdout.strip() else []
338-
339-
# Check each stack to see if it has the ServiceRoleArn output
340-
for stack_name in stack_names:
341-
try:
342-
service_role_arn = self._get_service_role_arn_from_stack(stack_name)
343-
if service_role_arn:
344-
logger.debug(f"Found service role managed by stack: {stack_name}")
345-
return stack_name
346-
347-
except Exception:
348-
continue
349-
350-
return None
351-
352-
except Exception as e:
353-
logger.error(f"Error finding managing stack: {e}")
354-
return None
355-
356266
def _get_service_role_arn_from_stack(self, stack_name):
357267
"""
358268
Get service role ARN from a specific stack.
@@ -390,52 +300,36 @@ def _get_service_role_arn_from_stack(self, stack_name):
390300
return None
391301

392302
def create_permission_boundary_policy(self):
393-
"""Create an 'allow everything' permission boundary policy if it doesn't exist"""
303+
"""Create an 'allow everything' permission boundary policy"""
394304

395305
policy_name = "IDPPermissionBoundary"
396306
iam = boto3.client('iam')
397307

398308
try:
399-
# First, check if the policy already exists
400-
account_id = boto3.client('sts').get_caller_identity()['Account']
401-
policy_arn = f"arn:aws:iam::{account_id}:policy/{policy_name}"
309+
policy_document = {
310+
"Version": "2012-10-17",
311+
"Statement": [
312+
{
313+
"Effect": "Allow",
314+
"Action": "*",
315+
"Resource": "*"
316+
}
317+
]
318+
}
319+
320+
response = iam.create_policy(
321+
PolicyName=policy_name,
322+
PolicyDocument=json.dumps(policy_document),
323+
Description="Permission boundary for IDP deployment - allows all actions"
324+
)
402325

403-
# Try to get the existing policy
404-
iam.get_policy(PolicyArn=policy_arn)
405-
logger.info(f"Permission boundary policy already exists: {policy_arn}")
326+
policy_arn = response['Policy']['Arn']
327+
logger.info(f"Created permission boundary policy: {policy_arn}")
406328
return policy_arn
407329

408-
except ClientError as e:
409-
if e.response['Error']['Code'] == 'NoSuchEntity':
410-
# Policy doesn't exist, create it
411-
policy_document = {
412-
"Version": "2012-10-17",
413-
"Statement": [
414-
{
415-
"Effect": "Allow",
416-
"Action": "*",
417-
"Resource": "*"
418-
}
419-
]
420-
}
421-
422-
try:
423-
response = iam.create_policy(
424-
PolicyName=policy_name,
425-
PolicyDocument=json.dumps(policy_document),
426-
Description="Permission boundary for IDP deployment - allows all actions"
427-
)
428-
429-
policy_arn = response['Policy']['Arn']
430-
logger.info(f"Created permission boundary policy: {policy_arn}")
431-
return policy_arn
432-
433-
except ClientError as create_error:
434-
logger.error(f"Error creating permission boundary policy: {create_error}")
435-
return None
436-
else:
437-
logger.error(f"Error checking for existing permission boundary policy: {e}")
438-
return None
330+
except ClientError as create_error:
331+
logger.error(f"Error creating permission boundary policy: {create_error}")
332+
return None
439333

440334
def validate_permission_boundary(self, stack_name, boundary_arn):
441335
"""Validate that all IAM roles in the stack and nested stacks have the permission boundary"""

scripts/sdlc/idp-cli/src/idp_cli/service/uninstall_service.py

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
# SPDX-License-Identifier: MIT-0
33

44
import os
5+
import boto3
56
from typing import Any, Dict, Optional
7+
from botocore.exceptions import ClientError
68
from idp_cli.util.cfn_util import CfnUtil
79
from idp_cli.util.s3_util import S3Util
810
from loguru import logger
@@ -54,8 +56,48 @@ def delete_stack(self, wait=True):
5456
response = CfnUtil.delete_stack(stack_name=self.stack_name, wait=wait)
5557
logger.debug(response)
5658

59+
def delete_service_role_stack(self):
60+
"""Delete the CloudFormation service role stack if it exists"""
61+
service_role_stack_name = f"{self.cfn_prefix}-cloudformation-service-role"
62+
63+
try:
64+
logger.info(f"Attempting to delete service role stack: {service_role_stack_name}")
65+
response = CfnUtil.delete_stack(stack_name=service_role_stack_name, wait=True)
66+
logger.info(f"Successfully deleted service role stack: {service_role_stack_name}")
67+
logger.debug(response)
68+
except Exception as e:
69+
if "does not exist" in str(e):
70+
logger.debug(f"Service role stack {service_role_stack_name} does not exist, skipping")
71+
else:
72+
logger.error(f"Failed to delete service role stack {service_role_stack_name}: {e}")
73+
74+
def delete_permission_boundary_policy(self):
75+
"""Delete the permission boundary policy if it exists"""
76+
policy_name = "IDPPermissionBoundary"
77+
78+
try:
79+
iam = boto3.client('iam')
80+
account_id = boto3.client('sts').get_caller_identity()['Account']
81+
policy_arn = f"arn:aws:iam::{account_id}:policy/{policy_name}"
82+
83+
logger.info(f"Attempting to delete permission boundary policy: {policy_arn}")
84+
iam.delete_policy(PolicyArn=policy_arn)
85+
logger.info(f"Successfully deleted permission boundary policy: {policy_arn}")
86+
87+
except ClientError as e:
88+
if e.response['Error']['Code'] == 'NoSuchEntity':
89+
logger.debug(f"Permission boundary policy {policy_name} does not exist, skipping")
90+
elif e.response['Error']['Code'] == 'DeleteConflict':
91+
logger.warning(f"Permission boundary policy {policy_name} is still attached to resources, skipping deletion")
92+
else:
93+
logger.error(f"Failed to delete permission boundary policy {policy_name}: {e}")
94+
except Exception as e:
95+
logger.error(f"Unexpected error deleting permission boundary policy {policy_name}: {e}")
96+
5797
def uninstall(self):
5898
self.get_outputs()
5999
self.delete_stack(wait=True)
60100
self.get_buckets()
61-
self.delete_buckets()
101+
self.delete_buckets()
102+
self.delete_service_role_stack()
103+
self.delete_permission_boundary_policy()

0 commit comments

Comments
 (0)