Python Script to find untagged resources in AWS

Here is the script to find a un tagged resources in AWS:

import boto3
import datetime
from botocore.exceptions import ClientError
import json

class AWSTagRecommender:
    def __init__(self, region='us-east-1'):
        self.region = region
        self.ec2 = boto3.client('ec2', region_name=region)
        self.rds = boto3.client('rds', region_name=region)
        self.s3 = boto3.client('s3')
        self.lambda_client = boto3.client('lambda', region_name=region)

    def recommended_tags(self, resource_type, resource_details=None):
        """Generate recommended tags based on resource type and details"""
        current_date = datetime.datetime.now().strftime('%Y-%m-%d')
        
        # Base recommended tags
        base_tags = {
            'Environment': ['prod', 'dev', 'stage', 'test'],
            'Owner': 'REQUIRED',
            'CostCenter': 'REQUIRED',
            'Project': 'REQUIRED',
            'CreatedDate': current_date,
            'Backup': ['true', 'false'],
            'SecurityLevel': ['high', 'medium', 'low']
        }
        
        # Resource-specific tag recommendations
        specific_tags = {
            'ec2': {
                'ApplicationRole': ['web', 'app', 'db', 'cache'],
                'PatchGroup': ['group1', 'group2', 'critical'],
                'AutoStop': ['true', 'false']
            },
            'rds': {
                'DatabaseType': ['mysql', 'postgres', 'oracle', 'sqlserver'],
                'BackupRetention': ['7days', '30days', '90days'],
                'DataClassification': ['public', 'private', 'confidential']
            },
            's3': {
                'DataType': ['logs', 'backups', 'user-content', 'static-assets'],
                'AccessPattern': ['frequent', 'infrequent', 'archive'],
                'LifecyclePolicy': ['required', 'not-required']
            },
            'lambda': {
                'FunctionType': ['api', 'scheduled', 'event-driven'],
                'Runtime': resource_details.get('Runtime', 'unknown') if resource_details else 'REQUIRED',
                'APIEndpoint': ['true', 'false']
            }
        }
        
        return {**base_tags, **specific_tags.get(resource_type, {})}

    def find_untagged_ec2(self):
        """Find untagged EC2 resources"""
        try:
            instances = self.ec2.describe_instances()
            untagged = []
            
            for reservation in instances['Reservations']:
                for instance in reservation['Instances']:
                    if not instance.get('Tags'):
                        untagged.append({
                            'ResourceId': instance['InstanceId'],
                            'Type': 'ec2',
                            'Details': {
                                'InstanceType': instance['InstanceType'],
                                'State': instance['State']['Name'],
                                'LaunchTime': instance['LaunchTime'].strftime('%Y-%m-%d')
                            }
                        })
            return untagged
        except ClientError as e:
            print(f"Error finding untagged EC2 instances: {e}")
            return []

    def find_untagged_rds(self):
        """Find untagged RDS resources"""
        try:
            instances = self.rds.describe_db_instances()
            untagged = []
            
            for instance in instances['DBInstances']:
                tags = self.rds.list_tags_for_resource(
                    ResourceName=instance['DBInstanceArn']
                )['TagList']
                
                if not tags:
                    untagged.append({
                        'ResourceId': instance['DBInstanceIdentifier'],
                        'Type': 'rds',
                        'Details': {
                            'Engine': instance['Engine'],
                            'Class': instance['DBInstanceClass'],
                            'Storage': instance['AllocatedStorage']
                        }
                    })
            return untagged
        except ClientError as e:
            print(f"Error finding untagged RDS instances: {e}")
            return []

    def find_untagged_s3(self):
        """Find untagged S3 buckets"""
        try:
            buckets = self.s3.list_buckets()['Buckets']
            untagged = []
            
            for bucket in buckets:
                try:
                    tags = self.s3.get_bucket_tagging(Bucket=bucket['Name'])
                except ClientError as e:
                    if e.response['Error']['Code'] == 'NoSuchTagSet':
                        untagged.append({
                            'ResourceId': bucket['Name'],
                            'Type': 's3',
                            'Details': {
                                'CreationDate': bucket['CreationDate'].strftime('%Y-%m-%d')
                            }
                        })
            return untagged
        except ClientError as e:
            print(f"Error finding untagged S3 buckets: {e}")
            return []

    def find_untagged_lambda(self):
        """Find untagged Lambda functions"""
        try:
            functions = self.lambda_client.list_functions()['Functions']
            untagged = []
            
            for function in functions:
                tags = self.lambda_client.list_tags(
                    Resource=function['FunctionArn']
                ).get('Tags', {})
                
                if not tags:
                    untagged.append({
                        'ResourceId': function['FunctionName'],
                        'Type': 'lambda',
                        'Details': {
                            'Runtime': function['Runtime'],
                            'LastModified': function['LastModified']
                        }
                    })
            return untagged
        except ClientError as e:
            print(f"Error finding untagged Lambda functions: {e}")
            return []

    def generate_report(self):
        """Generate a comprehensive report of untagged resources and recommendations"""
        all_untagged = []
        all_untagged.extend(self.find_untagged_ec2())
        all_untagged.extend(self.find_untagged_rds())
        all_untagged.extend(self.find_untagged_s3())
        all_untagged.extend(self.find_untagged_lambda())

        report = {
            'generated_date': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
            'region': self.region,
            'untagged_resources': []
        }

        for resource in all_untagged:
            report['untagged_resources'].append({
                'resource_id': resource['ResourceId'],
                'resource_type': resource['Type'],
                'details': resource['Details'],
                'recommended_tags': self.recommended_tags(resource['Type'], resource['Details'])
            })

        return report

