AWSTemplateFormatVersion: "2010-09-09" Description: "CloudSweeper cross-account IAM role for cloud resource scanning and tagging. Grants read-only discovery and tagging permissions." Parameters: VendorAccountId: Type: String Description: "CloudSweeper's AWS account ID (QLoop Technologies)" Default: "811740411929" AllowedPattern: "^[0-9]{12}$" ConstraintDescription: "Must be a valid 12-digit AWS account ID" ExternalId: Type: String Description: "External ID provided by CloudSweeper for secure cross-account access (computed from your email)" MinLength: 35 MaxLength: 35 AllowedPattern: "^cs-[a-f0-9]{32}$" ConstraintDescription: "Must be a valid CloudSweeper External ID (format: cs-{32_hex_characters})" NoEcho: true CustomerEmail: Type: String Description: "Your CloudSweeper account email (used for role naming)" AllowedPattern: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$" ConstraintDescription: "Must be a valid email address" Resources: CloudSweeperRole: Type: AWS::IAM::Role Properties: RoleName: !Sub "CloudSweeper-${AWS::StackName}" Path: / Description: !Sub "CloudSweeper role for ${CustomerEmail} - automated cloud resource scanning and optimization" AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Sid: AllowCloudSweeperAssumeRole Effect: Allow Principal: AWS: !Sub "arn:aws:iam::${VendorAccountId}:root" Action: sts:AssumeRole Condition: StringEquals: sts:ExternalId: !Ref ExternalId Tags: - Key: ManagedBy Value: CloudSweeper - Key: CustomerEmail Value: !Ref CustomerEmail - Key: Purpose Value: "Cross-account resource scanning and tagging" Policies: - PolicyName: CloudSweeperAccessPolicy PolicyDocument: Version: "2012-10-17" Statement: # 1. Read-only discovery permissions - Sid: ReadOnlyResourceDiscovery Effect: Allow Action: # EC2 Resources - ec2:Describe* # ELB Resources - elasticloadbalancing:Describe* # Lambda Functions - lambda:ListFunctions - lambda:GetFunctionConfiguration - lambda:GetProvisionedConcurrencyConfig # DynamoDB Tables - dynamodb:DescribeTable - dynamodb:ListTables # S3 Buckets - s3:ListAllMyBuckets - s3:GetBucketLocation - s3:GetBucketTagging - s3:GetBucketVersioning - s3:GetEncryptionConfiguration - s3:GetLifecycleConfiguration # ElastiCache - elasticache:DescribeCacheClusters - elasticache:DescribeCacheParameterGroups - elasticache:DescribeCacheSecurityGroups - elasticache:DescribeCacheSubnetGroups - elasticache:DescribeReplicationGroups - elasticache:ListTagsForResource # EKS Clusters - eks:ListClusters - eks:DescribeCluster - eks:ListNodegroups # ECR Repositories - ecr:DescribeRepositories - ecr:ListImages - ecr:DescribeImages - ecr:ListTagsForResource - ecr:GetLifecyclePolicy # ECS Clusters - ecs:ListClusters - ecs:DescribeClusters - ecs:ListServices - ecs:DescribeServices - ecs:ListTasks # RDS Databases - rds:DescribeDBInstances - rds:DescribeDBClusters - rds:DescribeDBSnapshots - rds:ListTagsForResource # SQS Queues - sqs:ListQueues - sqs:GetQueueAttributes - sqs:ListQueueTags # API Gateway (HTTP APIs / v2) - apigatewayv2:GetApis - apigatewayv2:GetStages - apigatewayv2:GetRoutes - apigatewayv2:GetIntegrations Resource: "*" # 2. CloudWatch metrics for idle resource detection - Sid: ReadCloudWatchMetrics Effect: Allow Action: - cloudwatch:GetMetricStatistics - cloudwatch:ListMetrics Resource: "*" # 3. Tagging permissions for audit trails and grace periods - Sid: TagResourcesForTracking Effect: Allow Action: # EC2 Tagging - ec2:CreateTags - ec2:DeleteTags # ELB Tagging - elasticloadbalancing:AddTags - elasticloadbalancing:RemoveTags # Lambda Tagging - lambda:TagResource - lambda:UntagResource # DynamoDB Tagging - dynamodb:TagResource - dynamodb:UntagResource # S3 Tagging - s3:PutBucketTagging - s3:DeleteBucketTagging # ElastiCache Tagging - elasticache:AddTagsToResource - elasticache:RemoveTagsFromResource # EKS Tagging - eks:TagResource - eks:UntagResource # ECR Tagging - ecr:TagResource - ecr:UntagResource # ECS Tagging - ecs:TagResource - ecs:UntagResource # RDS Tagging - rds:AddTagsToResource - rds:RemoveTagsFromResource # SQS Tagging - sqs:TagQueue - sqs:UntagQueue # API Gateway Tagging - apigatewayv2:TagResource - apigatewayv2:UntagResource Resource: "*" Outputs: RoleArn: Description: "IAM Role ARN - Copy this to CloudSweeper settings" Value: !GetAtt CloudSweeperRole.Arn Export: Name: !Sub "${AWS::StackName}-RoleArn" ExternalIdUsed: Description: "External ID used for this role (for reference only)" Value: !Ref ExternalId RoleName: Description: "IAM Role Name" Value: !Ref CloudSweeperRole SetupInstructions: Description: "Next steps" Value: "Copy the RoleArn above and paste it into your CloudSweeper connector settings to complete setup" AccountId: Description: "Your AWS Account ID" Value: !Ref AWS::AccountId