diff --git a/aws/modules/tag-conformance-pack/backend.tf b/aws/modules/tag-conformance-pack/backend.tf deleted file mode 100644 index 89118c9..0000000 --- a/aws/modules/tag-conformance-pack/backend.tf +++ /dev/null @@ -1,32 +0,0 @@ -module "backend_bucket" { - source = "terraform-aws-modules/s3-bucket/aws" - version = "3.15.1" - - create_bucket = var.create_tf_backend - - bucket = "tag-conformance-pack-terraform-${replace(lower(var.profile), "_", "-")}" - acl = "private" - control_object_ownership = true - object_ownership = "ObjectWriter" - - versioning = { - enabled = true - } -} - -module "backend_dynamodb_table" { - source = "terraform-aws-modules/dynamodb-table/aws" - - create_table = var.create_tf_backend_dynamo_table - - name = "tag-conformance-pack-terraform-${replace(lower(var.profile), "_", "-")}" - server_side_encryption_enabled = true - hash_key = "LockID" - - attributes = [ - { - name = "LockID" - type = "S" - } - ] -} \ No newline at end of file diff --git a/aws/modules/tag-conformance-pack/examples/multiple-accounts-deploy/accounts/demo_account/dev/variables.tfvars b/aws/modules/tag-conformance-pack/examples/multiple-accounts-deploy/accounts/demo_account/dev/variables.tfvars index 3550778..088efdd 100644 --- a/aws/modules/tag-conformance-pack/examples/multiple-accounts-deploy/accounts/demo_account/dev/variables.tfvars +++ b/aws/modules/tag-conformance-pack/examples/multiple-accounts-deploy/accounts/demo_account/dev/variables.tfvars @@ -1,8 +1,8 @@ -profile = "DEMO" #account name, do not change -bucket_name = "tag-conformance-pack-files-demo-dev" -create_tf_backend = false +profile = "" #account name, do not change +bucket_name = "tag-conformance-pack-files--" +create_tf_backend = true region = "us-east-1" -application_domain_path = "./accounts/demo_account/application-domain.json" +application_domain_path = "./accounts///application-domain.json" script_path = "./src" custom_lambda_script = "custom-required-tags-evaluation.py" create_event_bridge_tagger = true @@ -11,10 +11,10 @@ ssm_script = "ssmDocumentAutomation.py" tags = { application = "config" domain = "infrastructure" - board = "demo" + board = "board" company = "rd" shared = "no" - env = "dev" + env = "env" tag_created = "iac" } RemediationExecutionControls = { @@ -118,4 +118,4 @@ custom_lambda_resource_types = [ "AWS::Cloud9::EnvironmentEC2", "AWS::CloudTrail::Trail" ] - + diff --git a/aws/modules/tag-conformance-pack/examples/multiple-accounts-deploy/accounts/demo_account/qa/variables.tfvars b/aws/modules/tag-conformance-pack/examples/multiple-accounts-deploy/accounts/demo_account/qa/variables.tfvars index 6de0d10..088efdd 100644 --- a/aws/modules/tag-conformance-pack/examples/multiple-accounts-deploy/accounts/demo_account/qa/variables.tfvars +++ b/aws/modules/tag-conformance-pack/examples/multiple-accounts-deploy/accounts/demo_account/qa/variables.tfvars @@ -1,8 +1,8 @@ -profile = "DEMO" #account name, do not change -bucket_name = "tag-conformance-pack-files-demo-qa" -create_tf_backend = false +profile = "" #account name, do not change +bucket_name = "tag-conformance-pack-files--" +create_tf_backend = true region = "us-east-1" -application_domain_path = "./accounts/demo_account/application-domain.json" +application_domain_path = "./accounts///application-domain.json" script_path = "./src" custom_lambda_script = "custom-required-tags-evaluation.py" create_event_bridge_tagger = true @@ -11,10 +11,10 @@ ssm_script = "ssmDocumentAutomation.py" tags = { application = "config" domain = "infrastructure" - board = "demo" + board = "board" company = "rd" shared = "no" - env = "qa" + env = "env" tag_created = "iac" } RemediationExecutionControls = { @@ -118,4 +118,4 @@ custom_lambda_resource_types = [ "AWS::Cloud9::EnvironmentEC2", "AWS::CloudTrail::Trail" ] - + diff --git a/aws/modules/tag-conformance-pack/examples/multiple-accounts-deploy/accounts/demo_account_2/qa/variables.tfvars b/aws/modules/tag-conformance-pack/examples/multiple-accounts-deploy/accounts/demo_account_2/qa/variables.tfvars index bdd5918..088efdd 100644 --- a/aws/modules/tag-conformance-pack/examples/multiple-accounts-deploy/accounts/demo_account_2/qa/variables.tfvars +++ b/aws/modules/tag-conformance-pack/examples/multiple-accounts-deploy/accounts/demo_account_2/qa/variables.tfvars @@ -1,8 +1,8 @@ -profile = "DEMO2" #account name, do not change -bucket_name = "tag-conformance-pack-files-demo2-qa" +profile = "" #account name, do not change +bucket_name = "tag-conformance-pack-files--" create_tf_backend = true region = "us-east-1" -application_domain_path = "./accounts/demo_account_2/application-domain.json" +application_domain_path = "./accounts///application-domain.json" script_path = "./src" custom_lambda_script = "custom-required-tags-evaluation.py" create_event_bridge_tagger = true @@ -11,10 +11,10 @@ ssm_script = "ssmDocumentAutomation.py" tags = { application = "config" domain = "infrastructure" - board = "demo" + board = "board" company = "rd" shared = "no" - env = "qa" + env = "env" tag_created = "iac" } RemediationExecutionControls = { @@ -24,7 +24,7 @@ RemediationExecutionControls = { ErrorPercentage = 40 } } - Automatic = false + Automatic = true MaximumAutomaticAttempts = 1 RetryAttemptSeconds = 1200 } @@ -32,18 +32,90 @@ RemediationExecutionControls = { # supported resources for required-tags managed config rule # https://docs.aws.amazon.com/config/latest/developerguide/required-tags.html resource_types = [ + "AWS::ACM::Certificate", + "AWS::AutoScaling::AutoScalingGroup", + "AWS::CodeBuild::Project", + "AWS::DynamoDB::Table", + "AWS::EC2::CustomerGateway", "AWS::EC2::Instance", + "AWS::EC2::InternetGateway", + "AWS::EC2::NetworkAcl", + "AWS::EC2::NetworkInterface", + "AWS::EC2::RouteTable", + "AWS::EC2::SecurityGroup", + "AWS::EC2::Subnet", + "AWS::EC2::Volume", + "AWS::EC2::VPC", + "AWS::EC2::VPNConnection", + "AWS::EC2::VPNGateway", + "AWS::ElasticLoadBalancing::LoadBalancer", + "AWS::ElasticLoadBalancingV2::LoadBalancer", + "AWS::RDS::DBInstance", + "AWS::RDS::DBSecurityGroup", + "AWS::RDS::DBSnapshot", + "AWS::RDS::DBSubnetGroup", + "AWS::RDS::EventSubscription", + "AWS::Redshift::Cluster", + "AWS::Redshift::ClusterParameterGroup", + "AWS::Redshift::ClusterSecurityGroup", + "AWS::Redshift::ClusterSnapshot", + "AWS::Redshift::ClusterSubnetGroup", + "AWS::S3::Bucket" ] # all supporter resources # https://docs.aws.amazon.com/config/latest/developerguide/resource-config-reference.html custom_lambda_resource_types = [ + "AWS::ECR::Repository", + "AWS::ECR::RegistryPolicy", + "AWS::ECR::PullThroughCacheRule", + "AWS::ECR::PublicRepository", + "AWS::AmazonMQ::Broker", "AWS::ECS::Cluster", "AWS::ECS::Cluster", "AWS::ECS::TaskDefinition", "AWS::ECS::Service", "AWS::ECS::TaskSet", "AWS::ECS::CapacityProvider", - + "AWS::CloudFront::Distribution", + "AWS::CloudFront::StreamingDistribution", + "AWS::CloudWatch::Alarm", + "WS::CloudWatch::MetricStream", + "AWS::OpenSearch::Domain", + "AWS::Elasticsearch::Domain", + "AWS::EKS::Cluster", + "AWS::EKS::FargateProfile", + "AWS::EKS::IdentityProviderConfig", + "AWS::EKS::Addon", + "AWS::Lambda::Function", + "AWS::Athena::WorkGroup", + "AWS::Athena::DataCatalog", + "AWS::Athena::PreparedStatement", + "AWS::SQS::Queue", + "AWS::SNS::Topic", + "AWS::EMR::SecurityConfiguration", + "AWS::Events::EventBus", + "AWS::Events::Rule", + "AWS::GuardDuty::Detector", + "AWS::GuardDuty::ThreatIntelSet", + "AWS::GuardDuty::IPSet", + "AWS::GuardDuty::Filter", + "AWS::MSK::Cluster", + "AWS::MSK::Configuration", + "AWS::KafkaConnect::Connector", + "AWS::MSK::BatchScramSecret", + "AWS::Backup::BackupPlan", + "AWS::Backup::BackupSelection", + "AWS::Backup::BackupVault", + "AWS::Backup::RecoveryPoint", + "AWS::Backup::ReportPlan", + "AWS::NetworkManager::TransitGatewayRegistration", + "AWS::NetworkManager::GlobalNetwork", + "AWS::NetworkManager::CustomerGatewayAssociation", + "AWS::SecretsManager::Secret", + "AWS::ApiGatewayV2::Api", + "AWS::ApiGateway::RestApi", + "AWS::Cloud9::EnvironmentEC2", + "AWS::CloudTrail::Trail" ] - + diff --git a/aws/modules/tag-conformance-pack/examples/multiple-accounts-deploy/backend.tf b/aws/modules/tag-conformance-pack/examples/multiple-accounts-deploy/backend.tf index 12c0dbe..502a55a 100644 --- a/aws/modules/tag-conformance-pack/examples/multiple-accounts-deploy/backend.tf +++ b/aws/modules/tag-conformance-pack/examples/multiple-accounts-deploy/backend.tf @@ -1,3 +1,37 @@ terraform { backend "s3" {} } + + +module "backend_bucket" { + source = "terraform-aws-modules/s3-bucket/aws" + version = "3.15.1" + + create_bucket = var.create_tf_backend + + bucket = "tag-conformance-pack-terraform-${replace(lower(var.profile), "_", "-")}" + acl = "private" + control_object_ownership = true + object_ownership = "ObjectWriter" + + versioning = { + enabled = true + } +} + +module "backend_dynamodb_table" { + source = "terraform-aws-modules/dynamodb-table/aws" + + create_table = var.create_tf_backend_dynamo_table + + name = "tag-conformance-pack-terraform-${replace(lower(var.profile), "_", "-")}" + server_side_encryption_enabled = true + hash_key = "LockID" + + attributes = [ + { + name = "LockID" + type = "S" + } + ] +} \ No newline at end of file diff --git a/aws/modules/tag-conformance-pack/examples/multiple-accounts-deploy/conformance-pack.tf b/aws/modules/tag-conformance-pack/examples/multiple-accounts-deploy/conformance-pack.tf index f650fd8..dbf8238 100644 --- a/aws/modules/tag-conformance-pack/examples/multiple-accounts-deploy/conformance-pack.tf +++ b/aws/modules/tag-conformance-pack/examples/multiple-accounts-deploy/conformance-pack.tf @@ -2,8 +2,6 @@ module "ConformancePack" { source = "../module/tag-conformance-pack" profile = var.profile - create_tf_backend = var.create_tf_backend - create_tf_backend_dynamo_table = var.create_tf_backend_dynamo_table bucket_name = var.bucket_name application_domain_path = var.application_domain_path RemediationExecutionControls = var.RemediationExecutionControls diff --git a/aws/modules/tag-conformance-pack/examples/multiple-accounts-deploy/providers.tf b/aws/modules/tag-conformance-pack/examples/multiple-accounts-deploy/providers.tf index b1f3890..79c2201 100644 --- a/aws/modules/tag-conformance-pack/examples/multiple-accounts-deploy/providers.tf +++ b/aws/modules/tag-conformance-pack/examples/multiple-accounts-deploy/providers.tf @@ -3,6 +3,10 @@ provider "aws" { region = var.region default_tags { tags = { +<<<<<<< HEAD + Name = "TagConformancePack" +======= +>>>>>>> main git-location = "https://gitlab.com/raiadrogasil/rd/devops-rd/finopstools/tagconformacepack" application = var.tags["application"] domain = var.tags["domain"] diff --git a/aws/modules/tag-conformance-pack/examples/multiple-accounts-deploy/variables.tf b/aws/modules/tag-conformance-pack/examples/multiple-accounts-deploy/variables.tf index ac6ab24..59d2d53 100644 --- a/aws/modules/tag-conformance-pack/examples/multiple-accounts-deploy/variables.tf +++ b/aws/modules/tag-conformance-pack/examples/multiple-accounts-deploy/variables.tf @@ -6,7 +6,15 @@ variable "profile" { } variable "tags" { - type = map(string) + type = object({ + application = string + domain = string + board = string + company = string + shared = string + env = string + tag_created = string + }) } variable "application_domain_path" { @@ -25,7 +33,7 @@ variable "custom_lambda_resource_types" { variable "custom_lambda_script" { type = string - description = "script para a função lambda do lambda custom config" + description = "script para a função landa do lambda custom config" } variable "script_path" { @@ -55,7 +63,17 @@ variable "RemediationExecutionControls" { MaximumAutomaticAttempts = number RetryAttemptSeconds = number }) - + default = { + ExecutionControls = { + SsmControls = { + ConcurrentExecutionRatePercentage = 20 + ErrorPercentage = 40 + } + } + Automatic = false + MaximumAutomaticAttempts = 1 + RetryAttemptSeconds = 1200 + } description = "Config Remediation ExecutionControls yaml block" } @@ -77,4 +95,12 @@ variable "event_bridge_tagger_script" { variable "create_event_bridge_tagger" { type = bool +} + +# a função lambda event_bridge_tagger vai dispara apenas quando um recurso for modificado. +# esse scheduler tem como função executar a função lambda periodicamente para todos os recursos suportados por ela. +variable "schedule_expression" { + type = string + default = "rate(10 day)" + description = "taxa de execução do event bridge schedule que dispara a função lambda event_bridge_tagger." } \ No newline at end of file diff --git a/aws/modules/tag-conformance-pack/lambda-event_bridge_tagger.tf b/aws/modules/tag-conformance-pack/lambda-event_bridge_tagger.tf index facd3a5..7df0ce3 100644 --- a/aws/modules/tag-conformance-pack/lambda-event_bridge_tagger.tf +++ b/aws/modules/tag-conformance-pack/lambda-event_bridge_tagger.tf @@ -7,7 +7,7 @@ module "event_bridge_tagger" { handler = "${trimsuffix(var.event_bridge_tagger_script, ".py")}.lambda_handler" runtime = "python3.10" create = var.create_event_bridge_tagger - source_path = "../module/tag-conformance-pack/src/event_bridge_tagger.py" # #"${var.script_path}/${var.event_bridge_tagger_script}" + source_path = "${var.script_path}/${var.event_bridge_tagger_script}" attach_create_log_group_permission = true cloudwatch_logs_retention_in_days = 1 @@ -145,6 +145,7 @@ PATTERN } + resource "aws_cloudwatch_event_target" "cloudwatch_logs_trigger" { count = var.create_event_bridge_tagger ? 1 : 0 rule = aws_cloudwatch_event_rule.cloudwatch_logs_trigger[0].name @@ -168,3 +169,23 @@ resource "aws_cloudwatch_event_target" "config_rule_trigger" { rule = aws_cloudwatch_event_rule.config_rule_trigger[0].name arn = module.event_bridge_tagger.lambda_function_arn } + +module "event_bridge_schedule" { + source = "terraform-aws-modules/eventbridge/aws" + create = var.create_event_bridge_tagger + + bus_name = "event_bridge_tagger_schedule" + + attach_lambda_policy = true + lambda_target_arns = [module.event_bridge_tagger.lambda_function_arn] + + schedules = { + event-bridge-tagger-cron = { + description = "Trigger for a Lambda" + schedule_expression = var.schedule_expression + timezone = "America/Sao_Paulo" + arn = module.event_bridge_tagger.lambda_function_arn + input = jsonencode({ "event_bridge_tagger_schedule": "schedule" }) # utilizado no script para distinguir o evento de schedule de outros. + } + } +} \ No newline at end of file diff --git a/aws/modules/tag-conformance-pack/src/event_bridge_tagger.py b/aws/modules/tag-conformance-pack/src/event_bridge_tagger.py index ae2d80e..3efe289 100644 --- a/aws/modules/tag-conformance-pack/src/event_bridge_tagger.py +++ b/aws/modules/tag-conformance-pack/src/event_bridge_tagger.py @@ -32,7 +32,7 @@ def load_application_domain_json_catalog_from_s3(self): )['Body'].read().decode('utf-8') return json.loads(response) - except Exception as e: + except ClientError as e: print(f"Error reading JSON from S3: {e}") raise @@ -90,7 +90,7 @@ def get_application_domain_values_from_json(self, json_data, search_key): domain_value = matching_item.get("domain", "") return application_value, domain_value - except Exception as e: + except ClientError as e: print( f"\nNo match found for search key (application and domain values): {search_key}\n" ) @@ -253,6 +253,7 @@ def get_logs_tags(self, resource_arn) -> dict: return response['tags'] + def get_ssm_parameter_tags(self, resource_arn) -> list: response = self.ssm.list_tags_for_resource( ResourceType = 'Parameter', @@ -267,62 +268,191 @@ def get_config_rule_tags(self, resource_arn) -> list: return response['Tags'] + def get_log_groups(self) -> list: + ''' + + :return: lista de arns de todos os log groups + ''' + next_token = None + arn_list = [] + + while True: + if next_token: + response = self.logs.describe_log_groups( + limit = 50, + NextToken = next_token + ) + + else: + response = self.logs.describe_log_groups( + limit = 50, + ) + + resources = response['logGroups'] + + for resource in resources: + resource_arn = f"arn:aws:logs:{region}:{account}:log-group:{resource['logGroupName']}" + arn_list.append(resource_arn) + next_token = response.get('nextToken') + + if not next_token: + break + + return arn_list + + def get_config_rules(self) -> list: + ''' + + :return: lista de arns de todos os log groups + ''' + next_token = None + arn_list = [] + + while True: + if next_token: + response = self.config.describe_config_rules( + NextToken = next_token + ) + else: + response = self.config.describe_config_rules( + ) + + resources = response['ConfigRules'] + + for resource in resources: + resource_arn = resource['ConfigRuleArn'] + arn_list.append(resource_arn) + + next_token = response.get('NextToken') + + if not next_token: + break + + return arn_list + + def get_ssm_parameters(self) -> list: + ''' + + :return: lista de arns de todos os ssm parameters + ''' + next_token = None + arn_list = [] + + while True: + if next_token: + response = self.ssm.describe_parameters( + MaxResults = 50, + NextToken = next_token + ) + else: + response = self.ssm.describe_parameters( + MaxResults = 50 + ) + + resources = response['Parameters'] + + for resource in resources: + resource_arn = resource['Name'] + arn_list.append(resource_arn) + + next_token = response.get('NextToken') + + if not next_token: + break + + return arn_list + + + def get_elasticache_clusters(self) -> list: + ''' + + :return: lista de arns de todos os ssm parameters + ''' + next_token = None + arn_list = [] + + while True: + if next_token: + response = self.elasticache.describe_cache_clusters( + MaxRecords = 100, + Marker = next_token + ) + else: + response = self.elasticache.describe_cache_clusters( + MaxRecords = 100 + ) + + resources = response['CacheClusters'] + + for resource in resources: + resource_arn = resource['ARN'] + arn_list.append(resource_arn) + + next_token = response.get('Marker') + + if not next_token: + break + + return arn_list + def check_defined(reference, reference_name): if not reference: - raise Exception('Error: ', reference_name, 'is not defined') + raise ClientError('Error: ', reference_name, 'is not defined') return reference -def lambda_handler(event, context): - ''' - Cada evento represena 1 recurso. Para cada recurso é comparado suas tags um catálogo de tags de referência. - Se fora de conformidade o recurso é tagueado. - :param event: payload do eventbridge - :return: resposta da api de tagueamento ou que o recurso já está em compliance com o catálogo. - ''' - event_source = event["source"] +def resource_tagger(event, lambda_action): print(f"Event: {event}\n") + event_source = event["source"] print(f"EVENT SOURCE: {event_source}\n") resource_key_words = [] resource_arn = "" - # cada source (logs, elasticache, ssm, config) possui uma estrutura de payload diferente. - if 'logs' in event_source: - if "resourceArn" in event["detail"]["requestParameters"].keys(): - resource_arn = event["detail"]["requestParameters"]["resourceArn"] + if 'event_bridge_tagger_schedule' not in event: + # cada source (logs, elasticache, ssm, config) possui uma estrutura de payload diferente. + if 'logs' in event_source: + if "resourceArn" in event["detail"]["requestParameters"].keys(): + resource_arn = event["detail"]["requestParameters"]["resourceArn"] - elif "logGroupName" in event["detail"]["requestParameters"].keys(): - log_group = event["detail"]["requestParameters"]["logGroupName"] - resource_arn = f"arn:aws:logs:{region}:{account}:log-group:{log_group}" - resource_key_words.extend(["logs"]) + elif "logGroupName" in event["detail"]["requestParameters"].keys(): + log_group = event["detail"]["requestParameters"]["logGroupName"] + resource_arn = f"arn:aws:logs:{region}:{account}:log-group:{log_group}" + resource_key_words.extend(["logs"]) - elif 'elasticache' in event_source: - resource_arn = event["detail"]["requestParameters"]["resourceName"] - resource_key_words.extend(["elasticache"]) + elif 'elasticache' in event_source: + resource_arn = event["detail"]["requestParameters"]["resourceName"] + resource_key_words.extend(["elasticache"]) - elif 'config' in event_source: - if "resourceArn" in event["detail"]["requestParameters"].keys(): - resource_arn = event["detail"]["requestParameters"]["resourceArn"] + elif 'config' in event_source: + if "resourceArn" in event["detail"]["requestParameters"].keys(): + resource_arn = event["detail"]["requestParameters"]["resourceArn"] - elif "configRuleArn" in event["detail"]["requestParameters"]["configRule"].keys(): - resource_arn = event["detail"]["requestParameters"]["configRule"]["configRuleArn"] + elif "configRuleArn" in event["detail"]["requestParameters"]["configRule"].keys(): + resource_arn = event["detail"]["requestParameters"]["configRule"]["configRuleArn"] - elif 'ssm' in event_source: - resource_arn = event["detail"]["requestParameters"]["resourceId"] - resource_key_words.extend(["ssm"]) + elif 'ssm' in event_source: + resource_arn = event["detail"]["requestParameters"]["resourceId"] + # o ssm é identificado via resource id que não contem a palavra ssm como no arn de outros recursos + # portanto é necessario add a palavra à lista de comparações + resource_key_words.extend(["ssm"]) + else: + raise ClientError('event source não identificado. Recrusosos suportados: SSM, CONFIG, ELASTICACHE, LOGS') else: - raise Exception('event source não identificado. Recrusosos suportados: SSM, CONFIG, ELASTICACHE, LOGS') + resource_arn = event['resourceID'] + if 'ssm' in event_source: + # o ssm é identificado via resource id que não contem a palavra 'ssm',por exemplo, como no arn de outros recursos + # portanto é necessario add a palavra à lista de comparações + resource_key_words.extend(["ssm"]) required_tags = {} - lambda_action = EventBridgeTagger( - bucket_name = os.environ.get("BUCKET_NAME"), - application_domain_json_key = os.environ.get("BUCKET_KEY"), - ) - - resource_tags = lambda_action.get_tags(event_source, resource_arn) + try: + resource_tags = lambda_action.get_tags(event_source, resource_arn) + except ClientError as e: + print(f'Erro ao listar tags do recurso: {e}') + raise # normalizar a estrutura de tags para formato lista if isinstance(resource_tags, dict): @@ -361,7 +491,7 @@ def lambda_handler(event, context): resource_key_words.extend([item['eks:nodegroup-name']]) print(f"Lista de palavras + TagName e Tags EKS, se houver -> {resource_key_words}\n") - except Exception as e: + except ClientError as e: print(f'\n exception No tag Name found-> {e}') print(f'continuing...') @@ -370,7 +500,7 @@ def lambda_handler(event, context): json_data = json_data, resource_words_list = resource_key_words ) print(f'\nsearch_key -> {search_key}') - except Exception as e: + except ClientError as e: print(f'\nNão foi possivel encontrar search_key\n') raise @@ -393,7 +523,7 @@ def lambda_handler(event, context): required_tags['env'] = os.environ.get("TAG_ENV") - except Exception as e: + except ClientError as e: print( f'\nNão foi possivel gerar tags application e/ou domain -> \n{e}\n' ) @@ -403,14 +533,67 @@ def lambda_handler(event, context): if required_tags == lambda_action.array_to_dict(resource_tags): print(f'\nREQUIRED TAGS: \n {required_tags}') print(f'\nRESOURCE TAGS: \n {resource_tags}') - print("NOTHING TO DO, TAG IS COMPLIANT") - return "Nothing to do, tag is COMPLIANT" + return "NOTHING TO DO, TAG IS COMPLIANT" + + else: + # add info tags + # required_tags['lambda_automation'] = "event_bridge_tagger" + + try: + response = lambda_action.tag_resource(event_source, resource_arn, required_tags) + except ClientError as e: + print(f'Erro ao taguear o recurso: {e}') + raise + + print(f'RESPONSE -> {response}') + return response + + +def schedule_trigger(event, lambda_action): + resources_arns = [] + lambda_response = {} + lambda_action = lambda_action + + event_sources = ["aws.logs", "aws.config", "" + ".ssm", "aws.elasticache"] + + for event_source in event_sources: + event['source'] = event_source + + if 'logs' in event_source: + resources_arns = lambda_action.get_log_groups() + lambda_response['logGroups'] = len(resources_arns) + elif 'config' in event_source: + resources_arns = lambda_action.get_config_rules() + lambda_response['configRules'] = len(resources_arns) + elif 'elasticache' in event_source: + resources_arns = lambda_action.get_elasticache_clusters() + lambda_response['elasticacheClusters'] = len(resources_arns) + elif 'ssm' in event_source: + resources_arns = lambda_action.get_ssm_parameters() + lambda_response['ssmParameters'] = len(resources_arns) - # add info tags - # required_tags['lambda_automation'] = "event_bridge_tagger" + print(f'TAGGING BY SCHEDULE EVENT') + print(f'TAGGING {len(resources_arns)} {event_source} resources') + for arn in resources_arns: + event['resourceID'] = arn + print(f'TAGGING {event_source}: {arn}') + response = resource_tagger(event, lambda_action) + print(f"RESPONSE -> {response}") - response = lambda_action.tag_resource(event_source, resource_arn, required_tags) + return lambda_response - print(f'\n ### response \n {response} \n########') - return response + +def lambda_handler(event, context): + lambda_action = EventBridgeTagger( + bucket_name = os.environ.get("BUCKET_NAME"), + application_domain_json_key = os.environ.get("BUCKET_KEY"), + ) + + if 'event_bridge_tagger_schedule' in event: + return schedule_trigger(event, lambda_action) + + else: + return resource_tagger(event, lambda_action) + diff --git a/aws/modules/tag-conformance-pack/ssm.tf b/aws/modules/tag-conformance-pack/ssm.tf index e7db0d7..5b735e8 100644 --- a/aws/modules/tag-conformance-pack/ssm.tf +++ b/aws/modules/tag-conformance-pack/ssm.tf @@ -1,7 +1,7 @@ # automation documents must use version 0.3 # https://docs.aws.amazon.com/systems-manager/latest/userguide/documents-schemas-features.html resource "aws_ssm_document" "SsmDocumentTagRemediation" { - name = "SsmDocumentTagRemediation" + name = "SsmDocumentTagRemediationAutomation" document_format = "YAML" document_type = "Automation" content = local.ssm_content diff --git a/aws/modules/tag-conformance-pack/variables.tf b/aws/modules/tag-conformance-pack/variables.tf index 9a6c2dd..390f900 100644 --- a/aws/modules/tag-conformance-pack/variables.tf +++ b/aws/modules/tag-conformance-pack/variables.tf @@ -63,16 +63,11 @@ variable "script_policy" { type = any } -variable "create_tf_backend" { - type = bool - default = false -} - -variable "create_tf_backend_dynamo_table" { - type = bool - default = false +variable "profile" { + type = string } -variable "profile" { +variable "schedule_expression" { type = string + default = "rate(10 day)" } \ No newline at end of file