Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions IaC/cdk/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# CDK Projects

AWS CDK infrastructure as code for automated resource management.

## openshift-resources-cleanup

Automated Lambda that cleans up expired OpenShift/ROSA clusters. Scans all AWS regions every 15 minutes, validates TTL tags, and deletes cluster infrastructure (VPC, ELB, Route53, S3, EC2).

```bash
cd openshift-resources-cleanup
just install && just bootstrap
just deploy # Deploy LIVE mode
just logs # View logs
```

See [openshift-resources-cleanup/README.md](openshift-resources-cleanup/README.md) for full documentation.

## Requirements

- AWS CLI configured
- `brew install uv just`
84 changes: 84 additions & 0 deletions IaC/cdk/openshift-resources-cleanup/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# CDK
cdk.out/
.cdk.staging/
cdk.context.json

# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# Virtual environments
venv/
ENV/
env/
.venv

# Testing
.pytest_cache/
.coverage
htmlcov/
.tox/

# IDEs
.vscode/
.idea/
*.swp
*.swo
*~

# OS
.DS_Store
Thumbs.db

# Lambda artifacts
*.zip
/tmp/

# Lambda dependencies (installed at build time)
lambda/*.dist-info/
lambda/bin/
lambda/boto3/
lambda/boto3-*.dist-info/
lambda/botocore/
lambda/botocore-*.dist-info/
lambda/aws_lambda_powertools/
lambda/aws_lambda_powertools-*.dist-info/
lambda/aws_xray_sdk/
lambda/aws_xray_sdk-*.dist-info/
lambda/s3transfer/
lambda/s3transfer-*.dist-info/
lambda/jmespath/
lambda/jmespath-*.dist-info/
lambda/dateutil/
lambda/python_dateutil-*.dist-info/
lambda/urllib3/
lambda/urllib3-*.dist-info/
lambda/six.py
lambda/six-*.dist-info/
lambda/typing_extensions.py
lambda/typing_extensions-*.dist-info/
lambda/wrapt/
lambda/wrapt-*.dist-info/
lambda/.lock

# Logs
*.log
56 changes: 56 additions & 0 deletions IaC/cdk/openshift-resources-cleanup/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# OpenShift Cluster Cleanup

Automated Lambda that cleans up expired OpenShift/ROSA clusters. Runs every 15 minutes, scans for expired clusters, deletes all resources (VPC, ELB, Route53, S3, EC2).

## Configuration

| Setting | Default | How to Change |
|---------|---------|---------------|
| **Lambda Location** | `us-east-2` | `AWS_REGION=us-west-1 just deploy` |
| **Scan Regions** (comma-separated) | `all` | `just deploy us-east-2` or `just deploy us-east-1,eu-west-1,ap-south-1` |
| **AWS Profile** | `default` | `AWS_PROFILE=myprofile just deploy` |
| **Mode** | `LIVE` | `just deploy-dry` |

## Quick Start

```bash
brew install uv just && aws configure
cd IaC/cdk/openshift-resources-cleanup
just install && just bootstrap
just deploy # Scans all regions (default)
just deploy us-east-2 # Scans us-east-2 only
AWS_REGION=us-west-1 just deploy # Deploy Lambda to us-west-1
```

## Commands

```bash
just deploy [regions] # Deploy LIVE (default: all regions)
just deploy-dry [regions]# Deploy DRY_RUN (toggles LIVE off)
just logs # Tail CloudWatch logs
just params # Show configuration
just test # Run tests
```

Run `just` for all commands.

## How It Works

1. **Detect**: Scans EC2 for OpenShift/ROSA clusters (tags: `red-hat-clustertype: rosa` or name: `*-master-*`)
2. **Check TTL**: Reads `creation-time` + `delete-cluster-after-hours` tags, skips if not expired
3. **Delete**: Removes all resources in dependency order (instances → ELB → NAT → VPC → Route53 → S3)

## Logs & Troubleshooting

```bash
just logs # View real-time logs
just params # Check configuration
```

**Example output:**
```
Detected OpenShift ROSA cluster: jvp-rosa1-qmdkk
Cluster TTL not expired (5.45 hours remaining)
```

**Common issues:** Missing TTL tags (`creation-time`, `delete-cluster-after-hours`), `DryRunMode=true`, permissions
28 changes: 28 additions & 0 deletions IaC/cdk/openshift-resources-cleanup/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env python3
"""CDK app for OpenShift Cluster Cleanup Lambda."""

import os
import aws_cdk as cdk
from stacks.resource_cleanup_stack import ResourceCleanupStack

# Stack name (single source of truth)
STACK_NAME = "OpenShiftResourcesCleanupStack"

app = cdk.App()

ResourceCleanupStack(
app,
STACK_NAME,
description="OpenShift cluster infrastructure cleanup for AWS",
env=cdk.Environment(
account=os.getenv('CDK_DEFAULT_ACCOUNT'),
region=os.getenv('CDK_DEFAULT_REGION', 'us-east-2')
),
tags={
"Project": "PlatformEngineering",
"ManagedBy": "CDK",
"iit-billing-tag": "openshift-cleanup"
}
)

app.synth()
114 changes: 114 additions & 0 deletions IaC/cdk/openshift-resources-cleanup/cdk.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
{
"app": "python3 app.py",
"watch": {
"include": [
"**"
],
"exclude": [
"README.md",
"cdk*.json",
"requirements*.txt",
"source.bat",
"**/__pycache__",
"**/*.pyc",
".pytest_cache"
]
},
"context": {
"@aws-cdk/aws-lambda:recognizeLayerVersion": true,
"@aws-cdk/core:checkSecretUsage": true,
"@aws-cdk/core:target-partitions": [
"aws",
"aws-cn"
],
"@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
"@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
"@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true,
"@aws-cdk/aws-iam:minimizePolicies": true,
"@aws-cdk/core:validateSnapshotRemovalPolicy": true,
"@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true,
"@aws-cdk/aws-s3:createDefaultLoggingPolicy": true,
"@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true,
"@aws-cdk/aws-apigateway:disableCloudWatchRole": true,
"@aws-cdk/core:enablePartitionLiterals": true,
"@aws-cdk/aws-events:eventsTargetQueueSameAccount": true,
"@aws-cdk/aws-iam:standardizedServicePrincipals": true,
"@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true,
"@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true,
"@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true,
"@aws-cdk/aws-route53-patternslibrary:useCertificate": true,
"@aws-cdk/customresources:installLatestAwsSdkDefault": false,
"@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true,
"@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true,
"@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true,
"@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true,
"@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true,
"@aws-cdk/aws-redshift:columnId": true,
"@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true,
"@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true,
"@aws-cdk/aws-apigateway:requestValidatorUniqueId": true,
"@aws-cdk/aws-kms:aliasNameRef": true,
"@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true,
"@aws-cdk/core:includePrefixInUniqueNameGeneration": true,
"@aws-cdk/aws-efs:denyAnonymousAccess": true,
"@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true,
"@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true,
"@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true,
"@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true,
"@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true,
"@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true,
"@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true,
"@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": true,
"@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": true,
"@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": true,
"@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": true,
"@aws-cdk/aws-eks:nodegroupNameAttribute": true,
"@aws-cdk/aws-ec2:ebsDefaultGp3Volume": true,
"@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": true,
"@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": false,
"@aws-cdk/aws-s3:keepNotificationInImportedBucket": false,
"@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true,
"@aws-cdk/aws-appsync:appSyncGraphQLAPIScopeLambdaPermission": true,
"@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true,
"@aws-cdk/aws-dynamodb:resourcePolicyPerReplica": true,
"@aws-cdk/aws-dynamodb:retainTableReplica": true,
"@aws-cdk/aws-ec2-alpha:useResourceIdForVpcV2Migration": false,
"@aws-cdk/aws-ec2:bastionHostUseAmazonLinux2023ByDefault": true,
"@aws-cdk/aws-ec2:ec2SumTImeoutEnabled": true,
"@aws-cdk/aws-ec2:requirePrivateSubnetsForEgressOnlyInternetGateway": true,
"@aws-cdk/aws-ecs-patterns:secGroupsDisablesImplicitOpenListener": true,
"@aws-cdk/aws-ecs:disableEcsImdsBlocking": true,
"@aws-cdk/aws-ecs:enableImdsBlockingDeprecatedFeature": false,
"@aws-cdk/aws-ecs:reduceEc2FargateCloudWatchPermissions": true,
"@aws-cdk/aws-elasticloadbalancingV2:albDualstackWithoutPublicIpv4SecurityGroupRulesDefault": true,
"@aws-cdk/aws-events:requireEventBusPolicySid": true,
"@aws-cdk/aws-iam:oidcRejectUnauthorizedConnections": true,
"@aws-cdk/aws-kms:applyImportedAliasPermissionsToPrincipal": true,
"@aws-cdk/aws-lambda-nodejs:sdkV3ExcludeSmithyPackages": true,
"@aws-cdk/aws-lambda:createNewPoliciesWithAddToRolePolicy": false,
"@aws-cdk/aws-lambda:recognizeVersionProps": true,
"@aws-cdk/aws-lambda:useCdkManagedLogGroup": true,
"@aws-cdk/aws-rds:lowercaseDbIdentifier": true,
"@aws-cdk/aws-rds:setCorrectValueForDatabaseInstanceReadReplicaInstanceResourceId": true,
"@aws-cdk/aws-route53-patters:useCertificate": true,
"@aws-cdk/aws-route53-targets:userPoolDomainNameMethodWithoutCustomResource": true,
"@aws-cdk/aws-s3:publicAccessBlockedByDefault": true,
"@aws-cdk/aws-s3:setUniqueReplicationRoleName": true,
"@aws-cdk/aws-signer:signingProfileNamePassedToCfn": true,
"@aws-cdk/aws-stepfunctions-tasks:fixRunEcsTaskPolicy": true,
"@aws-cdk/aws-stepfunctions-tasks:useNewS3UriParametersForBedrockInvokeModelTask": true,
"@aws-cdk/aws-stepfunctions:useDistributedMapResultWriterV2": true,
"@aws-cdk/cognito:logUserPoolClientSecretValue": false,
"@aws-cdk/core:aspectPrioritiesMutating": true,
"@aws-cdk/core:aspectStabilization": true,
"@aws-cdk/core:cfnIncludeRejectComplexResourceUpdateCreatePolicyIntrinsics": true,
"@aws-cdk/core:enableAdditionalMetadataCollection": true,
"@aws-cdk/core:explicitStackTags": true,
"@aws-cdk/core:newStyleStackSynthesis": true,
"@aws-cdk/core:stackRelativeExports": true,
"@aws-cdk/pipelines:reduceAssetRoleTrustScope": true,
"@aws-cdk/pipelines:reduceCrossAccountActionRoleTrustScope": true,
"@aws-cdk/pipelines:reduceStageRoleTrustScope": true,
"@aws-cdk/s3-notifications:addS3TrustKeyPolicyForSnsSubscriptions": true
}
}
Loading