Skip to content
Draft
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
64 changes: 64 additions & 0 deletions IaC/cdk/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# CDK Projects

AWS CDK (Cloud Development Kit) infrastructure as code implementations.

## Projects

### aws-resources-cleanup
Comprehensive AWS resource cleanup Lambda with CDK deployment.

**Purpose**: Automated cleanup of EC2 instances, EKS clusters, and OpenShift infrastructure based on TTL policies and billing tags.

**Features**:
- TTL-based expiration (8h, 24h policies)
- Billing tag validation (category + Unix timestamps)
- EKS CloudFormation deletion
- OpenShift comprehensive cleanup (VPC, ELB, Route53, S3, NAT, security groups)
- DRY_RUN mode (default)
- SNS notifications
- Hourly EventBridge schedule

**Quick Start**:
```bash
cd aws-resources-cleanup
just install # Install dependencies
just deploy # Deploy in DRY_RUN mode
just logs # Tail CloudWatch logs
```

📖 **Full documentation**: [aws-resources-cleanup/README.md](aws-resources-cleanup/README.md)

## Requirements

- AWS CLI configured with appropriate profile
- `uv` package manager: `brew install uv`
- `just` task runner: `brew install just`

## Common Commands

All projects use Justfile for consistent automation:

| Command | Description |
|---------|-------------|
| `just install` | Install all dependencies |
| `just synth` | Generate CloudFormation template |
| `just diff` | Preview infrastructure changes |
| `just deploy` | Deploy stack |
| `just destroy` | Remove stack |
| `just logs` | Tail CloudWatch logs (if applicable) |

## Adding New CDK Projects

When creating a new CDK project in this directory:

1. Create project directory: `mkdir project-name`
2. Initialize CDK: `cdk init app --language python`
3. Add Justfile for automation
4. Add project-specific README.md
5. Update this README with project description

## Resources

- [AWS CDK Documentation](https://docs.aws.amazon.com/cdk/)
- [CDK Python API Reference](https://docs.aws.amazon.com/cdk/api/v2/python/)
- [Justfile Documentation](https://github.com/casey/just)
57 changes: 57 additions & 0 deletions IaC/cdk/aws-resources-cleanup/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# 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/

# Logs
*.log
95 changes: 95 additions & 0 deletions IaC/cdk/aws-resources-cleanup/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# AWS Resources Cleanup

Automated Lambda for EC2, EBS, EKS, and OpenShift cleanup across AWS regions.

**Runtime**: Python 3.13 ARM64, 1024MB, 600s timeout
**Default**: DRY_RUN mode (logs only)
**Concurrency**: 1 (prevents race conditions)

## Features

- **EC2**: TTL expiration, stop policy, long-stopped instances, untagged cleanup
- **EBS**: Unattached volume deletion
- **EKS**: CloudFormation stack deletion (skip pattern: `pe-.*`)
- **OpenShift**: Full cluster cleanup (VPC, ELB, Route53, S3)

**Protection**: Persistent tags (`jenkins-*`, `pmm-dev`), valid billing tags, `PerconaKeep`, "do not remove" in names

## Quick Start

```bash
brew install uv just
cd IaC/cdk/aws-resources-cleanup
just install
just bootstrap # First time only
just deploy # DRY_RUN mode
just deploy-live # LIVE mode (destructive!)
```

## Commands

```bash
just deploy # Deploy (DRY_RUN)
just logs # Tail logs
just invoke-aws # Manual trigger
just params # Show config
just test # Run tests (176, 87% coverage)
```

Run `just` for all commands.

## Configuration

Key parameters (CloudFormation):

| Parameter | Default | Description |
|-----------|---------|-------------|
| `DryRunMode` | `true` | Safe mode |
| `ScheduleRateMinutes` | `15` | Run frequency |
| `TargetRegions` | `all` | Regions to scan |
| `LogLevel` | `INFO` | Log verbosity |
| `UntaggedThresholdMinutes` | `30` | Grace period |
| `VolumeCleanupEnabled` | `true` | Enable volume cleanup |
| `EKSCleanupEnabled` | `true` | Enable EKS cleanup |
| `OpenShiftCleanupEnabled` | `true` | Enable OpenShift cleanup |

View all: `just params`

## Cleanup Policies

Priority order:

1. **TTL** - `creation-time` + `delete-cluster-after-hours` → TERMINATE
2. **Stop** - `stop-after-days` → STOP
3. **Long Stopped** - >30 days → TERMINATE
4. **Untagged** - Missing `iit-billing-tag` → TERMINATE

## Logging

```
Instance i-0d09... protected: Valid billing tag 'ps-package-testing'
[DRY-RUN] Would TERMINATE instance i-085e... in us-east-2: Missing billing tag
Instance scan for us-west-2: 11 scanned, 1 actions, 10 protected
Cleanup complete: 31 actions across 17 regions (15.4s)
```

## Troubleshooting

```bash
just logs-recent # Check logs
just params # Verify config
just invoke-aws # Test manually
```

**Issues:**
- No actions: Set `DryRunMode=false`
- Volume cleanup fails: Check `VolumeCleanupEnabled=true`, volumes `available`
- OpenShift errors: Auto-retries 3 times

## Architecture

```
EventBridge → Lambda → EC2/Volumes/EKS/OpenShift → SNS
```

Justfile retrieves function name from CDK outputs for alignment.
25 changes: 25 additions & 0 deletions IaC/cdk/aws-resources-cleanup/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/env python3
"""CDK app for AWS Resources Cleanup Lambda."""

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

app = cdk.App()

ResourceCleanupStack(
app,
"AWSResourcesCleanupStack",
description="Comprehensive AWS resource cleanup: EC2, EKS, OpenShift infrastructure",
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": "resource-cleanup"
}
)

app.synth()
114 changes: 114 additions & 0 deletions IaC/cdk/aws-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