def main():
    # Initialize the tag recommender
    recommender = AWSTagRecommender()
    
    # Generate the report
    print("Analyzing AWS resources for missing tags...")
    report = recommender.generate_report()
    
    # Save the report to a file
    filename = f"tag_recommendations_{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
    with open(filename, 'w') as f:
        json.dump(report, f, indent=2, default=str)
    
    # Print summary
    print(f"\nReport generated: {filename}")
    print(f"Found {len(report['untagged_resources'])} untagged resources")
    
    # Print resource type breakdown
    resource_types = {}
    for resource in report['untagged_resources']:
        resource_types[resource['resource_type']] = resource_types.get(resource['resource_type'], 0) + 1
    
    print("\nBreakdown by resource type:")
    for rtype, count in resource_types.items():
        print(f"{rtype}: {count} untagged resources")

if __name__ == "__main__":
    main()

Hope you enjoyed the post.

Cheers

Ramasankar Molleti

LinkedIn

Published by Ramasankar

As a Principal Cloud Architect with over 18 years of experience, I am dedicated to revolutionizing IT landscapes through cutting-edge cloud solutions. My expertise spans Cloud Architecture, Security Architecture, Solution Design, Cloud Migration, Database Transformation, Development, and Big Data Analytics.Currently, I spearhead cloud initiatives with a focus on Infrastructure, Containerization, Security, Big Data, Machine Learning, and Artificial Intelligence. I collaborate closely with development teams to architect, build, and manage robust cloud ecosystems that drive business growth and technological advancement.Core Competencies: • Cloud Platforms: AWS, Google Cloud Platform, Microsoft Azure • Technologies: Kubernetes, Serverless Computing, Microservices • Databases: MS SQL Server, PostgreSQL, Oracle, MongoDB, Amazon Redshift, DynamoDB, Aurora • Industries: Finance, Retail, Manufacturing. Throughout my career, I’ve had the privilege of working with industry leaders such as OCC, Gate Gourmet, Walgreens, and Johnson Controls, gaining invaluable insights across diverse sectors.As a lifelong learner and knowledge sharer, I take pride in being the first in my organization to complete all major AWS certifications. I am passionate about mentoring and guiding fellow professionals in their cloud journey, fostering a culture of continuous learning and innovation.Let’s connect and explore how we can leverage cloud technologies to transform your business: • LinkedIn: https://www.linkedin.com/in/ramasankar-molleti-23b13218/ • Book a mentorship session: [1:1] Together, let’s architect the future of cloud computing and drive technological excellence. Disclaimer The views expressed on this website/blog are mine alone and do not reflect the views of my company. All postings on this blog are provided “AS IS” with no warranties, and confers no rights. The owner of https://ramasankarmolleti.com will not be liable for any errors or omissions in this information nor for the availability of this information. The owner will not be liable for any losses, injuries, or damages from the display or use of this information.

Leave a comment