diff --git a/README-base-tfvars.md b/README-base-tfvars.md new file mode 100644 index 0000000..344e8c8 --- /dev/null +++ b/README-base-tfvars.md @@ -0,0 +1,283 @@ +# How do we fix tfvars? + +The example is [terraform.example.tfvars](terraform/base/terraform.example.tfvars). The following is a list of things that must be modified and things that should be modified when doing terraform apply for the first time. +If you need to adjust the parameters, you can do so by yourself by searching TODO. + +- [Required](#required) + - [deploy_user](#deployuser) + - [region](#region) + - [support_iam_role_principal_arns](#supportiamroleprincipalarns) +- [Not Required](#not-required) + - [tags](#tags) + - [Slack](#slack) + - [is_enabled](#isenabled) + +# Required + +The following items must be modified; terraform apply will fail if you run it as an example. + +## deploy_user + +Specify a user to deploy Terraform that has been registered as an IAM user. +Of course, you can narrow down the permissions, but due to the large number of permissions required, give the user `Administrator Access` to deploy Terraform. + +``` +#-------------------------------------------------------------- +# Deploy IAM user +#-------------------------------------------------------------- +# TODO: need to change deploy IAM user. +deploy_user = "terraform" +``` + +## region + +Select the region where you want to create the resource. + +``` +# TODO: need to change region. +region = "ap-northeast-1" +``` + +## support_iam_role_principal_arns + +The following are the supporting IAM roles. If you are not sure, please specify your AWS Account ID once. For detailed documentation, please see + +https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-cis-controls.html#cis-1.20-remediation + +``` + # TODO: need to set principal role arn for Support IAM Role. + # https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-cis-controls.html#cis-1.20-remediation + support_iam_role_principal_arns = [ + # example) + # "arn:aws:iam::{account id}:{iam user}" + "arn:aws:iam::999999999999:root" + ] +``` + +# Not Required + +Although terraform apply will succeed without fixing the following items, the following is a list of things that should be changed for each environment. + +## tags + +You can leave the following as it is without any problem. However, if you want to add TAGs to the resources according to your environment, please modify the following. + +``` +# TODO: need to change tags. +tags = { +# TODO: need to change env. +env = "dev" +# TODO: need to change service. +# service is project name or job name or product name. +service = "base" +} +``` + +## Slack + +Basically, for notifications, you need an oauth access token from Slack and a specified channel ID. +If you can get it, please modify all of the following If there is no normal token and channel ID, you will not be notified, but the deployment itself will succeed. + +``` + # TODO: need to change SLACK_OAUTH_ACCESS_TOKEN. + SLACK_OAUTH_ACCESS_TOKEN = "xxxx-xxxxxxxxxxxxx-xxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxx" + # TODO: need to change SLACK_CHANNEL_ID. + SLACK_CHANNEL_ID = "XXXXXXXXXXXXXX" +``` + +## is_enabled + +The variable for each function has is_enabled. If you do not want to use it as a function, you can disable it by specifying false. + +- Budgets + +``` +#-------------------------------------------------------------- +# Budgets +#-------------------------------------------------------------- +budgets = { + # TODO: need to set is_enabled for settings of budgets. + is_enabled = true +``` + +- IAM + +``` +#-------------------------------------------------------------- +# IAM: Users +#-------------------------------------------------------------- +iam = { + # TODO: need to set is_enabled for settings of IAM. + is_enabled = true +``` + +- Compute Optimizer + +``` + #-------------------------------------------------------------- + +# Compute Optimizer + +# AWS Compute Optimizer recommends optimal AWS resources for your workloads to reduce + +# costs and improve performance by using machine learning to analyze historical utilization metrics. + +# Over-provisioning resources can lead to unnecessary infrastructure cost, and under-provisioning resources + +# can lead to poor application performance. Compute Optimizer helps you choose optimal configurations + +# for three types of AWS resources: Amazon EC2 instances, Amazon EBS volumes, and AWS Lambda functions, + +# based on your utilization data. + +#-------------------------------------------------------------- +compute_optimizer = { + +# TODO: need to set is_enabled for settings of Compute Optimizer. + +is_enabled = true +} +``` + +- Health + +``` +#-------------------------------------------------------------- +# Health +#-------------------------------------------------------------- +health = { + # TODO: need to set is_enabled for settings of AWS Health. + is_enabled = true +``` + +- Trusted Advisor + +``` +#-------------------------------------------------------------- +# Trusted Advisor +#-------------------------------------------------------------- +trusted_advisor = { + # TODO: need to set is_enabled for settings of Trusted Advisor. + // If you are not in a business or enterprise plan with a support plan, set is_enable to false as notifications will fail. If not, set it to true. + is_enabled = false +``` + +- Access Analyzer + +``` +#-------------------------------------------------------------- +# Security:Access Analyzer +#-------------------------------------------------------------- +security_access_analyzer = { + # TODO: need to set is_enabled for settings of Access Analyzer. + is_enabled = true +``` + +- Access Analyzer + +``` +#-------------------------------------------------------------- +# Security:Access Analyzer +#-------------------------------------------------------------- +security_access_analyzer = { + # TODO: need to set is_enabled for settings of Access Analyzer. + is_enabled = true +``` + +- CloudTrail + +``` +#-------------------------------------------------------------- +# Security:CloudTrail +#-------------------------------------------------------------- +security_cloudtrail = { + # TODO: need to set is_enabled for settings of CloudTrail. + is_enabled = true +``` + +- AWS Config + +``` +#-------------------------------------------------------------- +# Security:AWS Config +#-------------------------------------------------------------- +security_config = { + # TODO: need to set is_enabled for settings of AWS Config. + is_enabled = true +``` + +- Security:AWS Config(us-east-1(CloudFront)) + +``` +#-------------------------------------------------------------- +# Security:AWS Config(us-east-1(CloudFront)) +#-------------------------------------------------------------- +security_config_us_east_1 = { + # TODO: need to set is_enabled for settings of AWS Config. + is_enabled = false +``` + +- Security: Default VPC + +``` +#-------------------------------------------------------------- +# Security:Default VPC +#-------------------------------------------------------------- +security_default_vpc = { + # TODO: need to set is_enabled for settings of default VPC security. + is_enabled = true +``` + +- Security: EBS + +``` +#-------------------------------------------------------------- +# Security:EBS +#-------------------------------------------------------------- +security_ebs = { + # TODO: need to set is_enabled for settings of EBS. +``` + +- Security:GuardDuty + +``` +#-------------------------------------------------------------- +# Security:GuardDuty +#-------------------------------------------------------------- +security_guardduty = { + # TODO: need to set is_enabled for settings of GuardDuty. + is_enabled = true +``` + +- Security:IAM + +``` +#-------------------------------------------------------------- +# Security:IAM +#-------------------------------------------------------------- +security_iam = { + # TODO: need to set is_enabled for settings of IAM security. + is_enabled = true +``` + +- Security:S3 + +``` +#-------------------------------------------------------------- +# Security:S3 +#-------------------------------------------------------------- +security_s3 = { + # TODO: need to set is_enabled for settings of S3 security. + is_enabled = true +``` + +- Security:SecurityHub + +``` +#-------------------------------------------------------------- +# Security:SecurityHub +#-------------------------------------------------------------- +security_securityhub = { + # TODO: need to set is_enabled for settings of SecurityHub. + is_enabled = true +``` diff --git a/README.md b/README.md index d133a4a..72e8fdb 100644 --- a/README.md +++ b/README.md @@ -174,7 +174,6 @@ region: ap-northeast-1 - terraform.{environment}.tfvars file to configure for each environment You need to rename the linked file [terraform.example.tfvars](terraform/base/terraform.example.tfvars) and change each variable for your environment. The variables that need to be changed are marked with TODO comments; search for them in TODO. - - main_provider.tf file to set for each environment Rename the linked file [main_provider.tf.example](terraform/base/main_provider.tf.example) to main_provider.tf. After that, you need to change each parameter. The variables that need to be changed are marked with TODO comments, search for them in TODO. @@ -278,11 +277,11 @@ This is a description of the S3 bucket that will be created and the data in the | AWS Config | aws-log-common | /AWSLogs/{accountID}/Config/{region}/yyyy/m/d/ConfigHistory/ | AWS Config Compliance History Timeline for Resources. | https://docs.aws.amazon.com/config/latest/developerguide/view-compliance-history.html | | AWS Config | aws-log-common | /AWSLogs/{accountID}/Config/{region}/yyyy/m/d/ConfigSnapshot/ | AWS Config snapshot. | https://docs.aws.amazon.com/config/latest/developerguide/deliver-snapshot-cli.html | | AWS Config | aws-log-common | /AWSLogs/{accountID}/Config/ConfigWritabilityCheckFile/yyyy/m/d | This is a test file to confirm that Config can be written to the S3 bucket normally. | | -| AWS Config | aws-log-common | /AWSLogs/{accountID}/CloudTrail/AccessLog | This is the access log of the CloudTrail bucket. | +| AWS Config | aws-log-common | /AWSLogs/{accountID}/CloudTrail/AccessLog | This is the access log of the CloudTrail bucket. | | AWS CloudTrail | aws-log-cloudtrail | /AWSLogs/{accountID}/CloudTrail-Digest/{region}/yyyy/mm/dd | Each digest file contains the names of the log files that were delivered to your Amazon S3 bucket during the last hour, the hash values for those log files, and the digital signature of the previous digest file. The signature for the current digest file is stored in the metadata properties of the digest file object. The digital signatures and hashes are used for validating the integrity of the log files and of the digest file itself. | https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-log-file-validation-digest-file-structure.html | | AWS CloudTrail | aws-log-cloudtrail | /AWSLogs/{accountID}/CloudTrail-Insight/{region}/yyyy/mm/dd | CloudTrail Insights can help you detect unusual API activity in your AWS account by raising Insights events. CloudTrail Insights measures your normal patterns of API call volume, also called the baseline, and generates Insights events when the volume is outside normal patterns. Insights events are generated for write management APIs. | https://docs.aws.amazon.com/awscloudtrail/latest/userguide/log-insights-events-with-cloudtrail.html | | AWS CloudTrail | aws-log-cloudtrail | /AWSLogs/{accountID}/CloudTrail/{region}/yyyy/mm/dd | It is recorded as an event in CloudTrail. Events include actions taken in the AWS Management Console, AWS Command Line Interface. | https://docs.aws.amazon.com/awscloudtrail/latest/userguide/get-and-view-cloudtrail-log-files.html | -| AWS Log | aws-log-application | /Logs | Application log from CloudWatch Logs. | | +| AWS Log | aws-log-application | /Logs | Application log from CloudWatch Logs. | | ## Author Information diff --git a/lambda/outputs/heartbeat.zip b/lambda/outputs/heartbeat.zip new file mode 100644 index 0000000..c675114 Binary files /dev/null and b/lambda/outputs/heartbeat.zip differ diff --git a/modules/aws/recipes/budgets/create-v4/main.tf b/modules/aws/recipes/budgets/create-v4/main.tf new file mode 100644 index 0000000..d737fc7 --- /dev/null +++ b/modules/aws/recipes/budgets/create-v4/main.tf @@ -0,0 +1,83 @@ +#-------------------------------------------------------------- +# Locals +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + +#-------------------------------------------------------------- +# Provides a budgets budget resource. Budgets use the cost visualisation provided by Cost Explorer to show you the status of your budgets, to provide forecasts of your estimated costs, and to track your AWS usage, including your free tier usage. +#-------------------------------------------------------------- +resource "aws_budgets_budget" "this" { + count = var.is_enabled ? 1 : 0 + name = lookup(var.aws_budgets_budget, "name") + budget_type = lookup(var.aws_budgets_budget, "budget_type", "COST") + dynamic "cost_filter" { + for_each = lookup(var.aws_budgets_budget, "cost_filter", []) + content { + name = lookup(cost_filter.value, "name", null) + values = lookup(cost_filter.value, "values", null) + } + } + dynamic "cost_types" { + for_each = lookup(var.aws_budgets_budget, "cost_types", [{}]) + content { + include_credit = lookup(cost_types.value, "include_credit", true) + include_discount = lookup(cost_types.value, "include_discount", true) + include_other_subscription = lookup(cost_types.value, "include_other_subscription", true) + include_recurring = lookup(cost_types.value, "include_recurring", true) + include_refund = lookup(cost_types.value, "include_refund", true) + include_subscription = lookup(cost_types.value, "include_subscription", true) + include_support = lookup(cost_types.value, "include_support", true) + include_tax = lookup(cost_types.value, "include_tax", true) + include_upfront = lookup(cost_types.value, "include_upfront", true) + use_amortized = lookup(cost_types.value, "use_amortized", false) + use_blended = lookup(cost_types.value, "use_blended", false) + } + } + limit_amount = lookup(var.aws_budgets_budget, "limit_amount") + limit_unit = lookup(var.aws_budgets_budget, "limit_unit", "USD") + time_period_end = lookup(var.aws_budgets_budget, "time_period_end", "2050-12-31_00:00") + time_period_start = lookup(var.aws_budgets_budget, "time_period_start", "2021-01-01_00:00") + time_unit = lookup(var.aws_budgets_budget, "time_unit", "MONTHLY") + dynamic "notification" { + for_each = lookup(var.aws_budgets_budget, "notification", [{}]) + content { + comparison_operator = lookup(notification.value, "comparison_operator", "GREATER_THAN") + threshold = lookup(notification.value, "threshold", "80") + threshold_type = lookup(notification.value, "threshold_type", "PERCENTAGE") + notification_type = lookup(notification.value, "notification_type", "ACTUAL") + subscriber_email_addresses = lookup(notification.value, "subscriber_email_addresses", null) + subscriber_sns_topic_arns = lookup(notification.value, "subscriber_sns_topic_arns", null) + } + } +} + +#-------------------------------------------------------------- +# Provides an EventBridge Rule resource. +#-------------------------------------------------------------- +resource "aws_cloudwatch_event_rule" "this" { + count = var.is_enabled ? 1 : 0 + name = lookup(var.aws_cloudwatch_event_rule, "name", "budgets-cloudwatch-event-rule") + schedule_expression = lookup(var.aws_cloudwatch_event_rule, "schedule_expression", "cron(0 9 * * ? *)") + description = lookup(var.aws_cloudwatch_event_rule, "description", "This cloudwatch event used for Budgets.") + is_enabled = lookup(var.aws_cloudwatch_event_rule, "is_enabled", true) + tags = local.tags +} +#-------------------------------------------------------------- +# Provides an EventBridge Target resource. +#-------------------------------------------------------------- +resource "aws_cloudwatch_event_target" "this" { + count = var.is_enabled ? 1 : 0 + rule = aws_cloudwatch_event_rule.this[0].name + arn = lookup(var.aws_cloudwatch_event_target, "arn") + depends_on = [ + aws_cloudwatch_event_rule.this[0] + ] +} diff --git a/modules/aws/recipes/budgets/outputs.tf b/modules/aws/recipes/budgets/create-v4/outputs.tf similarity index 100% rename from modules/aws/recipes/budgets/outputs.tf rename to modules/aws/recipes/budgets/create-v4/outputs.tf diff --git a/modules/aws/recipes/budgets/create-v4/variables.tf b/modules/aws/recipes/budgets/create-v4/variables.tf new file mode 100644 index 0000000..88e07e4 --- /dev/null +++ b/modules/aws/recipes/budgets/create-v4/variables.tf @@ -0,0 +1,61 @@ +#-------------------------------------------------------------- +# module variables +#-------------------------------------------------------------- +variable "is_enabled" { + type = bool + description = "(Optional) A boolean flag to enable/disable Budgets. Defaults true." + default = true +} +variable "aws_budgets_budget" { + type = object( + { + # The name of a budget. Unique within accounts. + name = string + # Whether this budget tracks monetary cost or usage. + budget_type = string + # Map of Cost Filters key/value pairs to apply to the budget. + cost_filter = list(any) + # The amount of cost or usage being measured for a budget. + limit_amount = string + # Object containing Budget Notifications. Can be used multiple times to define more than one budget notification + notification = list(any) + } + ) + description = "(Required) Provides a budgets budget resource. Budgets use the cost visualisation provided by Cost Explorer to show you the status of your budgets, to provide forecasts of your estimated costs, and to track your AWS usage, including your free tier usage." +} + +variable "aws_cloudwatch_event_rule" { + type = object( + { + # The name of the rule. If omitted, Terraform will assign a random, unique name. Conflicts with name_prefix. + name = string + # The scheduling expression. For example, cron(0 20 * * ? *) or rate(5 minutes). At least one of schedule_expression or event_pattern is required. Can only be used on the default event bus. + schedule_expression = string + # The description of the rule. + description = string + # Whether the rule should be enabled (defaults to true). + is_enabled = bool + } + ) + description = "(Optional) Provides an EventBridge Rule resource." + default = { + name = "budgets-cloudwatch-event-rule" + description = "This cloudwatch event used for Budgets." + schedule_expression = "cron(0 9 * * ? *)" + is_enabled = true + } +} +variable "aws_cloudwatch_event_target" { + type = object( + { + # The Amazon Resource Name (ARN) associated of the target. + arn = string + } + ) + description = "(Required) Provides an EventBridge Target resource." +} +variable "tags" { + type = map(any) + description = "(Optional) Key-value map of resource tags." + default = null +} diff --git a/modules/aws/recipes/budgets/create-v4/versions.tf b/modules/aws/recipes/budgets/create-v4/versions.tf new file mode 100644 index 0000000..11294d7 --- /dev/null +++ b/modules/aws/recipes/budgets/create-v4/versions.tf @@ -0,0 +1,12 @@ +#-------------------------------------------------------------- +# Terraform Provider +#-------------------------------------------------------------- +terraform { + required_version = ">=0.14" + required_providers { + aws = { + source = "hashicorp/aws" + version = ">=4.0.0" + } + } +} diff --git a/modules/aws/recipes/budgets/main.tf b/modules/aws/recipes/budgets/create/main.tf similarity index 84% rename from modules/aws/recipes/budgets/main.tf rename to modules/aws/recipes/budgets/create/main.tf index 28c6fea..3b90e34 100644 --- a/modules/aws/recipes/budgets/main.tf +++ b/modules/aws/recipes/budgets/create/main.tf @@ -1,8 +1,22 @@ +#-------------------------------------------------------------- +# Locals +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Provides a budgets budget resource. Budgets use the cost visualisation provided by Cost Explorer to show you the status of your budgets, to provide forecasts of your estimated costs, and to track your AWS usage, including your free tier usage. #-------------------------------------------------------------- resource "aws_budgets_budget" "this" { count = var.is_enabled ? 1 : 0 + account_id = lookup(var.aws_budgets_budget, "account_id", null) name = lookup(var.aws_budgets_budget, "name") budget_type = lookup(var.aws_budgets_budget, "budget_type", "COST") cost_filters = lookup(var.aws_budgets_budget, "cost_filters", []) @@ -49,7 +63,7 @@ resource "aws_cloudwatch_event_rule" "this" { schedule_expression = lookup(var.aws_cloudwatch_event_rule, "schedule_expression", "cron(0 9 * * ? *)") description = lookup(var.aws_cloudwatch_event_rule, "description", "This cloudwatch event used for Budgets.") is_enabled = lookup(var.aws_cloudwatch_event_rule, "is_enabled", true) - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an EventBridge Target resource. diff --git a/modules/aws/recipes/budgets/create/outputs.tf b/modules/aws/recipes/budgets/create/outputs.tf new file mode 100644 index 0000000..521a246 --- /dev/null +++ b/modules/aws/recipes/budgets/create/outputs.tf @@ -0,0 +1,4 @@ +output "arn" { + description = "The Amazon Resource Name (ARN) of the rule" + value = var.is_enabled ? aws_cloudwatch_event_rule.this[0].arn : null +} diff --git a/modules/aws/recipes/budgets/variables.tf b/modules/aws/recipes/budgets/create/variables.tf similarity index 100% rename from modules/aws/recipes/budgets/variables.tf rename to modules/aws/recipes/budgets/create/variables.tf diff --git a/modules/aws/recipes/budgets/versions.tf b/modules/aws/recipes/budgets/create/versions.tf similarity index 100% rename from modules/aws/recipes/budgets/versions.tf rename to modules/aws/recipes/budgets/create/versions.tf diff --git a/modules/aws/recipes/cloudwatch/alarm/log/main.tf b/modules/aws/recipes/cloudwatch/alarm/log/main.tf index 9587f6d..deb19fc 100644 --- a/modules/aws/recipes/cloudwatch/alarm/log/main.tf +++ b/modules/aws/recipes/cloudwatch/alarm/log/main.tf @@ -2,6 +2,9 @@ # Locals #-------------------------------------------------------------- locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } aws_cloudwatch_log_metric_filter = { for k, v in var.aws_cloudwatch_log_metric_filter : v.log_group_name => v } @@ -9,6 +12,11 @@ locals { for k, v in var.aws_cloudwatch_metric_alarm : v.alarm_name => v } } +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Provides a CloudWatch Log Metric Filter resource. #-------------------------------------------------------------- @@ -52,5 +60,5 @@ resource "aws_cloudwatch_metric_alarm" "this" { extended_statistic = lookup(each.value, "extended_statistic", null) treat_missing_data = lookup(each.value, "treat_missing_data", null) evaluate_low_sample_count_percentiles = lookup(each.value, "evaluate_low_sample_count_percentiles", null) - tags = var.tags + tags = local.tags } diff --git a/modules/aws/recipes/cloudwatch/alarm/metric/main.tf b/modules/aws/recipes/cloudwatch/alarm/metric/main.tf index 4f9667d..fd1def9 100644 --- a/modules/aws/recipes/cloudwatch/alarm/metric/main.tf +++ b/modules/aws/recipes/cloudwatch/alarm/metric/main.tf @@ -1,3 +1,16 @@ +#-------------------------------------------------------------- +# Locals +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } +} +##-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Provides a CloudWatch Metric Alarm resource. #-------------------------------------------------------------- @@ -43,5 +56,5 @@ resource "aws_cloudwatch_metric_alarm" "this" { } } } - tags = var.tags + tags = local.tags } diff --git a/modules/aws/recipes/cloudwatch/event/main.tf b/modules/aws/recipes/cloudwatch/event/main.tf index 547baae..6851a88 100644 --- a/modules/aws/recipes/cloudwatch/event/main.tf +++ b/modules/aws/recipes/cloudwatch/event/main.tf @@ -1,3 +1,16 @@ +#-------------------------------------------------------------- +# Locals +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Provides an EventBridge Rule resource. #-------------------------------------------------------------- @@ -8,7 +21,7 @@ resource "aws_cloudwatch_event_rule" "this" { description = lookup(var.aws_cloudwatch_event_rule, "description", null) role_arn = lookup(var.aws_cloudwatch_event_rule, "role_arn", null) is_enabled = lookup(var.aws_cloudwatch_event_rule, "is_enabled", null) - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an EventBridge Target resource. diff --git a/modules/aws/recipes/cloudwatch/subscription/main.tf b/modules/aws/recipes/cloudwatch/subscription/main.tf index 0ac70c8..eb2027d 100644 --- a/modules/aws/recipes/cloudwatch/subscription/main.tf +++ b/modules/aws/recipes/cloudwatch/subscription/main.tf @@ -5,8 +5,16 @@ locals { aws_cloudwatch_log_subscription_filter = { for k, v in var.aws_cloudwatch_log_subscription_filter : v.name => v } + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } } +##-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. #-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + +# -------------------------------------------------------------- # Provides an IAM role. #-------------------------------------------------------------- resource "aws_iam_role" "this" { @@ -27,7 +35,7 @@ resource "aws_iam_role" "this" { } POLICY path = lookup(var.aws_iam_role, "path", "/") - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Generates an IAM policy document in JSON format for use with resources that expect policy documents such as aws_iam_policy. diff --git a/modules/aws/recipes/health/main.tf b/modules/aws/recipes/health/main.tf index 2120ccc..33dff4e 100644 --- a/modules/aws/recipes/health/main.tf +++ b/modules/aws/recipes/health/main.tf @@ -1,3 +1,16 @@ +#-------------------------------------------------------------- +# Locals +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Provides an EventBridge Rule resource. #-------------------------------------------------------------- @@ -13,7 +26,7 @@ resource "aws_cloudwatch_event_rule" "this" { EVENT_PATTERN description = lookup(var.aws_cloudwatch_event_rule, "description", "This cloudwatch event used for Health.") is_enabled = lookup(var.aws_cloudwatch_event_rule, "is_enabled", true) - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an EventBridge Target resource. diff --git a/modules/aws/recipes/iam/role/cloudtrail/main.tf b/modules/aws/recipes/iam/role/cloudtrail/main.tf index 6c55574..17c0524 100644 --- a/modules/aws/recipes/iam/role/cloudtrail/main.tf +++ b/modules/aws/recipes/iam/role/cloudtrail/main.tf @@ -1,3 +1,16 @@ +#-------------------------------------------------------------- +# Locals +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Provides an IAM role. #-------------------------------------------------------------- @@ -20,7 +33,7 @@ resource "aws_iam_role" "this" { POLICY force_detach_policies = true path = lookup(var.aws_iam_role, "path", "/") - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an IAM policy. diff --git a/modules/aws/recipes/iam/role/cloudwatch/main.tf b/modules/aws/recipes/iam/role/cloudwatch/main.tf index b0223fd..8ec40c2 100644 --- a/modules/aws/recipes/iam/role/cloudwatch/main.tf +++ b/modules/aws/recipes/iam/role/cloudwatch/main.tf @@ -1,3 +1,16 @@ +#-------------------------------------------------------------- +# Locals +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Provides an IAM role. #-------------------------------------------------------------- @@ -20,7 +33,7 @@ resource "aws_iam_role" "this" { POLICY force_detach_policies = true path = lookup(var.aws_iam_role, "path", "/") - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Generates an IAM policy document in JSON format for use with resources that expect policy documents such as aws_iam_policy. diff --git a/modules/aws/recipes/iam/role/config/main.tf b/modules/aws/recipes/iam/role/config/main.tf index 7c4d814..6e2222e 100644 --- a/modules/aws/recipes/iam/role/config/main.tf +++ b/modules/aws/recipes/iam/role/config/main.tf @@ -1,3 +1,16 @@ +#-------------------------------------------------------------- +# Locals +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Provides an IAM role. #-------------------------------------------------------------- @@ -20,7 +33,7 @@ resource "aws_iam_role" "this" { POLICY force_detach_policies = true path = lookup(var.aws_iam_role, "path", "/") - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Generates an IAM policy document in JSON format for use with resources that expect policy documents such as aws_iam_policy. diff --git a/modules/aws/recipes/iam/role/ec2/main.tf b/modules/aws/recipes/iam/role/ec2/main.tf index 5dcbe95..852619e 100644 --- a/modules/aws/recipes/iam/role/ec2/main.tf +++ b/modules/aws/recipes/iam/role/ec2/main.tf @@ -1,3 +1,16 @@ +#-------------------------------------------------------------- +# Locals +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Provides an IAM role. #-------------------------------------------------------------- @@ -20,7 +33,7 @@ resource "aws_iam_role" "this" { POLICY force_detach_policies = true path = lookup(var.aws_iam_role, "path", "/") - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an IAM instance profile. diff --git a/modules/aws/recipes/iam/role/ecs/main.tf b/modules/aws/recipes/iam/role/ecs/main.tf index e6b7f91..5c47ff7 100644 --- a/modules/aws/recipes/iam/role/ecs/main.tf +++ b/modules/aws/recipes/iam/role/ecs/main.tf @@ -1,3 +1,16 @@ +#-------------------------------------------------------------- +# Locals +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # role: ecs.amazonaws.com #-------------------------------------------------------------- @@ -21,7 +34,7 @@ resource "aws_iam_role" "ecs" { POLICY force_detach_policies = true path = lookup(var.aws_iam_role.ecs, "path", "/") - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- @@ -57,7 +70,7 @@ resource "aws_iam_role" "ecs_tasks" { POLICY force_detach_policies = true path = lookup(var.aws_iam_role.ecs_tasks, "path", "/") - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- @@ -91,7 +104,7 @@ resource "aws_iam_role" "events" { POLICY force_detach_policies = true path = lookup(var.aws_iam_role.events, "path", "/") - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Generates an IAM policy document in JSON format for use with resources that expect policy documents such as aws_iam_policy. diff --git a/modules/aws/recipes/iam/role/eks/main.tf b/modules/aws/recipes/iam/role/eks/main.tf index 1b1ae0d..9373543 100644 --- a/modules/aws/recipes/iam/role/eks/main.tf +++ b/modules/aws/recipes/iam/role/eks/main.tf @@ -1,3 +1,16 @@ +#-------------------------------------------------------------- +# Locals +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Provides an IAM role. # role: eks.amazonaws.com @@ -21,7 +34,7 @@ resource "aws_iam_role" "eks" { POLICY force_detach_policies = true path = lookup(var.aws_iam_role.eks, "path", "/") - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Attaches a Managed IAM Policy to an IAM role @@ -63,7 +76,7 @@ resource "aws_iam_role" "eks_worker_node" { POLICY force_detach_policies = true path = lookup(var.aws_iam_role.eks_worker_node, "path", "/") - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Attaches a Managed IAM Policy to an IAM role diff --git a/modules/aws/recipes/iam/role/eks_alb_ingress_controller/main.tf b/modules/aws/recipes/iam/role/eks_alb_ingress_controller/main.tf index 3fd99a0..8ec2e20 100644 --- a/modules/aws/recipes/iam/role/eks_alb_ingress_controller/main.tf +++ b/modules/aws/recipes/iam/role/eks_alb_ingress_controller/main.tf @@ -1,3 +1,16 @@ +#-------------------------------------------------------------- +# Locals +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Generates an IAM policy document in JSON format for use with resources that expect policy documents such as aws_iam_policy. # policy attach: for ALB Ingrees controller @@ -33,7 +46,7 @@ resource "aws_iam_role" "this" { assume_role_policy = data.aws_iam_policy_document.this.json force_detach_policies = true path = lookup(var.aws_iam_role, "path", "/") - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- diff --git a/modules/aws/recipes/iam/role/flow_log/main.tf b/modules/aws/recipes/iam/role/flow_log/main.tf index f111069..c3f501c 100644 --- a/modules/aws/recipes/iam/role/flow_log/main.tf +++ b/modules/aws/recipes/iam/role/flow_log/main.tf @@ -1,3 +1,16 @@ +#-------------------------------------------------------------- +# Locals +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Provides an IAM role. #-------------------------------------------------------------- @@ -20,7 +33,7 @@ resource "aws_iam_role" "this" { POLICY force_detach_policies = true path = lookup(var.aws_iam_role, "path", "/") - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an IAM policy. diff --git a/modules/aws/recipes/iam/role/kinesis_firehose/main.tf b/modules/aws/recipes/iam/role/kinesis_firehose/main.tf index 5776cc5..197fc43 100644 --- a/modules/aws/recipes/iam/role/kinesis_firehose/main.tf +++ b/modules/aws/recipes/iam/role/kinesis_firehose/main.tf @@ -1,3 +1,16 @@ +#-------------------------------------------------------------- +# Locals +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Provides an IAM role. #-------------------------------------------------------------- @@ -20,7 +33,7 @@ resource "aws_iam_role" "this" { POLICY force_detach_policies = true path = lookup(var.aws_iam_role, "path", "/") - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Generates an IAM policy document in JSON format for use with resources that expect policy documents such as aws_iam_policy. diff --git a/modules/aws/recipes/iam/role/lambda/main.tf b/modules/aws/recipes/iam/role/lambda/main.tf index 733db6e..2e85d7a 100644 --- a/modules/aws/recipes/iam/role/lambda/main.tf +++ b/modules/aws/recipes/iam/role/lambda/main.tf @@ -1,4 +1,16 @@ #-------------------------------------------------------------- +# Locals +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} +#-------------------------------------------------------------- # Provides an IAM role. #-------------------------------------------------------------- resource "aws_iam_role" "this" { @@ -20,7 +32,7 @@ resource "aws_iam_role" "this" { POLICY force_detach_policies = true path = lookup(var.aws_iam_role, "path", "/") - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an IAM policy. diff --git a/modules/aws/recipes/iam/role/monitoring_rds/main.tf b/modules/aws/recipes/iam/role/monitoring_rds/main.tf index 3c45e1b..30a9d9d 100644 --- a/modules/aws/recipes/iam/role/monitoring_rds/main.tf +++ b/modules/aws/recipes/iam/role/monitoring_rds/main.tf @@ -1,3 +1,16 @@ +#-------------------------------------------------------------- +# Locals +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Provides an IAM role. #-------------------------------------------------------------- @@ -20,7 +33,7 @@ resource "aws_iam_role" "this" { POLICY force_detach_policies = true path = lookup(var.aws_iam_role, "path", "/") - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Attaches a Managed IAM Policy to an IAM role diff --git a/modules/aws/recipes/iam/role/s3/replication/main.tf b/modules/aws/recipes/iam/role/s3/replication/main.tf new file mode 100644 index 0000000..8c94084 --- /dev/null +++ b/modules/aws/recipes/iam/role/s3/replication/main.tf @@ -0,0 +1,87 @@ +#-------------------------------------------------------------- +# Locals +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + +#-------------------------------------------------------------- +# Provides an IAM role. +#-------------------------------------------------------------- +resource "aws_iam_role" "this" { + description = lookup(var.aws_iam_role, "description", null) + name = lookup(var.aws_iam_role, "name") + assume_role_policy = < v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Local #-------------------------------------------------------------- @@ -32,7 +45,7 @@ resource "aws_iam_role" "this" { assume_role_policy = lookup(var.aws_iam_role, "assume_role_policy", null) == null ? local.assume_role_policy : lookup(var.aws_iam_role, "assume_role_policy", null) force_detach_policies = true path = lookup(var.aws_iam_role, "path", "/") - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Attaches a Managed IAM Policy to an IAM role diff --git a/modules/aws/recipes/kinesis/firehose/s3/main.tf b/modules/aws/recipes/kinesis/firehose/s3/main.tf index 1bfb6c4..db67f46 100644 --- a/modules/aws/recipes/kinesis/firehose/s3/main.tf +++ b/modules/aws/recipes/kinesis/firehose/s3/main.tf @@ -2,17 +2,25 @@ # Locals #-------------------------------------------------------------- locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } aws_kinesis_firehose_delivery_stream = { for k, v in var.aws_kinesis_firehose_delivery_stream : v.name => v } } +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Provides a Kinesis Firehose Delivery Stream resource. Amazon Kinesis Firehose is a fully managed, elastic service to easily deliver real-time data streams to destinations such as Amazon S3 and Amazon Redshift. #-------------------------------------------------------------- resource "aws_kinesis_firehose_delivery_stream" "this" { for_each = local.aws_kinesis_firehose_delivery_stream name = lookup(each.value, "name") - tags = var.tags + tags = local.tags dynamic "server_side_encryption" { for_each = lookup(each.value, "server_side_encryption", []) content { @@ -87,7 +95,6 @@ resource "aws_kinesis_firehose_delivery_stream" "this" { } } } - } #-------------------------------------------------------------- # Provides an IAM role. @@ -111,7 +118,7 @@ resource "aws_iam_role" "this" { } POLICY path = lookup(var.aws_iam_role, "path", "/") - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Generates an IAM policy document in JSON format for use with resources that expect policy documents such as aws_iam_policy. diff --git a/modules/aws/recipes/lambda/create/main.tf b/modules/aws/recipes/lambda/create/main.tf index 9d3c2d8..aaf6f02 100644 --- a/modules/aws/recipes/lambda/create/main.tf +++ b/modules/aws/recipes/lambda/create/main.tf @@ -1,4 +1,16 @@ #-------------------------------------------------------------- +# Locals +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} +#-------------------------------------------------------------- # Provides a CloudWatch Log Group resource. #-------------------------------------------------------------- resource "aws_cloudwatch_log_group" "this" { @@ -6,7 +18,7 @@ resource "aws_cloudwatch_log_group" "this" { name = "/aws/lambda/${aws_lambda_function.this[0].function_name}" retention_in_days = lookup(var.aws_cloudwatch_log_group, "retention_in_days") kms_key_id = lookup(var.aws_cloudwatch_log_group, "kms_key_id", null) - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides a Lambda Function resource. @@ -53,7 +65,7 @@ resource "aws_lambda_function" "this" { } kms_key_arn = lookup(var.aws_lambda_function, "kms_key_arn", null) source_code_hash = lookup(var.aws_lambda_function, "source_code_hash", null) - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- diff --git a/modules/aws/recipes/lambda/triggers/cron/main.tf b/modules/aws/recipes/lambda/triggers/cron/main.tf index b9ca6cb..a7ad52d 100644 --- a/modules/aws/recipes/lambda/triggers/cron/main.tf +++ b/modules/aws/recipes/lambda/triggers/cron/main.tf @@ -1,3 +1,16 @@ +#-------------------------------------------------------------- +# Locals +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Provides an EventBridge Rule resource. #-------------------------------------------------------------- @@ -8,7 +21,7 @@ resource "aws_cloudwatch_event_rule" "this" { description = lookup(var.aws_cloudwatch_event_rule, "description", null) role_arn = lookup(var.aws_cloudwatch_event_rule, "role_arn", null) is_enabled = lookup(var.aws_cloudwatch_event_rule, "is_enabled", null) - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an EventBridge Target resource. diff --git a/modules/aws/recipes/lambda/vpc/main.tf b/modules/aws/recipes/lambda/vpc/main.tf index 4418197..f617399 100644 --- a/modules/aws/recipes/lambda/vpc/main.tf +++ b/modules/aws/recipes/lambda/vpc/main.tf @@ -1,3 +1,16 @@ +#-------------------------------------------------------------- +# Locals +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Provides an VPC subnet resource. #-------------------------------------------------------------- @@ -8,7 +21,7 @@ resource "aws_subnet" "this" { map_public_ip_on_launch = lookup(var.aws_subnet[count.index], "map_public_ip_on_launch", false) outpost_arn = lookup(var.aws_subnet[count.index], "outpost_arn", null) vpc_id = lookup(var.aws_subnet[count.index], "vpc_id", null) - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides a resource to create an association between a route table and a subnet or a route table and an internet gateway or virtual private gateway. @@ -41,7 +54,7 @@ resource "aws_security_group" "this" { #tfsec:ignore:AWS009 cidr_blocks = ["0.0.0.0/0"] } - tags = var.tags + tags = local.tags lifecycle { create_before_destroy = true } @@ -55,7 +68,7 @@ resource "aws_iam_role" "this" { assume_role_policy = lookup(var.aws_iam_role, "assume_role_policy") force_detach_policies = true path = lookup(var.aws_iam_role, "path", "/") - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- diff --git a/modules/aws/recipes/metric/alb/main.tf b/modules/aws/recipes/metric/alb/main.tf index fb53d7a..a5ab5cf 100644 --- a/modules/aws/recipes/metric/alb/main.tf +++ b/modules/aws/recipes/metric/alb/main.tf @@ -5,6 +5,9 @@ # Local #-------------------------------------------------------------- locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } url = "https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-cloudwatch-metrics.html" count = length(var.dimensions) > 0 ? length(var.dimensions) : 1 names = length(var.dimensions) > 0 ? flatten([ @@ -15,6 +18,11 @@ locals { }] is_dimensions = length(var.dimensions) > 0 ? true : false } +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # For ActiveConnectionCount # Provides a CloudWatch Metric Alarm resource. @@ -37,7 +45,7 @@ resource "aws_cloudwatch_metric_alarm" "active_connection_count" { unit = "Count" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? var.dimensions[count.index] : null - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # For ClientTLSNegotiationErrorCount @@ -61,7 +69,7 @@ resource "aws_cloudwatch_metric_alarm" "client_tls_negotiation_error_count" { unit = "Count" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? var.dimensions[count.index] : null - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # For ConsumedLCUs @@ -85,7 +93,7 @@ resource "aws_cloudwatch_metric_alarm" "consumed_lcus" { unit = "Count" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? var.dimensions[count.index] : null - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # For HTTPCode_4XX_Count @@ -109,7 +117,7 @@ resource "aws_cloudwatch_metric_alarm" "httpcode_4xx_count" { unit = "Count" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? var.dimensions[count.index] : null - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # For HTTPCode_5XX_Count @@ -133,7 +141,7 @@ resource "aws_cloudwatch_metric_alarm" "httpcode_5xx_count" { unit = "Count" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? var.dimensions[count.index] : null - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # For HTTPCode_ELB_4XX_Count @@ -157,7 +165,7 @@ resource "aws_cloudwatch_metric_alarm" "httpcode_elb_4xx_count" { unit = "Count" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? var.dimensions[count.index] : null - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # For HTTPCode_ELB_5XX_Count @@ -181,7 +189,7 @@ resource "aws_cloudwatch_metric_alarm" "httpcode_elb_5xx_count" { unit = "Count" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? var.dimensions[count.index] : null - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # For TargetResponseTime @@ -204,7 +212,7 @@ resource "aws_cloudwatch_metric_alarm" "target_response_time" { ok_actions = var.ok_actions treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? var.dimensions[count.index] : null - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # For TargetTLSNegotiationErrorCount @@ -228,7 +236,7 @@ resource "aws_cloudwatch_metric_alarm" "target_tls_negotiation_error_count" { unit = "Count" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? var.dimensions[count.index] : null - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # For UnHealthyHostCount @@ -252,5 +260,5 @@ resource "aws_cloudwatch_metric_alarm" "unhealthy_host_count" { unit = "Count" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? var.dimensions[count.index] : null - tags = var.tags + tags = local.tags } diff --git a/modules/aws/recipes/metric/api_gateway/main.tf b/modules/aws/recipes/metric/api_gateway/main.tf index 7275e91..d087972 100644 --- a/modules/aws/recipes/metric/api_gateway/main.tf +++ b/modules/aws/recipes/metric/api_gateway/main.tf @@ -5,6 +5,9 @@ # Local #-------------------------------------------------------------- locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } url = "https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-metrics-and-dimensions.html" count = length(var.dimensions) > 0 ? length(var.dimensions) : 1 names = length(var.dimensions) > 0 ? flatten([ @@ -15,6 +18,11 @@ locals { }] is_dimensions = length(var.dimensions) > 0 ? true : false } +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # For 4XXError # Provides a CloudWatch Metric Alarm resource. @@ -60,7 +68,7 @@ resource "aws_cloudwatch_metric_alarm" "error_4xx" { unit = "Count" } } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # For 5XXError @@ -107,7 +115,7 @@ resource "aws_cloudwatch_metric_alarm" "error_5xx" { unit = "Count" } } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- @@ -131,5 +139,5 @@ resource "aws_cloudwatch_metric_alarm" "latency" { unit = "Milliseconds" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? var.dimensions[count.index] : null - tags = var.tags + tags = local.tags } diff --git a/modules/aws/recipes/metric/cloudfront/main.tf b/modules/aws/recipes/metric/cloudfront/main.tf index 92c54d9..b007d7a 100644 --- a/modules/aws/recipes/metric/cloudfront/main.tf +++ b/modules/aws/recipes/metric/cloudfront/main.tf @@ -5,6 +5,9 @@ # Local #-------------------------------------------------------------- locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } url = "https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/programming-cloudwatch-metrics.html" count = length(var.dimensions) > 0 ? length(var.dimensions) : 1 names = length(var.dimensions) > 0 ? flatten([ @@ -26,6 +29,11 @@ locals { }]) : [{ }] } +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # For 404ErrorRate # Provides a CloudWatch Metric Alarm resource. @@ -47,7 +55,7 @@ resource "aws_cloudwatch_metric_alarm" "error_401_rate" { unit = "Percent" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? local.dimensions[count.index] : null - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # For 403ErrorRate @@ -70,7 +78,7 @@ resource "aws_cloudwatch_metric_alarm" "error_403_rate" { unit = "Percent" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? local.dimensions[count.index] : null - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # For 404ErrorRate @@ -93,7 +101,7 @@ resource "aws_cloudwatch_metric_alarm" "error_404_rate" { unit = "Percent" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? local.dimensions[count.index] : null - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- @@ -117,7 +125,7 @@ resource "aws_cloudwatch_metric_alarm" "error_502_rate" { unit = "Percent" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? local.dimensions[count.index] : null - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # For 503ErrorRate @@ -140,7 +148,7 @@ resource "aws_cloudwatch_metric_alarm" "error_503_rate" { unit = "Percent" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? local.dimensions[count.index] : null - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # For 504ErrorRate @@ -163,7 +171,7 @@ resource "aws_cloudwatch_metric_alarm" "error_504_rate" { unit = "Percent" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? local.dimensions[count.index] : null - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # For CacheHitRate @@ -186,7 +194,7 @@ resource "aws_cloudwatch_metric_alarm" "cache_hit_rate" { unit = "Percent" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? local.dimensions[count.index] : null - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # For OriginLatency @@ -209,7 +217,7 @@ resource "aws_cloudwatch_metric_alarm" "origin_latency" { unit = "Milliseconds" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? local.dimensions[count.index] : null - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- diff --git a/modules/aws/recipes/metric/ec2/main.tf b/modules/aws/recipes/metric/ec2/main.tf index eb6f44c..e93b6cc 100644 --- a/modules/aws/recipes/metric/ec2/main.tf +++ b/modules/aws/recipes/metric/ec2/main.tf @@ -5,6 +5,9 @@ # Local #-------------------------------------------------------------- locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } url = "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/viewing_metrics_with_cloudwatch.html" count = length(var.dimensions) > 0 ? length(var.dimensions) : 1 names = length(var.dimensions) > 0 ? flatten([ @@ -15,6 +18,11 @@ locals { }] is_dimensions = length(var.dimensions) > 0 ? true : false } +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # For CPUUtilization # Provides a CloudWatch Metric Alarm resource. @@ -37,7 +45,7 @@ resource "aws_cloudwatch_metric_alarm" "cpu_utilization" { unit = "Percent" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? var.dimensions[count.index] : null - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # For MetadataNoToken @@ -61,7 +69,7 @@ resource "aws_cloudwatch_metric_alarm" "metadata_no_token" { unit = "Count" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? var.dimensions[count.index] : null - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # For CPUCreditUsage @@ -85,7 +93,7 @@ resource "aws_cloudwatch_metric_alarm" "cpu_credit_usage" { unit = "Count" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? var.dimensions[count.index] : null - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # For StatusCheckFailed @@ -109,5 +117,5 @@ resource "aws_cloudwatch_metric_alarm" "status_check_failed" { unit = "Count" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? var.dimensions[count.index] : null - tags = var.tags + tags = local.tags } diff --git a/modules/aws/recipes/metric/elasticache/main.tf b/modules/aws/recipes/metric/elasticache/main.tf index eca8f94..a7c19c6 100644 --- a/modules/aws/recipes/metric/elasticache/main.tf +++ b/modules/aws/recipes/metric/elasticache/main.tf @@ -5,6 +5,9 @@ # Local #-------------------------------------------------------------- locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } url = "https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/CacheMetrics.Redis.html" count = length(var.dimensions) > 0 ? length(var.dimensions) : 1 names = length(var.dimensions) > 0 ? flatten([ @@ -15,6 +18,11 @@ locals { }] is_dimensions = length(var.dimensions) > 0 ? true : false } +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # For AuthenticationFailures # Provides a CloudWatch Metric Alarm resource. @@ -37,7 +45,7 @@ resource "aws_cloudwatch_metric_alarm" "authentication_failures" { unit = "Count" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? var.dimensions[count.index] : null - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # For CacheHitRate @@ -82,7 +90,7 @@ resource "aws_cloudwatch_metric_alarm" "cache_hit_rate" { stat = "Sum" } } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # For CommandAuthorizationFailures @@ -106,7 +114,7 @@ resource "aws_cloudwatch_metric_alarm" "command_authorization_failures" { unit = "Count" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? var.dimensions[count.index] : null - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # For CurrConnections @@ -130,7 +138,7 @@ resource "aws_cloudwatch_metric_alarm" "curr_connections" { unit = "Count" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? var.dimensions[count.index] : null - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # For DatabaseMemoryUsagePercentage @@ -154,7 +162,7 @@ resource "aws_cloudwatch_metric_alarm" "database_memory_usage_percentage" { unit = "Percent" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? var.dimensions[count.index] : null - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # For EngineCPUUtilization @@ -178,7 +186,7 @@ resource "aws_cloudwatch_metric_alarm" "engine_cpu_utilization" { unit = "Percent" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? var.dimensions[count.index] : null - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # For KeyAuthorizationFailures @@ -202,7 +210,7 @@ resource "aws_cloudwatch_metric_alarm" "key_authorization_failures" { unit = "Count" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? var.dimensions[count.index] : null - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # For NewConnections @@ -226,7 +234,7 @@ resource "aws_cloudwatch_metric_alarm" "new_connections" { unit = "Count" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? var.dimensions[count.index] : null - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # For SwapUsage @@ -250,5 +258,5 @@ resource "aws_cloudwatch_metric_alarm" "swap_usage" { unit = "Bytes" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? var.dimensions[count.index] : null - tags = var.tags + tags = local.tags } diff --git a/modules/aws/recipes/metric/lambda/main.tf b/modules/aws/recipes/metric/lambda/main.tf index 104459e..2569608 100644 --- a/modules/aws/recipes/metric/lambda/main.tf +++ b/modules/aws/recipes/metric/lambda/main.tf @@ -5,6 +5,9 @@ # Local #-------------------------------------------------------------- locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } url = "https://docs.aws.amazon.com/lambda/latest/dg/monitoring-metrics.html" count = length(var.dimensions) > 0 ? length(var.dimensions) : 1 names = length(var.dimensions) > 0 ? flatten([ @@ -15,6 +18,11 @@ locals { }] is_dimensions = length(var.dimensions) > 0 ? true : false } +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # For Concurrent Executions # Provides a CloudWatch Metric Alarm resource. @@ -37,7 +45,7 @@ resource "aws_cloudwatch_metric_alarm" "concurrent_executions" { unit = "Count" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? var.dimensions[count.index] : null - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # For Duration @@ -61,7 +69,7 @@ resource "aws_cloudwatch_metric_alarm" "duration" { unit = "Milliseconds" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? var.dimensions[count.index] : null - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- @@ -86,7 +94,7 @@ resource "aws_cloudwatch_metric_alarm" "error" { unit = "Count" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? var.dimensions[count.index] : null - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # For Throttles @@ -110,5 +118,5 @@ resource "aws_cloudwatch_metric_alarm" "throttles" { unit = "Count" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? var.dimensions[count.index] : null - tags = var.tags + tags = local.tags } diff --git a/modules/aws/recipes/metric/rds/main.tf b/modules/aws/recipes/metric/rds/main.tf index 1c06c20..6de2ab4 100644 --- a/modules/aws/recipes/metric/rds/main.tf +++ b/modules/aws/recipes/metric/rds/main.tf @@ -5,6 +5,9 @@ # Local #-------------------------------------------------------------- locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } url = var.is_aurora ? "https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/Aurora.AuroraMySQL.Monitoring.Metrics.html" : "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/monitoring-cloudwatch.html" count = length(var.dimensions) > 0 ? length(var.dimensions) : 1 names = length(var.dimensions) > 0 ? flatten([ @@ -15,6 +18,10 @@ locals { }] is_dimensions = length(var.dimensions) > 0 ? true : false } +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} #-------------------------------------------------------------- # For CommitLatency @@ -37,7 +44,7 @@ resource "aws_cloudwatch_metric_alarm" "commit_latency" { unit = "Milliseconds" treat_missing_data = "notBreaching" dimensions = var.dimensions[count.index] - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # For CPUCreditBalance @@ -60,7 +67,7 @@ resource "aws_cloudwatch_metric_alarm" "cpu_creadit_balance" { unit = "Count" treat_missing_data = "notBreaching" dimensions = var.dimensions[count.index] - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- @@ -84,7 +91,7 @@ resource "aws_cloudwatch_metric_alarm" "cpu_utilization" { unit = "Percent" treat_missing_data = "notBreaching" dimensions = var.dimensions[count.index] - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- @@ -108,7 +115,7 @@ resource "aws_cloudwatch_metric_alarm" "database_connections" { unit = "Count" treat_missing_data = "notBreaching" dimensions = var.dimensions[count.index] - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- @@ -132,7 +139,7 @@ resource "aws_cloudwatch_metric_alarm" "deadlocks" { unit = "Count/Second" treat_missing_data = "notBreaching" dimensions = var.dimensions[count.index] - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # For DeleteLatency @@ -155,7 +162,7 @@ resource "aws_cloudwatch_metric_alarm" "delete_latency" { unit = "Seconds" treat_missing_data = "notBreaching" dimensions = var.dimensions[count.index] - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # For DiskQueueDepth @@ -178,7 +185,7 @@ resource "aws_cloudwatch_metric_alarm" "disk_queue_depth" { unit = "Count" treat_missing_data = "notBreaching" dimensions = var.dimensions[count.index] - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- @@ -202,7 +209,7 @@ resource "aws_cloudwatch_metric_alarm" "freeable_memory" { unit = "Megabits" treat_missing_data = "notBreaching" dimensions = var.dimensions[count.index] - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- @@ -226,7 +233,7 @@ resource "aws_cloudwatch_metric_alarm" "read_latency" { unit = "Seconds" treat_missing_data = "notBreaching" dimensions = var.dimensions[count.index] - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- @@ -250,5 +257,5 @@ resource "aws_cloudwatch_metric_alarm" "write_latency" { unit = "Seconds" treat_missing_data = "notBreaching" dimensions = var.dimensions[count.index] - tags = var.tags + tags = local.tags } diff --git a/modules/aws/recipes/metric/ses/main.tf b/modules/aws/recipes/metric/ses/main.tf index 2090441..bad4f79 100644 --- a/modules/aws/recipes/metric/ses/main.tf +++ b/modules/aws/recipes/metric/ses/main.tf @@ -5,23 +5,25 @@ # Local #-------------------------------------------------------------- locals { - url = "https://docs.aws.amazon.com/ses/latest/DeveloperGuide/reputationdashboard-cloudwatch-alarm.html" - count = length(var.dimensions) > 0 ? length(var.dimensions) : 1 - names = length(var.dimensions) > 0 ? flatten([ - for r in var.dimensions : { - name = format("%s-", r.InstanceId) - }]) : [{ - name = "" - }] + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } + url = "https://docs.aws.amazon.com/ses/latest/DeveloperGuide/reputationdashboard-cloudwatch-alarm.html" + count = length(var.dimensions) > 0 ? length(var.dimensions) : 1 is_dimensions = length(var.dimensions) > 0 ? true : false } +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # For Reputation.BounceRate # Provides a CloudWatch Metric Alarm resource. #-------------------------------------------------------------- resource "aws_cloudwatch_metric_alarm" "reputation_bouncerate" { count = var.is_enabled && var.threshold.enabled_reputation_bouncerate ? local.count : 0 - alarm_name = "${var.name_prefix}metric-ses-${local.names[count.index].name}reputation-bouncerate" + alarm_name = "${var.name_prefix}metric-ses-reputation-bouncerate" comparison_operator = "GreaterThanOrEqualToThreshold" evaluation_periods = 1 namespace = "AWS/SES" @@ -37,7 +39,7 @@ resource "aws_cloudwatch_metric_alarm" "reputation_bouncerate" { unit = "Percent" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? var.dimensions[count.index] : null - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # For Reputation.ComplaintRate @@ -45,7 +47,7 @@ resource "aws_cloudwatch_metric_alarm" "reputation_bouncerate" { #-------------------------------------------------------------- resource "aws_cloudwatch_metric_alarm" "reputation_complaintrate" { count = var.is_enabled && var.threshold.enabled_reputation_complaintrate ? local.count : 0 - alarm_name = "${var.name_prefix}metric-ses-${local.names[count.index].name}reputation-complaintrate" + alarm_name = "${var.name_prefix}metric-ses-reputation-complaintrate" comparison_operator = "GreaterThanOrEqualToThreshold" evaluation_periods = 1 namespace = "AWS/SES" @@ -61,5 +63,5 @@ resource "aws_cloudwatch_metric_alarm" "reputation_complaintrate" { unit = "Percent" treat_missing_data = "notBreaching" dimensions = local.is_dimensions ? var.dimensions[count.index] : null - tags = var.tags + tags = local.tags } diff --git a/modules/aws/recipes/metric/synthetics_canary/main.tf b/modules/aws/recipes/metric/synthetics_canary/main.tf new file mode 100644 index 0000000..ba9f976 --- /dev/null +++ b/modules/aws/recipes/metric/synthetics_canary/main.tf @@ -0,0 +1,49 @@ +#-------------------------------------------------------------- +# For Synthetics Canary +#-------------------------------------------------------------- +#-------------------------------------------------------------- +# Local +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } + url = "https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries_metrics.html" + count = length(var.dimensions) > 0 ? length(var.dimensions) : 1 + names = length(var.dimensions) > 0 ? flatten([ + for r in var.dimensions : { + name = format("%s-", r.CanaryName) + }]) : [{ + name = "" + }] + is_dimensions = length(var.dimensions) > 0 ? true : false +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + +#-------------------------------------------------------------- +# For SuccessPercent +# Provides a CloudWatch Metric Alarm resource. +#-------------------------------------------------------------- +resource "aws_cloudwatch_metric_alarm" "success_percent" { + count = var.is_enabled && var.threshold.enabled_success_percent ? local.count : 0 + alarm_name = "${var.name_prefix}metric-synthetics-canary-${local.names[count.index].name}success-percent" + comparison_operator = "LessThanOrEqualToThreshold" + evaluation_periods = 1 + namespace = "CloudWatchSynthetics" + metric_name = "SuccessPercent" + period = var.period + statistic = "Average" + threshold = var.threshold.success_percent + actions_enabled = true + alarm_actions = var.alarm_actions + alarm_description = "This is an alarm to check for <${local.url}|Synthetics Canary success percent>(<= ${var.threshold.success_percent}%)." + insufficient_data_actions = [] + ok_actions = var.ok_actions + unit = "Percent" + treat_missing_data = "notBreaching" + dimensions = local.is_dimensions ? var.dimensions[count.index] : null + tags = local.tags +} diff --git a/modules/aws/recipes/metric/synthetics_canary/outputs.tf b/modules/aws/recipes/metric/synthetics_canary/outputs.tf new file mode 100644 index 0000000..e69de29 diff --git a/modules/aws/recipes/metric/synthetics_canary/variables.tf b/modules/aws/recipes/metric/synthetics_canary/variables.tf new file mode 100644 index 0000000..6cc18c5 --- /dev/null +++ b/modules/aws/recipes/metric/synthetics_canary/variables.tf @@ -0,0 +1,48 @@ +#-------------------------------------------------------------- +# module variables +#-------------------------------------------------------------- +variable "is_enabled" { + type = bool + description = "(Optional) A boolean flag to enable/disable settings of EC2. Defaults true." + default = true +} +variable "period" { + type = number + description = "(Optional) The period in seconds over which the specified statistic is applied." + default = 300 +} +variable "threshold" { + type = object({ + # SuccessPercent threshold (unit=Percent) + enabled_success_percent = bool + success_percent = number + } + ) + description = "(Optional) Set the threshold for each Metric in Synthetics." + default = { + enabled_success_percent = true + success_percent = 99 + } +} +variable "dimensions" { + type = list(map(any)) + description = "(Required) The dimensions for the alarm's associated metric. For the list of available dimensions see the AWS documentation here." +} +variable "name_prefix" { + type = string + description = "(Required) Center for Internet Security CloudWatch Filter/Alarm name prefix." +} +variable "alarm_actions" { + type = list(string) + description = "(Required) The list of actions to execute when this alarm transitions into an ALARM state from any other state. Each action is specified as an Amazon Resource Name (ARN)." +} +variable "ok_actions" { + type = list(string) + description = "(Optional) The list of actions to execute when this alarm transitions into an OK state from any other state. Each action is specified as an Amazon Resource Name (ARN)." + default = null +} +variable "tags" { + type = map(any) + description = "(Optional) Key-value map of resource tags." + default = null +} diff --git a/modules/aws/recipes/metric/synthetics_canary/versions.tf b/modules/aws/recipes/metric/synthetics_canary/versions.tf new file mode 100644 index 0000000..11294d7 --- /dev/null +++ b/modules/aws/recipes/metric/synthetics_canary/versions.tf @@ -0,0 +1,12 @@ +#-------------------------------------------------------------- +# Terraform Provider +#-------------------------------------------------------------- +terraform { + required_version = ">=0.14" + required_providers { + aws = { + source = "hashicorp/aws" + version = ">=4.0.0" + } + } +} diff --git a/modules/aws/recipes/resource_groups/main.tf b/modules/aws/recipes/resource_groups/main.tf index cdb3d8b..522ab75 100644 --- a/modules/aws/recipes/resource_groups/main.tf +++ b/modules/aws/recipes/resource_groups/main.tf @@ -1,3 +1,16 @@ +#-------------------------------------------------------------- +# Locals +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Provides a Resource Group. #-------------------------------------------------------------- @@ -11,5 +24,5 @@ resource "aws_resourcegroups_group" "this" { type = lookup(resource_query.value, "type", null) } } - tags = var.tags + tags = local.tags } diff --git a/modules/aws/recipes/s3/bucket/cloudtrail-v4/main.tf b/modules/aws/recipes/s3/bucket/cloudtrail-v4/main.tf new file mode 100644 index 0000000..8868006 --- /dev/null +++ b/modules/aws/recipes/s3/bucket/cloudtrail-v4/main.tf @@ -0,0 +1,416 @@ +#-------------------------------------------------------------- +# Locals +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } + name = var.is_random_name_suffix ? "${var.bucket}-${random_id.this.dec}" : var.bucket +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + +#-------------------------------------------------------------- +# create random id for s3 bukect name +#-------------------------------------------------------------- +resource "random_id" "this" { + byte_length = 4 +} +#-------------------------------------------------------------- +# Provides a S3 bucket resource. +#-------------------------------------------------------------- +#tfsec:ignore:AWS002 tfsec:ignore:AWS017 tfsec:ignore:AWS077 +resource "aws_s3_bucket" "this" { + bucket = local.name + force_destroy = var.force_destroy + dynamic "object_lock_configuration" { + for_each = var.object_lock_configuration + content { + object_lock_enabled = lookup(object_lock_configuration.value, "object_lock_enabled", null) + dynamic "rule" { + for_each = lookup(object_lock_configuration.value, "rule", []) + content { + dynamic "default_retention" { + for_each = lookup(rule.value, "default_retention", []) + content { + mode = lookup(default_retention.value, "mode", null) + days = lookup(default_retention.value, "days", null) + years = lookup(default_retention.value, "years", null) + } + } + } + } + } + } + tags = local.tags +} +#-------------------------------------------------------------- +# Provides a resource for controlling versioning on an S3 bucket. Deleting this resource will suspend versioning on the associated S3 bucket. For more information, see How S3 versioning works. +#-------------------------------------------------------------- +resource "aws_s3_bucket_acl" "this" { + count = var.aws_s3_bucket_acl == null ? 0 : 1 + acl = lookup(var.aws_s3_bucket_acl, "acl") + dynamic "access_control_policy" { + for_each = lookup(var.aws_s3_bucket_acl, "access_control_policy", []) + content { + dynamic "grant" { + for_each = lookup(access_control_policy.value, "grant", []) + content { + dynamic "grantee" { + for_each = lookup(grant.value, "grantee", []) + content { + email_address = lookup(grantee.value, "email_address", null) + id = lookup(grantee.value, "id", null) + type = lookup(grantee.value, "type", null) + uri = lookup(grantee.value, "uri", null) + } + } + permission = lookup(grant.value, "permission", null) + } + } + dynamic "owner" { + for_each = lookup(access_control_policy.value, "owner", []) + content { + id = lookup(owner.value, "id", null) + display_name = lookup(owner.value, "display_name", null) + } + } + } + } + bucket = aws_s3_bucket.this.id + expected_bucket_owner = lookup(var.aws_s3_bucket_acl, "expected_bucket_owner", null) + +} + +#-------------------------------------------------------------- +# Provides a resource for controlling versioning on an S3 bucket. Deleting this resource will suspend versioning on the associated S3 bucket. For more information, see How S3 versioning works. +#-------------------------------------------------------------- +resource "aws_s3_bucket_versioning" "this" { + count = var.aws_s3_bucket_versioning == null ? 0 : 1 + bucket = aws_s3_bucket.this.id + dynamic "versioning_configuration" { + for_each = lookup(var.aws_s3_bucket_versioning, "versioning_configuration", []) + content { + status = lookup(versioning_configuration.value, "status", null) + mfa_delete = lookup(versioning_configuration.value, "mfa_delete", null) + } + } +} + +#-------------------------------------------------------------- +# Provides a S3 bucket server-side encryption configuration resource. +#-------------------------------------------------------------- +resource "aws_s3_bucket_server_side_encryption_configuration" "this" { + count = var.aws_s3_bucket_server_side_encryption_configuration == null ? 0 : 1 + bucket = aws_s3_bucket.this.bucket + + dynamic "rule" { + for_each = lookup(var.aws_s3_bucket_server_side_encryption_configuration, "rule", []) + content { + dynamic "apply_server_side_encryption_by_default" { + for_each = lookup(rule.value, "apply_server_side_encryption_by_default", []) + content { + sse_algorithm = lookup(apply_server_side_encryption_by_default.value, "sse_algorithm", null) + kms_master_key_id = lookup(apply_server_side_encryption_by_default.value, "kms_master_key_id", null) + } + } + bucket_key_enabled = lookup(rule.value, "bucket_key_enabled", null) + } + } +} + +#-------------------------------------------------------------- +# Provides a S3 bucket logging resource. +#-------------------------------------------------------------- +resource "aws_s3_bucket_logging" "this" { + count = var.aws_s3_bucket_logging == null ? 0 : 1 + bucket = aws_s3_bucket.this.bucket + expected_bucket_owner = lookup(var.aws_s3_bucket_logging, "expected_bucket_owner", null) + target_bucket = lookup(var.aws_s3_bucket_logging, "target_bucket", null) + target_prefix = lookup(var.aws_s3_bucket_logging, "target_prefix", null) + dynamic "target_grant" { + for_each = lookup(var.aws_s3_bucket_logging, "target_grant", []) + content { + dynamic "grantee" { + for_each = lookup(target_grant.value, "grantee", []) + content { + email_address = lookup(grantee.value, "email_address", null) + id = lookup(grantee.value, "id", null) + type = lookup(grantee.value, "type", null) + uri = lookup(grantee.value, "uri", null) + } + } + permission = lookup(target_grant.value, "permission", null) + } + } +} +#-------------------------------------------------------------- +# Provides an independent configuration resource for S3 bucket lifecycle configuration. +#-------------------------------------------------------------- +resource "aws_s3_bucket_lifecycle_configuration" "this" { + count = var.aws_s3_bucket_lifecycle_configuration == null ? 0 : 1 + bucket = aws_s3_bucket.this.bucket + expected_bucket_owner = lookup(var.aws_s3_bucket_lifecycle_configuration, "expected_bucket_owner", null) + dynamic "rule" { + for_each = lookup(var.aws_s3_bucket_lifecycle_configuration, "rule", []) + content { + dynamic "abort_incomplete_multipart_upload" { + for_each = lookup(rule.value, "abort_incomplete_multipart_upload", []) + content { + days_after_initiation = lookup(abort_incomplete_multipart_upload.value, "days_after_initiation", null) + } + } + dynamic "expiration" { + for_each = lookup(rule.value, "expiration", []) + content { + date = lookup(expiration.value, "date", null) + days = lookup(expiration.value, "days", null) + expired_object_delete_marker = lookup(expiration.value, "expired_object_delete_marker", null) + } + } + dynamic "filter" { + for_each = lookup(rule.value, "filter", []) + content { + dynamic "and" { + for_each = lookup(filter.value, "and", []) + content { + object_size_greater_than = lookup(and.value, "object_size_greater_than", null) + object_size_less_than = lookup(and.value, "object_size_less_than", null) + prefix = lookup(and.value, "prefix", null) + tags = lookup(and.value, "tags", null) + } + } + object_size_greater_than = lookup(filter.value, "object_size_greater_than", null) + object_size_less_than = lookup(filter.value, "object_size_less_than", null) + prefix = lookup(filter.value, "prefix", null) + dynamic "tag" { + for_each = lookup(filter.value, "tag", []) + content { + key = lookup(tag.value, "key", null) + value = lookup(tag.value, "value", null) + } + } + } + } + id = lookup(rule.value, "id") + dynamic "noncurrent_version_expiration" { + for_each = lookup(rule.value, "noncurrent_version_expiration", []) + content { + newer_noncurrent_versions = lookup(noncurrent_version_expiration.value, "newer_noncurrent_versions", null) + noncurrent_days = lookup(noncurrent_version_expiration.value, "noncurrent_days", null) + } + } + dynamic "noncurrent_version_transition" { + for_each = lookup(rule.value, "noncurrent_version_transition", []) + content { + newer_noncurrent_versions = lookup(noncurrent_version_transition.value, "newer_noncurrent_versions", null) + noncurrent_days = lookup(noncurrent_version_transition.value, "noncurrent_days", null) + storage_class = lookup(noncurrent_version_transition.value, "storage_class", null) + } + } + prefix = lookup(rule.value, "prefix", null) + status = lookup(rule.value, "status", null) + dynamic "transition" { + for_each = lookup(rule.value, "transition", []) + content { + date = lookup(transition.value, "date", null) + days = lookup(transition.value, "days", null) + storage_class = lookup(transition.value, "storage_class", null) + } + } + } + } +} + +#-------------------------------------------------------------- +# Provides an independent configuration resource for S3 bucket replication configuration. +#-------------------------------------------------------------- +resource "aws_s3_bucket_replication_configuration" "this" { + count = var.aws_s3_bucket_replication_configuration == null ? 0 : 1 + bucket = aws_s3_bucket.this.id + role = var.s3_replication_configuration_role_arn + + dynamic "rule" { + for_each = lookup(var.aws_s3_bucket_replication_configuration, "rule", []) + content { + dynamic "delete_marker_replication" { + for_each = lookup(rule.value, "delete_marker_replication", []) + content { + status = lookup(delete_marker_replication.value, "status", null) + } + } + dynamic "destination" { + for_each = lookup(rule.value, "destination", []) + content { + dynamic "access_control_translation" { + for_each = lookup(destination.value, "access_control_translation", []) + content { + owner = lookup(access_control_translation.value, "owner", null) + } + } + account = lookup(destination.value, "account", null) + bucket = lookup(destination.value, "bucket", null) + dynamic "encryption_configuration" { + for_each = lookup(destination.value, "encryption_configuration", []) + content { + replica_kms_key_id = lookup(encryption_configuration.value, "replica_kms_key_id", null) + } + } + dynamic "metrics" { + for_each = lookup(destination.value, "metrics", []) + content { + dynamic "event_threshold" { + for_each = lookup(metrics.value, "event_threshold", []) + content { + minutes = lookup(event_threshold.value, "minutes", null) + } + } + status = lookup(metrics.value, "status", null) + } + } + + dynamic "replication_time" { + for_each = lookup(destination.value, "replication_time", []) + content { + status = lookup(replication_time.value, "status", null) + dynamic "time" { + for_each = lookup(replication_time.value, "time", []) + content { + minutes = lookup(time.value, "minutes", null) + } + } + } + } + storage_class = lookup(destination.value, "storage_class", null) + } + } + dynamic "existing_object_replication" { + for_each = lookup(rule.value, "existing_object_replication", []) + content { + status = lookup(existing_object_replication.value, "status", null) + } + } + dynamic "filter" { + for_each = lookup(rule.value, "filter", []) + content { + dynamic "and" { + for_each = lookup(filter.value, "and", []) + content { + prefix = lookup(and.value, "prefix", null) + tags = lookup(and.value, "tags", null) + } + } + prefix = lookup(filter.value, "prefix", null) + dynamic "tag" { + for_each = lookup(filter.value, "tag", []) + content { + key = lookup(tag.value, "key", null) + value = lookup(tag.value, "value", null) + } + } + } + } + id = lookup(rule.value, "id", null) + prefix = lookup(rule.value, "prefix", null) + priority = lookup(rule.value, "priority", null) + dynamic "source_selection_criteria" { + for_each = lookup(rule.value, "source_selection_criteria", []) + content { + dynamic "replica_modifications" { + for_each = lookup(source_selection_criteria.value, "replica_modifications", null) + content { + status = lookup(replica_modifications.value, "status", null) + } + } + dynamic "sse_kms_encrypted_objects" { + for_each = lookup(source_selection_criteria.value, "sse_kms_encrypted_objects", null) + content { + status = lookup(sse_kms_encrypted_objects.value, "status", null) + } + } + } + } + status = lookup(rule.value, "status", null) + } + } + depends_on = [aws_s3_bucket_versioning.this] +} +#-------------------------------------------------------------- +# Manages S3 bucket-level Public Access Block configuration. For more information about these settings, see the AWS S3 Block Public Access documentation. +#-------------------------------------------------------------- +resource "aws_s3_bucket_public_access_block" "this" { + bucket = aws_s3_bucket.this.id + block_public_acls = true + block_public_policy = true + ignore_public_acls = true + restrict_public_buckets = true +} + +#-------------------------------------------------------------- +# Provides IAM Policy document. +#-------------------------------------------------------------- +data "aws_iam_policy_document" "this" { + version = "2012-10-17" + statement { + sid = "AWSCloudTrailAclCheck" + effect = "Allow" + principals { + type = "Service" + identifiers = ["cloudtrail.amazonaws.com"] + } + actions = [ + "s3:GetBucketAcl" + ] + resources = [ + aws_s3_bucket.this.arn + ] + } + statement { + sid = "AWSCloudTrailWrite" + effect = "Allow" + principals { + type = "Service" + identifiers = ["cloudtrail.amazonaws.com"] + } + actions = [ + "s3:PutObject" + ] + resources = [ + "${aws_s3_bucket.this.arn}/AWSLogs/${var.account_id}/*" + ] + condition { + test = "StringEquals" + variable = "s3:x-amz-acl" + values = ["bucket-owner-full-control"] + } + } + statement { + sid = "AllowSSLRequestsOnly" + effect = "Deny" + principals { + type = "*" + identifiers = ["*"] + } + actions = [ + "s3:*" + ] + resources = [ + aws_s3_bucket.this.arn, + "${aws_s3_bucket.this.arn}/*" + ] + condition { + test = "Bool" + variable = "aws:SecureTransport" + values = ["false"] + } + } +} +#-------------------------------------------------------------- +# Attaches a policy to an S3 bucket resource. +#-------------------------------------------------------------- +resource "aws_s3_bucket_policy" "this" { + bucket = aws_s3_bucket.this.id + policy = data.aws_iam_policy_document.this.json +} diff --git a/modules/aws/recipes/s3/bucket/cloudtrail-v4/outputs.tf b/modules/aws/recipes/s3/bucket/cloudtrail-v4/outputs.tf new file mode 100644 index 0000000..a66ee9e --- /dev/null +++ b/modules/aws/recipes/s3/bucket/cloudtrail-v4/outputs.tf @@ -0,0 +1,12 @@ +output "id" { + description = "The name of the bucket." + value = aws_s3_bucket.this.id +} +output "arn" { + description = "The ARN of the bucket. Will be of format arn:aws:s3:::bucketname." + value = aws_s3_bucket.this.arn +} +output "bucket" { + description = "The name of the bucket." + value = aws_s3_bucket.this.bucket +} diff --git a/modules/aws/recipes/s3/bucket/cloudtrail-v4/variables.tf b/modules/aws/recipes/s3/bucket/cloudtrail-v4/variables.tf new file mode 100644 index 0000000..8d04956 --- /dev/null +++ b/modules/aws/recipes/s3/bucket/cloudtrail-v4/variables.tf @@ -0,0 +1,129 @@ +#-------------------------------------------------------------- +# module variables +#-------------------------------------------------------------- +variable "is_random_name_suffix" { + type = bool + description = "(Optional) The random name suffix of the bucket." + default = false +} +variable "account_id" { + type = string + description = "(Required) AWS account ID for member account." +} +variable "aws_s3_bucket" { + type = object( + { + # (Optional, Forces new resource) The name of the bucket. If omitted, Terraform will assign a random, unique name. Must be lowercase and less than or equal to 63 characters in length. A full list of bucket naming rules may be found here. + bucket = string + # (Optional, Default:false) A boolean that indicates all objects (including any locked objects) should be deleted from the bucket so that the bucket can be destroyed without error. These objects are not recoverable. + force_destroy = bool + # (Optional) A configuration of S3 object locking. See Object Lock Configuration below. + object_lock_configuration = list(object( + { + object_lock_enabled = string + } + )) + } + ) +} +variable "aws_s3_bucket_acl" { + type = object( + { + acl = string + access_control_policy = list(any) + expected_bucket_owner = string + + }) + description = "(Optional) Provides an S3 bucket ACL resource." + default = { + acl = "log-delivery-write" + access_control_policy = [] + expected_bucket_owner = null + } +} +variable "aws_s3_bucket_versioning" { + type = object( + { + versioning_configuration = list(any) + }) + description = "(Optional) Configuration block for the versioning parameters." + default = { + versioning_configuration = [ + { + status = "Disabled" + mfa_delete = "Disabled" + } + ] + } +} +variable "aws_s3_bucket_server_side_encryption_configuration" { + type = object( + { + # (Optional, Forces new resource) The account ID of the expected bucket owner. + expected_bucket_owner = string + # (Required) Set of server-side encryption configuration rules. documented below. Currently, only a single rule is supported. + rule = list(any) + } + ) + description = "(Optional) Provides a S3 bucket server-side encryption configuration resource." + default = { + expected_bucket_owner = null + + rule = [ + { + apply_server_side_encryption_by_default = [ + { + sse_algorithm = "AES256" + kms_master_key_id = null + } + ] + } + ] + } +} +variable "aws_s3_bucket_logging" { + type = object( + { + # (Optional, Forces new resource) The account ID of the expected bucket owner. + expected_bucket_owner = string + # (Required) The bucket where you want Amazon S3 to store server access logs. + target_bucket = string + # (Required) A prefix for all log object keys. + target_prefix = string + # (Optional) Set of configuration blocks with information for granting permissions documented below. + target_grant = list(any) + }) + description = "(Optional) Provides a S3 bucket logging resource." + default = null +} +variable "aws_s3_bucket_lifecycle_configuration" { + type = object( + { + # (Optional) The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error. + expected_bucket_owner = string + # (Required) List of configuration blocks describing the rules managing the replication documented below. + rule = list(object( + { + + abort_incomplete_multipart_upload_days = list(any) + expiration = list(any) + filter = list(any) + id = string + noncurrent_version_expiration = list(any) + noncurrent_version_transition = list(any) + prefix = string + status = string + transition = list(any) + } + ) + ) + } + ) + description = "(Optional) Provides an independent configuration resource for S3 bucket lifecycle configuration." + default = null +} +variable "tags" { + type = map(any) + description = "(Optional) A mapping of tags to assign to the bucket." + default = null +} diff --git a/modules/aws/recipes/s3/bucket/cloudtrail-v4/versions.tf b/modules/aws/recipes/s3/bucket/cloudtrail-v4/versions.tf new file mode 100644 index 0000000..11294d7 --- /dev/null +++ b/modules/aws/recipes/s3/bucket/cloudtrail-v4/versions.tf @@ -0,0 +1,12 @@ +#-------------------------------------------------------------- +# Terraform Provider +#-------------------------------------------------------------- +terraform { + required_version = ">=0.14" + required_providers { + aws = { + source = "hashicorp/aws" + version = ">=4.0.0" + } + } +} diff --git a/modules/aws/recipes/s3/bucket/cloudtrail/main.tf b/modules/aws/recipes/s3/bucket/cloudtrail/main.tf index 3b4c9df..38be4ae 100644 --- a/modules/aws/recipes/s3/bucket/cloudtrail/main.tf +++ b/modules/aws/recipes/s3/bucket/cloudtrail/main.tf @@ -2,8 +2,16 @@ # Locals #-------------------------------------------------------------- locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } name = var.is_random_name_suffix ? "${var.bucket}-${random_id.this.dec}" : var.bucket } +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # create random id for s3 bukect name #-------------------------------------------------------------- @@ -18,7 +26,7 @@ resource "aws_s3_bucket" "this" { bucket = local.name # bucket_prefix = var.bucket_prefix acl = var.acl - tags = var.tags + tags = local.tags force_destroy = var.force_destroy # dynamic "website" { diff --git a/modules/aws/recipes/s3/bucket/log-v4/main.tf b/modules/aws/recipes/s3/bucket/log-v4/main.tf new file mode 100644 index 0000000..870188e --- /dev/null +++ b/modules/aws/recipes/s3/bucket/log-v4/main.tf @@ -0,0 +1,351 @@ +#-------------------------------------------------------------- +# Locals +#-------------------------------------------------------------- +locals { + name = var.is_random_name_suffix ? "${var.aws_s3_bucket.bucket}-${random_id.this.dec}" : var.aws_s3_bucket.bucket + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + +#-------------------------------------------------------------- +# create random id for s3 bukect name +#-------------------------------------------------------------- +resource "random_id" "this" { + byte_length = 4 +} +#-------------------------------------------------------------- +# Provides a S3 bucket resource. +#-------------------------------------------------------------- +#tfsec:ignore:AWS002 tfsec:ignore:AWS017 tfsec:ignore:AWS077 +resource "aws_s3_bucket" "this" { + bucket = local.name + force_destroy = lookup(var.aws_s3_bucket, "force_destroy", null) + + dynamic "object_lock_configuration" { + for_each = lookup(var.aws_s3_bucket, "object_lock_configuration", []) + content { + object_lock_enabled = lookup(object_lock_configuration.value, "object_lock_enabled", null) + dynamic "rule" { + for_each = lookup(object_lock_configuration.value, "rule", []) + content { + dynamic "default_retention" { + for_each = lookup(rule.value, "default_retention", []) + content { + mode = lookup(default_retention.value, "mode", null) + days = lookup(default_retention.value, "days", null) + years = lookup(default_retention.value, "years", null) + } + } + } + } + } + } + tags = local.tags +} +#-------------------------------------------------------------- +# Provides a resource for controlling versioning on an S3 bucket. Deleting this resource will suspend versioning on the associated S3 bucket. For more information, see How S3 versioning works. +#-------------------------------------------------------------- +resource "aws_s3_bucket_acl" "this" { + count = var.aws_s3_bucket_acl == null ? 0 : 1 + acl = lookup(var.aws_s3_bucket_acl, "acl") + dynamic "access_control_policy" { + for_each = lookup(var.aws_s3_bucket_acl, "access_control_policy", []) + content { + dynamic "grant" { + for_each = lookup(access_control_policy.value, "grant", []) + content { + dynamic "grantee" { + for_each = lookup(grant.value, "grantee", []) + content { + email_address = lookup(grantee.value, "email_address", null) + id = lookup(grantee.value, "id", null) + type = lookup(grantee.value, "type", null) + uri = lookup(grantee.value, "uri", null) + } + } + permission = lookup(grant.value, "permission", null) + } + } + dynamic "owner" { + for_each = lookup(access_control_policy.value, "owner", []) + content { + id = lookup(owner.value, "id", null) + display_name = lookup(owner.value, "display_name", null) + } + } + } + } + bucket = aws_s3_bucket.this.id + expected_bucket_owner = lookup(var.aws_s3_bucket_acl, "expected_bucket_owner", null) + +} + +#-------------------------------------------------------------- +# Provides a resource for controlling versioning on an S3 bucket. Deleting this resource will suspend versioning on the associated S3 bucket. For more information, see How S3 versioning works. +#-------------------------------------------------------------- +resource "aws_s3_bucket_versioning" "this" { + count = var.aws_s3_bucket_versioning == null ? 0 : 1 + bucket = aws_s3_bucket.this.id + dynamic "versioning_configuration" { + for_each = lookup(var.aws_s3_bucket_versioning, "versioning_configuration", []) + content { + status = lookup(versioning_configuration.value, "status", null) + mfa_delete = lookup(versioning_configuration.value, "mfa_delete", null) + } + } +} + +#-------------------------------------------------------------- +# Provides a S3 bucket server-side encryption configuration resource. +#-------------------------------------------------------------- +resource "aws_s3_bucket_server_side_encryption_configuration" "this" { + count = var.aws_s3_bucket_server_side_encryption_configuration == null ? 0 : 1 + bucket = aws_s3_bucket.this.bucket + + dynamic "rule" { + for_each = lookup(var.aws_s3_bucket_server_side_encryption_configuration, "rule", []) + content { + dynamic "apply_server_side_encryption_by_default" { + for_each = lookup(rule.value, "apply_server_side_encryption_by_default", []) + content { + sse_algorithm = lookup(apply_server_side_encryption_by_default.value, "sse_algorithm", null) + kms_master_key_id = lookup(apply_server_side_encryption_by_default.value, "kms_master_key_id", null) + } + } + bucket_key_enabled = lookup(rule.value, "bucket_key_enabled", null) + } + } +} + +#-------------------------------------------------------------- +# Provides a S3 bucket logging resource. +#-------------------------------------------------------------- +resource "aws_s3_bucket_logging" "this" { + count = var.aws_s3_bucket_logging == null ? 0 : 1 + bucket = aws_s3_bucket.this.bucket + expected_bucket_owner = lookup(var.aws_s3_bucket_logging, "expected_bucket_owner", null) + target_bucket = lookup(var.aws_s3_bucket_logging, "target_bucket", null) + target_prefix = lookup(var.aws_s3_bucket_logging, "target_prefix", null) + dynamic "target_grant" { + for_each = lookup(var.aws_s3_bucket_logging, "target_grant", []) + content { + dynamic "grantee" { + for_each = lookup(target_grant.value, "grantee", []) + content { + email_address = lookup(grantee.value, "email_address", null) + id = lookup(grantee.value, "id", null) + type = lookup(grantee.value, "type", null) + uri = lookup(grantee.value, "uri", null) + } + } + permission = lookup(target_grant.value, "permission", null) + } + } +} +#-------------------------------------------------------------- +# Provides an independent configuration resource for S3 bucket lifecycle configuration. +#-------------------------------------------------------------- +resource "aws_s3_bucket_lifecycle_configuration" "this" { + count = var.aws_s3_bucket_lifecycle_configuration == null ? 0 : 1 + bucket = aws_s3_bucket.this.bucket + expected_bucket_owner = lookup(var.aws_s3_bucket_lifecycle_configuration, "expected_bucket_owner", null) + dynamic "rule" { + for_each = lookup(var.aws_s3_bucket_lifecycle_configuration, "rule", []) + content { + dynamic "abort_incomplete_multipart_upload" { + for_each = lookup(rule.value, "abort_incomplete_multipart_upload", []) + content { + days_after_initiation = lookup(abort_incomplete_multipart_upload.value, "days_after_initiation", null) + } + } + dynamic "expiration" { + for_each = lookup(rule.value, "expiration", []) + content { + date = lookup(expiration.value, "date", null) + days = lookup(expiration.value, "days", null) + expired_object_delete_marker = lookup(expiration.value, "expired_object_delete_marker", null) + } + } + dynamic "filter" { + for_each = lookup(rule.value, "filter", []) + content { + dynamic "and" { + for_each = lookup(filter.value, "and", []) + content { + object_size_greater_than = lookup(and.value, "object_size_greater_than", null) + object_size_less_than = lookup(and.value, "object_size_less_than", null) + prefix = lookup(and.value, "prefix", null) + tags = lookup(and.value, "tags", null) + } + } + object_size_greater_than = lookup(filter.value, "object_size_greater_than", null) + object_size_less_than = lookup(filter.value, "object_size_less_than", null) + prefix = lookup(filter.value, "prefix", null) + dynamic "tag" { + for_each = lookup(filter.value, "tag", []) + content { + key = lookup(tag.value, "key", null) + value = lookup(tag.value, "value", null) + } + } + } + } + id = lookup(rule.value, "id") + dynamic "noncurrent_version_expiration" { + for_each = lookup(rule.value, "noncurrent_version_expiration", []) + content { + newer_noncurrent_versions = lookup(noncurrent_version_expiration.value, "newer_noncurrent_versions", null) + noncurrent_days = lookup(noncurrent_version_expiration.value, "noncurrent_days", null) + } + } + dynamic "noncurrent_version_transition" { + for_each = lookup(rule.value, "noncurrent_version_transition", []) + content { + newer_noncurrent_versions = lookup(noncurrent_version_transition.value, "newer_noncurrent_versions", null) + noncurrent_days = lookup(noncurrent_version_transition.value, "noncurrent_days", null) + storage_class = lookup(noncurrent_version_transition.value, "storage_class", null) + } + } + prefix = lookup(rule.value, "prefix", null) + status = lookup(rule.value, "status", null) + dynamic "transition" { + for_each = lookup(rule.value, "transition", []) + content { + date = lookup(transition.value, "date", null) + days = lookup(transition.value, "days", null) + storage_class = lookup(transition.value, "storage_class", null) + } + } + } + } +} + +#-------------------------------------------------------------- +# Provides an independent configuration resource for S3 bucket replication configuration. +#-------------------------------------------------------------- +resource "aws_s3_bucket_replication_configuration" "this" { + count = var.aws_s3_bucket_replication_configuration == null ? 0 : 1 + bucket = aws_s3_bucket.this.id + role = var.s3_replication_configuration_role_arn + + dynamic "rule" { + for_each = lookup(var.aws_s3_bucket_replication_configuration, "rule", []) + content { + dynamic "delete_marker_replication" { + for_each = lookup(rule.value, "delete_marker_replication", []) + content { + status = lookup(delete_marker_replication.value, "status", null) + } + } + dynamic "destination" { + for_each = lookup(rule.value, "destination", []) + content { + dynamic "access_control_translation" { + for_each = lookup(destination.value, "access_control_translation", []) + content { + owner = lookup(access_control_translation.value, "owner", null) + } + } + account = lookup(destination.value, "account", null) + bucket = lookup(destination.value, "bucket", null) + dynamic "encryption_configuration" { + for_each = lookup(destination.value, "encryption_configuration", []) + content { + replica_kms_key_id = lookup(encryption_configuration.value, "replica_kms_key_id", null) + } + } + dynamic "metrics" { + for_each = lookup(destination.value, "metrics", []) + content { + dynamic "event_threshold" { + for_each = lookup(metrics.value, "event_threshold", []) + content { + minutes = lookup(event_threshold.value, "minutes", null) + } + } + status = lookup(metrics.value, "status", null) + } + } + + dynamic "replication_time" { + for_each = lookup(destination.value, "replication_time", []) + content { + status = lookup(replication_time.value, "status", null) + dynamic "time" { + for_each = lookup(replication_time.value, "time", []) + content { + minutes = lookup(time.value, "minutes", null) + } + } + } + } + storage_class = lookup(destination.value, "storage_class", null) + } + } + dynamic "existing_object_replication" { + for_each = lookup(rule.value, "existing_object_replication", []) + content { + status = lookup(existing_object_replication.value, "status", null) + } + } + dynamic "filter" { + for_each = lookup(rule.value, "filter", []) + content { + dynamic "and" { + for_each = lookup(filter.value, "and", []) + content { + prefix = lookup(and.value, "prefix", null) + tags = lookup(and.value, "tags", null) + } + } + prefix = lookup(filter.value, "prefix", null) + dynamic "tag" { + for_each = lookup(filter.value, "tag", []) + content { + key = lookup(tag.value, "key", null) + value = lookup(tag.value, "value", null) + } + } + } + } + id = lookup(rule.value, "id", null) + prefix = lookup(rule.value, "prefix", null) + priority = lookup(rule.value, "priority", null) + dynamic "source_selection_criteria" { + for_each = lookup(rule.value, "source_selection_criteria", []) + content { + dynamic "replica_modifications" { + for_each = lookup(source_selection_criteria.value, "replica_modifications", null) + content { + status = lookup(replica_modifications.value, "status", null) + } + } + dynamic "sse_kms_encrypted_objects" { + for_each = lookup(source_selection_criteria.value, "sse_kms_encrypted_objects", null) + content { + status = lookup(sse_kms_encrypted_objects.value, "status", null) + } + } + } + } + status = lookup(rule.value, "status", null) + } + } + depends_on = [aws_s3_bucket_versioning.this] +} + +#-------------------------------------------------------------- +# Manages S3 bucket-level Public Access Block configuration. For more information about these settings, see the AWS S3 Block Public Access documentation. +#-------------------------------------------------------------- +resource "aws_s3_bucket_public_access_block" "this" { + bucket = aws_s3_bucket.this.id + block_public_acls = true + block_public_policy = true + ignore_public_acls = true + restrict_public_buckets = true +} diff --git a/modules/aws/recipes/s3/bucket/log-v4/outputs.tf b/modules/aws/recipes/s3/bucket/log-v4/outputs.tf new file mode 100644 index 0000000..a66ee9e --- /dev/null +++ b/modules/aws/recipes/s3/bucket/log-v4/outputs.tf @@ -0,0 +1,12 @@ +output "id" { + description = "The name of the bucket." + value = aws_s3_bucket.this.id +} +output "arn" { + description = "The ARN of the bucket. Will be of format arn:aws:s3:::bucketname." + value = aws_s3_bucket.this.arn +} +output "bucket" { + description = "The name of the bucket." + value = aws_s3_bucket.this.bucket +} diff --git a/modules/aws/recipes/s3/bucket/log-v4/variables.tf b/modules/aws/recipes/s3/bucket/log-v4/variables.tf new file mode 100644 index 0000000..852430b --- /dev/null +++ b/modules/aws/recipes/s3/bucket/log-v4/variables.tf @@ -0,0 +1,373 @@ +#-------------------------------------------------------------- +# module variables +#-------------------------------------------------------------- +variable "is_random_name_suffix" { + type = bool + description = "(Optional) The random name suffix of the bucket." + default = false +} +variable "aws_s3_bucket" { + type = object( + { + # (Optional, Forces new resource) The name of the bucket. If omitted, Terraform will assign a random, unique name. Must be lowercase and less than or equal to 63 characters in length. A full list of bucket naming rules may be found here. + bucket = string + # (Optional, Default:false) A boolean that indicates all objects (including any locked objects) should be deleted from the bucket so that the bucket can be destroyed without error. These objects are not recoverable. + force_destroy = bool + # (Optional) A configuration of S3 object locking. See Object Lock Configuration below. + object_lock_configuration = list(object( + { + object_lock_enabled = string + } + )) + } + ) +} + +variable "aws_s3_bucket_acl" { + type = object( + { + acl = string + access_control_policy = list(any) + expected_bucket_owner = string + + }) + description = "(Optional) Provides an S3 bucket ACL resource." + default = { + acl = "log-delivery-write" + access_control_policy = [] + expected_bucket_owner = null + } +} +variable "aws_s3_bucket_versioning" { + type = object( + { + versioning_configuration = list(object( + { + # (Required) The versioning state of the bucket. Valid values: Enabled or Suspended. + status = string + # (Optional) Specifies whether MFA delete is enabled in the bucket versioning configuration. Valid values: Enabled or Disabled. + mfa_delete = string + } + )) + }) + description = "(Optional) Configuration block for the versioning parameters." + default = { + versioning_configuration = [ + { + status = "Disabled" + mfa_delete = "Disabled" + } + ] + } +} +variable "aws_s3_bucket_server_side_encryption_configuration" { + type = object( + { + # (Optional, Forces new resource) The account ID of the expected bucket owner. + expected_bucket_owner = string + # (Required) Set of server-side encryption configuration rules. documented below. Currently, only a single rule is supported. + rule = list(object( + { + # (Optional) A single object for setting server-side encryption by default documented below + apply_server_side_encryption_by_default = list(object( + { + # (Required) The server-side encryption algorithm to use. Valid values are AES256 and aws:kms + sse_algorithm = string + # (Optional) The AWS KMS master key ID used for the SSE-KMS encryption. This can only be used when you set the value of sse_algorithm as aws:kms. The default aws/s3 AWS KMS master key is used if this element is absent while the sse_algorithm is aws:kms. + kms_master_key_id = string + } + )) + # (Optional) Whether or not to use Amazon S3 Bucket Keys for SSE-KMS. + bucket_key_enabled = bool + } + )) + } + ) + description = "(Optional) Provides a S3 bucket server-side encryption configuration resource." + default = { + expected_bucket_owner = null + rule = [ + { + apply_server_side_encryption_by_default = [ + { + sse_algorithm = "AES256" + kms_master_key_id = null + } + ] + bucket_key_enabled = null + } + ] + } +} +variable "aws_s3_bucket_logging" { + type = object( + { + # (Optional, Forces new resource) The account ID of the expected bucket owner. + expected_bucket_owner = string + # (Required) The bucket where you want Amazon S3 to store server access logs. + target_bucket = string + # (Required) A prefix for all log object keys. + target_prefix = string + # (Optional) Set of configuration blocks with information for granting permissions documented below. + target_grant = list(object( + { + # (Required) A configuration block for the person being granted permissions documented below. + grantee = list(object( + { + # (Optional) Email address of the grantee. See Regions and Endpoints for supported AWS regions where this argument can be specified. + email_address = string + # (Optional) The canonical user ID of the grantee. + id = string + # (Required) Type of grantee. Valid values: CanonicalUser, AmazonCustomerByEmail, Group. + type = string + # (Optional) URI of the grantee group. + uri = string + } + )) + # (Required) Logging permissions assigned to the grantee for the bucket. Valid values: FULL_CONTROL, READ, WRITE. + permission = string + } + )) + }) + description = "(Optional) Provides a S3 bucket logging resource." + default = null +} +variable "aws_s3_bucket_lifecycle_configuration" { + type = object( + { + # (Optional) The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error. + expected_bucket_owner = string + # (Required) List of configuration blocks describing the rules managing the replication documented below. + rule = list(object( + { + # (Optional) Configuration block that specifies the days since the initiation of an incomplete multipart upload that Amazon S3 will wait before permanently removing all parts of the upload documented below. + abort_incomplete_multipart_upload_days = list(object( + { + # The number of days after which Amazon S3 aborts an incomplete multipart upload. + days_after_initiation = number + } + )) + # (Optional) Configuration block that specifies the expiration for the lifecycle of the object in the form of date, days and, whether the object has a delete marker documented below. + expiration = list(object( + { + # (Optional) The date the object is to be moved or deleted. Should be in GMT ISO 8601 Format. + date = string + # (Optional) The lifetime, in days, of the objects that are subject to the rule. The value must be a non-zero positive integer. + days = number + # (Optional, Conflicts with date and days) Indicates whether Amazon S3 will remove a delete marker with no noncurrent versions. If set to true, the delete marker will be expired; if set to false the policy takes no action. + expired_object_delete_marker = string + } + )) + # (Optional) Configuration block used to identify objects that a Lifecycle Rule applies to documented below. If not specified, the rule will default to using prefix. + filter = list(object( + { + # (Optional) Configuration block used to apply a logical AND to two or more predicates documented below. The Lifecycle Rule will apply to any object matching all the predicates configured inside the and block. + and = string + # (Optional) Minimum object size (in bytes) to which the rule applies. + object_size_greater_than = number + # (Optional) Maximum object size (in bytes) to which the rule applies. + object_size_less_than = number + # (Optional) Prefix identifying one or more objects to which the rule applies. Defaults to an empty string ("") if not specified. + prefix = string + # (Optional) A configuration block for specifying a tag key and value documented below. + tag = list(object( + { + # (Required) Name of the object key. + key = string + # (Required) Value of the tag. + value = string + } + )) + } + )) + # (Required) Unique identifier for the rule. The value cannot be longer than 255 characters. + id = string + # (Optional) Configuration block that specifies when noncurrent object versions expire documented below. + noncurrent_version_expiration = list(object( + { + # (Optional) The number of noncurrent versions Amazon S3 will retain. Must be a non-zero positive integer. + newer_noncurrent_versions = number + # (Optional) The number of days an object is noncurrent before Amazon S3 can perform the associated action. Must be a positive integer. + noncurrent_days = number + } + )) + # (Optional) Set of configuration blocks that specify the transition rule for the lifecycle rule that describes when noncurrent objects transition to a specific storage class documented below. + noncurrent_version_transition = list(object( + { + # (Optional) The number of noncurrent versions Amazon S3 will retain. + newer_noncurrent_versions = number + # (Optional) The number of days an object is noncurrent before Amazon S3 can perform the associated action. + noncurrent_days = number + # (Required) The class of storage used to store the object. Valid Values: GLACIER, STANDARD_IA, ONEZONE_IA, INTELLIGENT_TIERING, DEEP_ARCHIVE, GLACIER_IR. + storage_class = string + } + )) + # (Optional) DEPRECATED Use filter instead. This has been deprecated by Amazon S3. Prefix identifying one or more objects to which the rule applies. Defaults to an empty string ("") if filter is not specified. + prefix = string + # (Required) Whether the rule is currently being applied. Valid values: Enabled or Disabled. + status = string + # (Optional) Set of configuration blocks that specify when an Amazon S3 object transitions to a specified storage class documented below. + transition = list(object( + { + # (Optional, Conflicts with days) The date objects are transitioned to the specified storage class. The date value must be in ISO 8601 format and set to midnight UTC e.g. 2023-01-13T00:00:00Z. + date = string + # (Optional, Conflicts with date) The number of days after creation when objects are transitioned to the specified storage class. The value must be a positive integer. If both days and date are not specified, defaults to 0. Valid values depend on storage_class, see Transition objects using Amazon S3 Lifecycle for more details. + days = string + # The class of storage used to store the object. Valid Values: GLACIER, STANDARD_IA, ONEZONE_IA, INTELLIGENT_TIERING, DEEP_ARCHIVE, GLACIER_IR. + storage_class = string + } + )) + } + ) + ) + } + ) + description = "(Optional) Provides an independent configuration resource for S3 bucket lifecycle configuration." + default = null +} + +variable "s3_replication_configuration_role_arn" { + type = string + description = "(Optional) IAM role ARN to set for the aws_s3_bucket_replication_configuration resource, which does not need to be specified if replication is not performed." + default = null +} + +variable "aws_s3_bucket_replication_configuration" { + type = object( + { + # (Required) Set of configuration blocks describing the rules managing the replication documented below. + rule = list(object( + { + # (Optional) Whether delete markers are replicated. This argument is only valid with V2 replication configurations (i.e., when filter is used)documented below. + delete_marker_replication = list(object( + { + # (Required) Whether delete markers should be replicated. Either "Enabled" or "Disabled". + status = string + } + )) + # (Required) Specifies the destination for the rule documented below. + destination = list(object( + { + # (Optional) A configuration block that specifies the overrides to use for object owners on replication documented below. Specify this only in a cross-account scenario (where source and destination bucket owners are not the same), and you want to change replica ownership to the AWS account that owns the destination bucket. If this is not specified in the replication configuration, the replicas are owned by same AWS account that owns the source object. Must be used in conjunction with account owner override configuration. + access_control_translation = list(object( + { + # (Required) Specifies the replica ownership. For default and valid values, see PUT bucket replication in the Amazon S3 API Reference. Valid values: Destination. + owner = string + } + )) + # (Optional) The Account ID to specify the replica ownership. Must be used in conjunction with access_control_translation override configuration. + account = string + # (Required) The ARN of the S3 bucket where you want Amazon S3 to store replicas of the objects identified by the rule. + bucket = string + # (Optional) A configuration block that provides information about encryption documented below. If source_selection_criteria is specified, you must specify this element. + encryption_configuration = list(object( + { + # (Required) The ID (Key ARN or Alias ARN) of the customer managed AWS KMS key stored in AWS Key Management Service (KMS) for the destination bucket. + replica_kms_key_id = string + } + )) + # (Optional) A configuration block that specifies replication metrics-related settings enabling replication metrics and events documented below. + metrics = list(object( + { + # (Optional) A configuration block that specifies the time threshold for emitting the s3:Replication:OperationMissedThreshold event documented below. + event_threshold = list(object( + { + # (Required) Time in minutes. Valid values: 15. + minutes = string + } + )) + # (Required) The status of the Destination Metrics. Either "Enabled" or "Disabled". + status = string + } + )) + # (Optional) A configuration block that specifies S3 Replication Time Control (S3 RTC), including whether S3 RTC is enabled and the time when all objects and operations on objects must be replicated documented below. Replication Time Control must be used in conjunction with metrics. + replication_time = list(object( + { + # (Required) The status of the Replication Time Control. Either "Enabled" or "Disabled". + status = string + # (Required) A configuration block specifying the time by which replication should be complete for all objects and operations on objects documented below. + time = list(object( + { + # (Required) Time in minutes. Valid values: 15. + minutes = string + } + )) + } + )) + # (Optional) The storage class used to store the object. By default, Amazon S3 uses the storage class of the source object to create the object replica. + storage_class = string + } + )) + + # (Optional) Replicate existing objects in the source bucket according to the rule configurations documented below. + existing_object_replication = list(object( + { + # (Required) Whether the existing objects should be replicated. Either "Enabled" or "Disabled". + status = string + } + )) + # (Optional, Conflicts with prefix) Filter that identifies subset of objects to which the replication rule applies documented below. + filter = list(object( + { + # (Optional) A configuration block for specifying rule filters. This element is required only if you specify more than one filter. See and below for more details. + and = list(object( + { + # (Optional) An object key name prefix that identifies subset of objects to which the rule applies. Must be less than or equal to 1024 characters in length. + prefix = string + # (Optional, Required if prefix is configured) A map of tags (key and value pairs) that identifies a subset of objects to which the rule applies. The rule applies only to objects having all the tags in its tagset. + tags = string + } + )) + # (Optional) An object key name prefix that identifies subset of objects to which the rule applies. Must be less than or equal to 1024 characters in length. + prefix = string + # (Optional) A configuration block for specifying a tag key and value documented below. + tag = list(object( + { + # (Required) Name of the object key. + key = string + # (Required) Value of the tag. + value = string + } + )) + } + )) + # (Optional) Unique identifier for the rule. Must be less than or equal to 255 characters in length. + id = string + # (Optional, Conflicts with filter) Object key name prefix identifying one or more objects to which the rule applies. Must be less than or equal to 1024 characters in length. + prefix = string + # (Optional) The priority associated with the rule. Priority should only be set if filter is configured. If not provided, defaults to 0. Priority must be unique between multiple rules. + priority = string + # (Optional) Specifies special object selection criteria documented below. + source_selection_criteria = list(object( + { + # (Optional) A configuration block that you can specify for selections for modifications on replicas. Amazon S3 doesn't replicate replica modifications by default. In the latest version of replication configuration (when filter is specified), you can specify this element and set the status to Enabled to replicate modifications on replicas. + replica_modifications = list(object( + { + # (Required) Whether the existing objects should be replicated. Either "Enabled" or "Disabled". + status = string + } + )) + # (Optional) A configuration block for filter information for the selection of Amazon S3 objects encrypted with AWS KMS. If specified, replica_kms_key_id in destination encryption_configuration must be specified as well. + sse_kms_encrypted_objects = list(object( + { + # (Required) Whether the existing objects should be replicated. Either "Enabled" or "Disabled". + status = string + } + )) + } + )) + # (Required) The status of the rule. Either "Enabled" or "Disabled". The rule is ignored if status is not "Enabled". + status = string + } + ) + ) + } + ) + description = "(Optional) Provides an independent configuration resource for S3 bucket lifecycle configuration." + default = null +} +variable "tags" { + type = map(any) + description = "(Optional) A mapping of tags to assign to the bucket." + default = null +} diff --git a/modules/aws/recipes/s3/bucket/log-v4/versions.tf b/modules/aws/recipes/s3/bucket/log-v4/versions.tf new file mode 100644 index 0000000..11294d7 --- /dev/null +++ b/modules/aws/recipes/s3/bucket/log-v4/versions.tf @@ -0,0 +1,12 @@ +#-------------------------------------------------------------- +# Terraform Provider +#-------------------------------------------------------------- +terraform { + required_version = ">=0.14" + required_providers { + aws = { + source = "hashicorp/aws" + version = ">=4.0.0" + } + } +} diff --git a/modules/aws/recipes/s3/bucket/log/main.tf b/modules/aws/recipes/s3/bucket/log/main.tf index d0c23a9..ff2e0b3 100644 --- a/modules/aws/recipes/s3/bucket/log/main.tf +++ b/modules/aws/recipes/s3/bucket/log/main.tf @@ -2,8 +2,16 @@ # Locals #-------------------------------------------------------------- locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } name = var.is_random_name_suffix ? "${var.bucket}-${random_id.this.dec}" : var.bucket } +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # create random id for s3 bukect name #-------------------------------------------------------------- @@ -19,7 +27,7 @@ resource "aws_s3_bucket" "this" { # bucket_prefix = var.bucket_prefix acl = var.acl policy = var.policy - tags = var.tags + tags = local.tags force_destroy = var.force_destroy # dynamic "website" { diff --git a/modules/aws/recipes/s3/bucket/private/main.tf b/modules/aws/recipes/s3/bucket/private/main.tf index f59650b..4ad6bf8 100644 --- a/modules/aws/recipes/s3/bucket/private/main.tf +++ b/modules/aws/recipes/s3/bucket/private/main.tf @@ -2,11 +2,19 @@ # Locals #-------------------------------------------------------------- locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } name = var.is_random_name_suffix ? "${var.bucket}-${random_id.this.dec}" : var.bucket - tags = var.tags == null ? null : merge(var.tags, { + tagsadd = local.tags == null ? null : merge(local.tags, { "Name" = local.name }) } +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # create random id for s3 bukect name #-------------------------------------------------------------- @@ -22,7 +30,7 @@ resource "aws_s3_bucket" "this" { # bucket_prefix = var.bucket_prefix acl = var.acl policy = var.policy - tags = local.tags + tags = local.tagsadd force_destroy = var.force_destroy # dynamic "website" { diff --git a/modules/aws/recipes/security/access_analyzer/main.tf b/modules/aws/recipes/security/access_analyzer/main.tf index 06d951e..bc70488 100644 --- a/modules/aws/recipes/security/access_analyzer/main.tf +++ b/modules/aws/recipes/security/access_analyzer/main.tf @@ -1,9 +1,22 @@ +#-------------------------------------------------------------- +# Locals +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Manages an Access Analyzer Analyzer. More information can be found in the Access Analyzer User Guide. #-------------------------------------------------------------- resource "aws_accessanalyzer_analyzer" "this" { count = var.is_enabled ? 1 : 0 analyzer_name = var.analyzer_name - tags = var.tags + tags = local.tags type = var.type } diff --git a/modules/aws/recipes/security/cloudtrail-v4/.tflint.hcl b/modules/aws/recipes/security/cloudtrail-v4/.tflint.hcl new file mode 100644 index 0000000..ec4cf12 --- /dev/null +++ b/modules/aws/recipes/security/cloudtrail-v4/.tflint.hcl @@ -0,0 +1,12 @@ +rule "aws_s3_bucket_invalid_acl" { + enabled = false +} +rule "aws_cloudwatch_log_group_invalid_kms_key_id" { + enabled = false +} +rule "aws_cloudwatch_log_group_invalid_name" { + enabled = false +} +rule "aws_kms_key_invalid_policy" { + enabled = false +} diff --git a/modules/aws/recipes/security/cloudtrail-v4/main.tf b/modules/aws/recipes/security/cloudtrail-v4/main.tf new file mode 100644 index 0000000..e456f8b --- /dev/null +++ b/modules/aws/recipes/security/cloudtrail-v4/main.tf @@ -0,0 +1,1317 @@ + +#-------------------------------------------------------------- +# For CloudTrail +#-------------------------------------------------------------- +#-------------------------------------------------------------- +# Local +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } + is_s3_enabled = var.is_enabled && var.is_s3_enabled + bucket_id = local.is_s3_enabled ? aws_s3_bucket.this[0].id : var.aws_s3_bucket_existing.bucket_id + bucket_arn = local.is_s3_enabled ? aws_s3_bucket.this[0].arn : var.aws_s3_bucket_existing.bucket_arn +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + +#-------------------------------------------------------------- +# Provides a KMS customer master key. +#-------------------------------------------------------------- +resource "aws_kms_key" "cloudtrail" { + count = var.is_enabled ? 1 : 0 + description = lookup(var.aws_kms_key.cloudtrail, "description", null) + policy = < v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } is_s3_enabled = var.is_enabled && var.is_s3_enabled bucket_id = local.is_s3_enabled ? aws_s3_bucket.this[0].id : var.aws_s3_bucket_existing.bucket_id bucket_arn = local.is_s3_enabled ? aws_s3_bucket.this[0].arn : var.aws_s3_bucket_existing.bucket_arn } +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} #-------------------------------------------------------------- # Provides a KMS customer master key. @@ -118,7 +125,7 @@ POLICY deletion_window_in_days = lookup(var.aws_kms_key.cloudtrail, "deletion_window_in_days", 7) is_enabled = lookup(var.aws_kms_key.cloudtrail, "is_enabled", true) enable_key_rotation = lookup(var.aws_kms_key.cloudtrail, "enable_key_rotation", true) - tags = merge(var.tags, { + tags = merge(local.tags, { Name = lookup(var.aws_kms_key.cloudtrail, "alias_name") } ) @@ -189,7 +196,7 @@ POLICY deletion_window_in_days = lookup(var.aws_kms_key.sns, "deletion_window_in_days", 7) is_enabled = lookup(var.aws_kms_key.sns, "is_enabled", true) enable_key_rotation = lookup(var.aws_kms_key.sns, "enable_key_rotation", true) - tags = merge(var.tags, { + tags = merge(local.tags, { Name = lookup(var.aws_kms_key.sns, "alias_name") } ) @@ -226,7 +233,7 @@ resource "aws_sns_topic" "this" { sqs_success_feedback_role_arn = lookup(var.aws_sns_topic, "sqs_success_feedback_role_arn", null) sqs_success_feedback_sample_rate = lookup(var.aws_sns_topic, "sqs_success_feedback_sample_rate", null) sqs_failure_feedback_role_arn = lookup(var.aws_sns_topic, "sqs_failure_feedback_role_arn", null) - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides a resource for subscribing to SNS topics. @@ -254,7 +261,7 @@ resource "aws_cloudwatch_log_group" "this" { name = lookup(var.aws_cloudwatch_log_group, "name") retention_in_days = lookup(var.aws_cloudwatch_log_group, "retention_in_days") kms_key_id = lookup(var.aws_cloudwatch_log_group, "kms_key_id", null) - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- @@ -293,7 +300,7 @@ resource "aws_cloudwatch_metric_alarm" "cis_3_1" { alarm_description = "[CIS.3.1] Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for unauthorized API calls." insufficient_data_actions = [] treat_missing_data = "notBreaching" - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- @@ -332,7 +339,7 @@ resource "aws_cloudwatch_metric_alarm" "cis_3_2" { alarm_description = "[CIS.3.2] Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for console logins that are not protected by multi-factor authentication (MFA)." insufficient_data_actions = [] treat_missing_data = "notBreaching" - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- @@ -371,7 +378,7 @@ resource "aws_cloudwatch_metric_alarm" "cis_3_3" { alarm_description = "[CIS.3.3] Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for root login attempts." insufficient_data_actions = [] treat_missing_data = "notBreaching" - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # (CIS.3.4) Provides a CloudWatch Log Metric Filter resource. @@ -409,7 +416,7 @@ resource "aws_cloudwatch_metric_alarm" "cis_3_4" { alarm_description = "[CIS.3.4] Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established changes made to Identity and Access Management (IAM) policies." insufficient_data_actions = [] treat_missing_data = "notBreaching" - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # (CIS.3.5) Provides a CloudWatch Log Metric Filter resource. @@ -447,7 +454,7 @@ resource "aws_cloudwatch_metric_alarm" "cis_3_5" { alarm_description = "[CIS.3.5] Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations." insufficient_data_actions = [] treat_missing_data = "notBreaching" - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # (CIS.3.6) Provides a CloudWatch Log Metric Filter resource. @@ -485,7 +492,7 @@ resource "aws_cloudwatch_metric_alarm" "cis_3_6" { alarm_description = "[CIS.3.6] Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for failed console authentication attempts." insufficient_data_actions = [] treat_missing_data = "notBreaching" - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # (CIS.3.7) Provides a CloudWatch Log Metric Filter resource. @@ -523,7 +530,7 @@ resource "aws_cloudwatch_metric_alarm" "cis_3_7" { alarm_description = "[CIS.3.7] Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for customer created CMKs which have changed state to disabled or scheduled deletion." insufficient_data_actions = [] treat_missing_data = "notBreaching" - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # (CIS.3.8) Provides a CloudWatch Log Metric Filter resource. @@ -561,7 +568,7 @@ resource "aws_cloudwatch_metric_alarm" "cis_3_8" { alarm_description = "[CIS.3.8] Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for changes to S3 bucket policies." insufficient_data_actions = [] treat_missing_data = "notBreaching" - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # (CIS.3.9) Provides a CloudWatch Log Metric Filter resource. @@ -599,7 +606,7 @@ resource "aws_cloudwatch_metric_alarm" "cis_3_9" { alarm_description = "[CIS.3.9] Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations" insufficient_data_actions = [] treat_missing_data = "notBreaching" - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # (CIS.3.10) Provides a CloudWatch Log Metric Filter resource. @@ -637,7 +644,7 @@ resource "aws_cloudwatch_metric_alarm" "cis_3_10" { alarm_description = "[CIS.3.10] Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security Groups are a stateful packet filter that controls ingress and egress traffic within a VPC. It is recommended that a metric filter and alarm be established changes to Security Groups." insufficient_data_actions = [] treat_missing_data = "notBreaching" - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # (CIS.3.11) Provides a CloudWatch Log Metric Filter resource. @@ -675,7 +682,7 @@ resource "aws_cloudwatch_metric_alarm" "cis_3_11" { alarm_description = "[CIS.3.11] Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. NACLs are used as a stateless packet filter to control ingress and egress traffic for subnets within a VPC. It is recommended that a metric filter and alarm be established for changes made to NACLs." insufficient_data_actions = [] treat_missing_data = "notBreaching" - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # (CIS.3.12) Provides a CloudWatch Log Metric Filter resource. @@ -713,7 +720,7 @@ resource "aws_cloudwatch_metric_alarm" "cis_3_12" { alarm_description = "[CIS.3.12] Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Network gateways are required to send/receive traffic to a destination outside of a VPC. It is recommended that a metric filter and alarm be established for changes to network gateways." insufficient_data_actions = [] treat_missing_data = "notBreaching" - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # (CIS.3.13) Provides a CloudWatch Log Metric Filter resource. @@ -751,7 +758,7 @@ resource "aws_cloudwatch_metric_alarm" "cis_3_13" { alarm_description = "[CIS.3.13] Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Routing tables are used to route network traffic between subnets and to network gateways. It is recommended that a metric filter and alarm be established for changes to route tables." insufficient_data_actions = [] treat_missing_data = "notBreaching" - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # (CIS.3.14) Provides a CloudWatch Log Metric Filter resource. @@ -789,7 +796,7 @@ resource "aws_cloudwatch_metric_alarm" "cis_3_14" { alarm_description = "[CIS.3.14] Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is possible to have more than 1 VPC within an account, in addition it is also possible to create a peer connection between 2 VPCs enabling network traffic to route between VPCs. It is recommended that a metric filter and alarm be established for changes made to VPCs." insufficient_data_actions = [] treat_missing_data = "notBreaching" - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- @@ -813,7 +820,7 @@ resource "aws_iam_role" "this" { } POLICY path = lookup(var.aws_iam_role, "path", "/") - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an IAM policy. @@ -869,7 +876,7 @@ resource "aws_s3_bucket" "this" { bucket = lookup(var.aws_s3_bucket, "bucket") # bucket_prefix = var.bucket_prefix acl = "private" - tags = var.tags + tags = local.tags force_destroy = lookup(var.aws_s3_bucket, "force_destroy", false) dynamic "versioning" { for_each = lookup(var.aws_s3_bucket, "versioning", []) @@ -1132,7 +1139,7 @@ resource "aws_cloudtrail" "this" { insight_type = lookup(insight_selector.value, "insight_type", null) } } - tags = var.tags + tags = local.tags depends_on = [ aws_kms_key.cloudtrail, aws_cloudwatch_log_group.this, diff --git a/modules/aws/recipes/security/config/create-v4/.tflint.hcl b/modules/aws/recipes/security/config/create-v4/.tflint.hcl new file mode 100644 index 0000000..9d2d096 --- /dev/null +++ b/modules/aws/recipes/security/config/create-v4/.tflint.hcl @@ -0,0 +1,9 @@ +rule "aws_s3_bucket_invalid_acl" { + enabled = false +} +rule "aws_config_configuration_recorder_invalid_name" { + enabled = false +} +rule "aws_config_delivery_channel_invalid_name" { + enabled = false +} diff --git a/modules/aws/recipes/security/config/create-v4/main.tf b/modules/aws/recipes/security/config/create-v4/main.tf new file mode 100644 index 0000000..6fd240b --- /dev/null +++ b/modules/aws/recipes/security/config/create-v4/main.tf @@ -0,0 +1,593 @@ +#-------------------------------------------------------------- +# Local +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } + is_s3_enabled = var.is_enabled && var.is_s3_enabled + bucket_id = local.is_s3_enabled ? aws_s3_bucket.this[0].id : var.aws_s3_bucket_existing.bucket_id + bucket_arn = local.is_s3_enabled ? aws_s3_bucket.this[0].arn : var.aws_s3_bucket_existing.bucket_arn +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + +#-------------------------------------------------------------- +# Provides an IAM role. +#-------------------------------------------------------------- +resource "aws_iam_role" "config" { + count = var.is_enabled ? 1 : 0 + description = lookup(var.aws_iam_role, "description", null) + name = lookup(var.aws_iam_role, "name") + assume_role_policy = < v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } is_s3_enabled = var.is_enabled && var.is_s3_enabled bucket_id = local.is_s3_enabled ? aws_s3_bucket.this[0].id : var.aws_s3_bucket_existing.bucket_id bucket_arn = local.is_s3_enabled ? aws_s3_bucket.this[0].arn : var.aws_s3_bucket_existing.bucket_arn } +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Provides an IAM role. #-------------------------------------------------------------- @@ -29,7 +37,7 @@ resource "aws_iam_role" "config" { POLICY path = lookup(var.aws_iam_role, "path", "/") force_detach_policies = true - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Attaches a Managed IAM Policy to an IAM role @@ -68,7 +76,7 @@ resource "aws_s3_bucket" "this" { bucket = lookup(var.aws_s3_bucket, "bucket") # bucket_prefix = var.bucket_prefix acl = "private" - tags = var.tags + tags = local.tags force_destroy = lookup(var.aws_s3_bucket, "force_destroy", false) dynamic "versioning" { for_each = lookup(var.aws_s3_bucket, "versioning", []) @@ -390,7 +398,7 @@ resource "aws_cloudwatch_event_rule" "this" { EVENT_PATTERN description = lookup(var.aws_cloudwatch_event_rule, "description") is_enabled = true - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an EventBridge Target resource. diff --git a/modules/aws/recipes/security/config/rule/acm/main.tf b/modules/aws/recipes/security/config/rule/acm/main.tf index f19b1e8..9dc1671 100644 --- a/modules/aws/recipes/security/config/rule/acm/main.tf +++ b/modules/aws/recipes/security/config/rule/acm/main.tf @@ -3,7 +3,15 @@ #-------------------------------------------------------------- locals { name_prefix = var.name_prefix == "" ? "" : "${trimsuffix(var.name_prefix, "-")}-" + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } } +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Provides an AWS Config Rule. #-------------------------------------------------------------- @@ -15,7 +23,7 @@ resource "aws_config_config_rule" "acm-certificate-expiration-check" { owner = "AWS" source_identifier = "ACM_CERTIFICATE_EXPIRATION_CHECK" } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -29,5 +37,5 @@ resource "aws_config_config_rule" "acm-certificate-expiration-check" { # owner = "AWS" # source_identifier = "API_GW_EXECUTION_LOGGING_ENABLED" # } -# tags = var.tags +# tags = local.tags # } diff --git a/modules/aws/recipes/security/config/rule/api_gateway/main.tf b/modules/aws/recipes/security/config/rule/api_gateway/main.tf index b0a6909..542bac7 100644 --- a/modules/aws/recipes/security/config/rule/api_gateway/main.tf +++ b/modules/aws/recipes/security/config/rule/api_gateway/main.tf @@ -2,8 +2,16 @@ # Locals #-------------------------------------------------------------- locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } name_prefix = var.name_prefix == "" ? "" : "${trimsuffix(var.name_prefix, "-")}-" } +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Provides an AWS Config Rule. #-------------------------------------------------------------- @@ -16,7 +24,7 @@ locals { # owner = "AWS" # source_identifier = "API_GW_ENDPOINT_TYPE_CHECK" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -29,7 +37,7 @@ resource "aws_config_config_rule" "api-gw-xray-enabled" { owner = "AWS" source_identifier = "API_GW_XRAY_ENABLED" } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -43,5 +51,5 @@ resource "aws_config_config_rule" "api-gw-xray-enabled" { # owner = "AWS" # source_identifier = "API_GW_EXECUTION_LOGGING_ENABLED" # } -# tags = var.tags +# tags = local.tags # } diff --git a/modules/aws/recipes/security/config/rule/cloudfront/main.tf b/modules/aws/recipes/security/config/rule/cloudfront/main.tf index 4295ffb..d4135c2 100644 --- a/modules/aws/recipes/security/config/rule/cloudfront/main.tf +++ b/modules/aws/recipes/security/config/rule/cloudfront/main.tf @@ -2,8 +2,16 @@ # Locals #-------------------------------------------------------------- locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } name_prefix = var.name_prefix == "" ? "" : "${trimsuffix(var.name_prefix, "-")}-" } +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Provides an AWS Config Rule. #-------------------------------------------------------------- @@ -15,7 +23,7 @@ resource "aws_config_config_rule" "cloudfront-accesslogs-enabled" { owner = "AWS" source_identifier = "CLOUDFRONT_ACCESSLOGS_ENABLED" } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -28,7 +36,7 @@ resource "aws_config_config_rule" "cloudfront-associated-with-waf" { owner = "AWS" source_identifier = "CLOUDFRONT_ASSOCIATED_WITH_WAF" } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -41,7 +49,7 @@ resource "aws_config_config_rule" "cloudfront-custom-ssl-certificate" { owner = "AWS" source_identifier = "CLOUDFRONT_CUSTOM_SSL_CERTIFICATE" } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -54,7 +62,7 @@ resource "aws_config_config_rule" "cloudfront-default-root-object-configured" { owner = "AWS" source_identifier = "CLOUDFRONT_DEFAULT_ROOT_OBJECT_CONFIGURED" } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -67,7 +75,7 @@ resource "aws_config_config_rule" "cloudfront-origin-access-identity-enabled" { owner = "AWS" source_identifier = "CLOUDFRONT_ORIGIN_ACCESS_IDENTITY_ENABLED" } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -80,7 +88,7 @@ resource "aws_config_config_rule" "cloudfront-origin-failover-enabled" { owner = "AWS" source_identifier = "CLOUDFRONT_ORIGIN_FAILOVER_ENABLED" } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -93,7 +101,7 @@ resource "aws_config_config_rule" "cloudfront-sni-enabled" { owner = "AWS" source_identifier = "CLOUDFRONT_SNI_ENABLED" } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -106,7 +114,7 @@ resource "aws_config_config_rule" "cloudfront-viewer-policy-https" { owner = "AWS" source_identifier = "CLOUDFRONT_VIEWER_POLICY_HTTPS" } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an AWS Config Remediation Configuration. diff --git a/modules/aws/recipes/security/config/rule/custom/main.tf b/modules/aws/recipes/security/config/rule/custom/main.tf index 605b0bc..18c033b 100644 --- a/modules/aws/recipes/security/config/rule/custom/main.tf +++ b/modules/aws/recipes/security/config/rule/custom/main.tf @@ -1,3 +1,16 @@ +#-------------------------------------------------------------- +# Locals +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Provides an AWS Config Rule. #-------------------------------------------------------------- @@ -31,5 +44,5 @@ resource "aws_config_config_rule" "this" { } } } - tags = var.tags + tags = local.tags } diff --git a/modules/aws/recipes/security/config/rule/ec2/main.tf b/modules/aws/recipes/security/config/rule/ec2/main.tf index 1fc6c74..b745ea3 100644 --- a/modules/aws/recipes/security/config/rule/ec2/main.tf +++ b/modules/aws/recipes/security/config/rule/ec2/main.tf @@ -2,8 +2,16 @@ # Locals #-------------------------------------------------------------- locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } name_prefix = var.name_prefix == "" ? "" : "${trimsuffix(var.name_prefix, "-")}-" } +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Provides an AWS Config Rule. #-------------------------------------------------------------- @@ -15,7 +23,7 @@ locals { # owner = "AWS" # source_identifier = "APPROVED_AMIS_BY_ID" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -28,7 +36,7 @@ locals { # owner = "AWS" # source_identifier = "APPROVED_AMIS_BY_TAG" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -41,7 +49,7 @@ locals { # owner = "AWS" # source_identifier = "DESIRED_INSTANCE_TENANCY" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -54,7 +62,7 @@ locals { # owner = "AWS" # source_identifier = "DESIRED_INSTANCE_TYPE" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -67,7 +75,7 @@ resource "aws_config_config_rule" "ebs-optimized-instance" { owner = "AWS" source_identifier = "EBS_OPTIMIZED_INSTANCE" } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -81,7 +89,7 @@ resource "aws_config_config_rule" "ebs-optimized-instance" { # owner = "AWS" # source_identifier = "EBS_SNAPSHOT_PUBLIC_RESTORABLE_CHECK" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -95,7 +103,7 @@ resource "aws_config_config_rule" "ebs-optimized-instance" { # owner = "AWS" # source_identifier = "EC2_EBS_ENCRYPTION_BY_DEFAULT" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -109,7 +117,7 @@ resource "aws_config_config_rule" "ebs-optimized-instance" { # owner = "AWS" # source_identifier = "EC2_IMDSV2_CHECK" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -122,7 +130,7 @@ resource "aws_config_config_rule" "ec2-instance-detailed-monitoring-enabled" { owner = "AWS" source_identifier = "EC2_INSTANCE_DETAILED_MONITORING_ENABLED" } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -136,7 +144,7 @@ resource "aws_config_config_rule" "ec2-instance-detailed-monitoring-enabled" { # owner = "AWS" # source_identifier = "EC2_INSTANCE_MANAGED_BY_SSM" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -150,7 +158,7 @@ resource "aws_config_config_rule" "ec2-instance-detailed-monitoring-enabled" { # owner = "AWS" # source_identifier = "EC2_INSTANCE_NO_PUBLIC_IP" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -163,7 +171,7 @@ resource "aws_config_config_rule" "ec2-instance-profile-attached" { owner = "AWS" source_identifier = "EC2_INSTANCE_PROFILE_ATTACHED" } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -176,7 +184,7 @@ resource "aws_config_config_rule" "ec2-instances-in-vpc" { owner = "AWS" source_identifier = "INSTANCES_IN_VPC" } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -189,7 +197,7 @@ resource "aws_config_config_rule" "ec2-instances-in-vpc" { # owner = "AWS" # source_identifier = "EC2_MANAGEDINSTANCE_APPLICATIONS_BLACKLISTED" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -202,7 +210,7 @@ resource "aws_config_config_rule" "ec2-instances-in-vpc" { # owner = "AWS" # source_identifier = "EC2_MANAGEDINSTANCE_APPLICATIONS_REQUIRED" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -216,7 +224,7 @@ resource "aws_config_config_rule" "ec2-instances-in-vpc" { # owner = "AWS" # source_identifier = "EC2_MANAGEDINSTANCE_ASSOCIATION_COMPLIANCE_STATUS_CHECK" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -229,7 +237,7 @@ resource "aws_config_config_rule" "ec2-instances-in-vpc" { # owner = "AWS" # source_identifier = "EC2_MANAGEDINSTANCE_INVENTORY_BLACKLISTED" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -242,7 +250,7 @@ resource "aws_config_config_rule" "ec2-instances-in-vpc" { # owner = "AWS" # source_identifier = "EC2_MANAGEDINSTANCE_PATCH_COMPLIANCE_STATUS_CHECK" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -255,7 +263,7 @@ resource "aws_config_config_rule" "ec2-instances-in-vpc" { # owner = "AWS" # source_identifier = "EC2_MANAGEDINSTANCE_PLATFORM_CHECK" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -269,7 +277,7 @@ resource "aws_config_config_rule" "ec2-instances-in-vpc" { # owner = "AWS" # source_identifier = "EC2_SECURITY_GROUP_ATTACHED_TO_ENI" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -286,7 +294,7 @@ resource "aws_config_config_rule" "ec2-instances-in-vpc" { # owner = "AWS" # source_identifier = "EC2_STOPPED_INSTANCE" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -299,7 +307,7 @@ resource "aws_config_config_rule" "ec2-volume-inuse-check" { owner = "AWS" source_identifier = "EC2_VOLUME_INUSE_CHECK" } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -313,7 +321,7 @@ resource "aws_config_config_rule" "ec2-volume-inuse-check" { # owner = "AWS" # source_identifier = "EIP_ATTACHED" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -327,7 +335,7 @@ resource "aws_config_config_rule" "ec2-volume-inuse-check" { # owner = "AWS" # source_identifier = "ENCRYPTED_VOLUMES" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -341,7 +349,7 @@ resource "aws_config_config_rule" "restricted-common-ports" { owner = "AWS" source_identifier = "RESTRICTED_INCOMING_TRAFFIC" } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -354,7 +362,7 @@ resource "aws_config_config_rule" "restricted-ssh" { owner = "AWS" source_identifier = "INCOMING_SSH_DISABLED" } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an AWS Config Remediation Configuration. @@ -390,7 +398,7 @@ resource "aws_config_remediation_configuration" "restricted-ssh" { # owner = "AWS" # source_identifier = "SUBNET_AUTO_ASSIGN_PUBLIC_IP_DISABLED" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -404,7 +412,7 @@ resource "aws_config_remediation_configuration" "restricted-ssh" { # owner = "AWS" # source_identifier = "VPC_FLOW_LOGS_ENABLED" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -417,5 +425,5 @@ resource "aws_config_remediation_configuration" "restricted-ssh" { # owner = "AWS" # source_identifier = "VPC_VPN_2_TUNNELS_UP" # } -# tags = var.tags +# tags = local.tags # } diff --git a/modules/aws/recipes/security/config/rule/load_balancer/main.tf b/modules/aws/recipes/security/config/rule/load_balancer/main.tf index b2d0c49..613d262 100644 --- a/modules/aws/recipes/security/config/rule/load_balancer/main.tf +++ b/modules/aws/recipes/security/config/rule/load_balancer/main.tf @@ -2,8 +2,16 @@ # Locals #-------------------------------------------------------------- locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } name_prefix = var.name_prefix == "" ? "" : "${trimsuffix(var.name_prefix, "-")}-" } +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Provides an AWS Config Rule. # SecurityHub: enabled @@ -16,7 +24,7 @@ locals { # owner = "AWS" # source_identifier = "ALB_HTTP_DROP_INVALID_HEADER_ENABLED" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -30,7 +38,7 @@ locals { # owner = "AWS" # source_identifier = "ALB_HTTP_TO_HTTPS_REDIRECTION_CHECK" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -43,7 +51,7 @@ resource "aws_config_config_rule" "alb-waf-enabled" { owner = "AWS" source_identifier = "ALB_WAF_ENABLED" } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -57,7 +65,7 @@ resource "aws_config_config_rule" "alb-waf-enabled" { # owner = "AWS" # source_identifier = "AUTOSCALING_GROUP_ELB_HEALTHCHECK_REQUIRED" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -70,7 +78,7 @@ resource "aws_config_config_rule" "elb-acm-certificate-required" { owner = "AWS" source_identifier = "ELB_ACM_CERTIFICATE_REQUIRED" } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -83,7 +91,7 @@ resource "aws_config_config_rule" "elb-cross-zone-load-balancing-enabled" { owner = "AWS" source_identifier = "ELB_CROSS_ZONE_LOAD_BALANCING_ENABLED" } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -96,7 +104,7 @@ resource "aws_config_config_rule" "elb-cross-zone-load-balancing-enabled" { # owner = "AWS" # source_identifier = "ELB_CUSTOM_SECURITY_POLICY_SSL_CHECK" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -110,7 +118,7 @@ resource "aws_config_config_rule" "elb-cross-zone-load-balancing-enabled" { # owner = "AWS" # source_identifier = "ELB_DELETION_PROTECTION_ENABLED" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -124,7 +132,7 @@ resource "aws_config_config_rule" "elb-cross-zone-load-balancing-enabled" { # owner = "AWS" # source_identifier = "ELB_LOGGING_ENABLED" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -137,7 +145,7 @@ resource "aws_config_config_rule" "elb-cross-zone-load-balancing-enabled" { # owner = "AWS" # source_identifier = "ELB_PREDEFINED_SECURITY_POLICY_SSL_CHECK" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -151,5 +159,5 @@ resource "aws_config_config_rule" "elb-cross-zone-load-balancing-enabled" { # owner = "AWS" # source_identifier = "ELB_TLS_HTTPS_LISTENERS_ONLY" # } -# tags = var.tags +# tags = local.tags # } diff --git a/modules/aws/recipes/security/config/rule/rds/main.tf b/modules/aws/recipes/security/config/rule/rds/main.tf index 36cd8c2..6f1c7af 100644 --- a/modules/aws/recipes/security/config/rule/rds/main.tf +++ b/modules/aws/recipes/security/config/rule/rds/main.tf @@ -2,8 +2,16 @@ # Locals #-------------------------------------------------------------- locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } name_prefix = var.name_prefix == "" ? "" : "${trimsuffix(var.name_prefix, "-")}-" } +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Provides an AWS Config Rule. #-------------------------------------------------------------- @@ -15,7 +23,7 @@ resource "aws_config_config_rule" "aurora-mysql-backtracking-enabled" { owner = "AWS" source_identifier = "AURORA_MYSQL_BACKTRACKING_ENABLED" } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -28,7 +36,7 @@ resource "aws_config_config_rule" "db-instance-backup-enabled" { owner = "AWS" source_identifier = "DB_INSTANCE_BACKUP_ENABLED" } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -41,7 +49,7 @@ resource "aws_config_config_rule" "rds-automatic-minor-version-upgrade-enabled" owner = "AWS" source_identifier = "RDS_AUTOMATIC_MINOR_VERSION_UPGRADE_ENABLED" } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -55,7 +63,7 @@ resource "aws_config_config_rule" "rds-automatic-minor-version-upgrade-enabled" # owner = "AWS" # source_identifier = "RDS_CLUSTER_DELETION_PROTECTION_ENABLED" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -68,7 +76,7 @@ resource "aws_config_config_rule" "rds-in-backup-plan" { owner = "AWS" source_identifier = "RDS_IN_BACKUP_PLAN" } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -82,7 +90,7 @@ resource "aws_config_config_rule" "rds-in-backup-plan" { # owner = "AWS" # source_identifier = "RDS_INSTANCE_DELETION_PROTECTION_ENABLED" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -95,7 +103,7 @@ resource "aws_config_config_rule" "rds-in-backup-plan" { # owner = "AWS" # source_identifier = "RDS_INSTANCE_PUBLIC_ACCESS_CHECK" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -109,7 +117,7 @@ resource "aws_config_config_rule" "rds-in-backup-plan" { # owner = "AWS" # source_identifier = "RDS_LOGGING_ENABLED" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -123,7 +131,7 @@ resource "aws_config_config_rule" "rds-in-backup-plan" { # owner = "AWS" # source_identifier = "RDS_MULTI_AZ_SUPPORT" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -137,7 +145,7 @@ resource "aws_config_config_rule" "rds-in-backup-plan" { # owner = "AWS" # source_identifier = "RDS_SNAPSHOT_ENCRYPTED" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -151,7 +159,7 @@ resource "aws_config_config_rule" "rds-in-backup-plan" { # owner = "AWS" # source_identifier = "RDS_SNAPSHOTS_PUBLIC_PROHIBITED" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -165,5 +173,5 @@ resource "aws_config_config_rule" "rds-in-backup-plan" { # owner = "AWS" # source_identifier = "RDS_STORAGE_ENCRYPTED" # } -# tags = var.tags +# tags = local.tags # } diff --git a/modules/aws/recipes/security/config/rule/s3/main.tf b/modules/aws/recipes/security/config/rule/s3/main.tf index 3035fa8..a6f0315 100644 --- a/modules/aws/recipes/security/config/rule/s3/main.tf +++ b/modules/aws/recipes/security/config/rule/s3/main.tf @@ -2,8 +2,16 @@ # Locals #-------------------------------------------------------------- locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } name_prefix = var.name_prefix == "" ? "" : "${trimsuffix(var.name_prefix, "-")}-" } +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Provides an AWS Config Rule. #-------------------------------------------------------------- @@ -15,7 +23,7 @@ resource "aws_config_config_rule" "cloudtrail-s3-dataevents-enabled" { owner = "AWS" source_identifier = "CLOUDTRAIL_S3_DATAEVENTS_ENABLED" } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -29,7 +37,7 @@ resource "aws_config_config_rule" "s3-account-level-public-access-blocks" { owner = "AWS" source_identifier = "S3_ACCOUNT_LEVEL_PUBLIC_ACCESS_BLOCKS" } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an AWS Config Remediation Configuration. @@ -80,7 +88,7 @@ resource "aws_config_remediation_configuration" "s3-account-level-public-access- # owner = "AWS" # source_identifier = "S3_BUCKET_BLACKLISTED_ACTIONS_PROHIBITED" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -93,7 +101,7 @@ resource "aws_config_remediation_configuration" "s3-account-level-public-access- # owner = "AWS" # source_identifier = "S3_BUCKET_DEFAULT_LOCK_ENABLED" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -106,7 +114,7 @@ resource "aws_config_config_rule" "s3-bucket-level-public-access-prohibited" { owner = "AWS" source_identifier = "S3_BUCKET_LEVEL_PUBLIC_ACCESS_PROHIBITED" } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an AWS Config Remediation Configuration. @@ -157,7 +165,7 @@ resource "aws_config_remediation_configuration" "s3-bucket-level-public-access-p # owner = "AWS" # source_identifier = "S3_BUCKET_LOGGING_ENABLED" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -170,7 +178,7 @@ resource "aws_config_remediation_configuration" "s3-bucket-level-public-access-p # owner = "AWS" # source_identifier = "S3_BUCKET_POLICY_GRANTEE_CHECK" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -183,7 +191,7 @@ resource "aws_config_remediation_configuration" "s3-bucket-level-public-access-p # owner = "AWS" # source_identifier = "S3_BUCKET_POLICY_NOT_MORE_PERMISSIVE" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -197,7 +205,7 @@ resource "aws_config_config_rule" "s3-bucket-public-read-prohibited" { owner = "AWS" source_identifier = "S3_BUCKET_PUBLIC_READ_PROHIBITED" } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an AWS Config Remediation Configuration. @@ -233,7 +241,7 @@ resource "aws_config_config_rule" "s3-bucket-public-write-prohibited" { owner = "AWS" source_identifier = "S3_BUCKET_PUBLIC_WRITE_PROHIBITED" } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an AWS Config Remediation Configuration. @@ -269,7 +277,7 @@ resource "aws_config_remediation_configuration" "s3-bucket-public-write-prohibit # owner = "AWS" # source_identifier = "S3_BUCKET_REPLICATION_ENABLED" # } -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an AWS Config Rule. @@ -283,7 +291,7 @@ resource "aws_config_config_rule" "s3-bucket-server-side-encryption-enabled" { owner = "AWS" source_identifier = "S3_BUCKET_SERVER_SIDE_ENCRYPTION_ENABLED" } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an AWS Config Remediation Configuration. @@ -323,7 +331,7 @@ resource "aws_config_config_rule" "s3-bucket-ssl-requests-only" { owner = "AWS" source_identifier = "S3_BUCKET_SSL_REQUESTS_ONLY" } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an AWS Config Remediation Configuration. @@ -359,7 +367,7 @@ resource "aws_config_config_rule" "s3-bucket-versioning-enabled" { owner = "AWS" source_identifier = "S3_BUCKET_VERSIONING_ENABLED" } - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an AWS Config Remediation Configuration. @@ -399,5 +407,5 @@ resource "aws_config_remediation_configuration" "s3-bucket-versioning-enabled" { # owner = "AWS" # source_identifier = "S3_DEFAULT_ENCRYPTION_KMS" # } -# tags = var.tags +# tags = local.tags # } diff --git a/modules/aws/recipes/security/config/ssm_automation/main.tf b/modules/aws/recipes/security/config/ssm_automation/main.tf index 4ae1adb..6e3f53b 100644 --- a/modules/aws/recipes/security/config/ssm_automation/main.tf +++ b/modules/aws/recipes/security/config/ssm_automation/main.tf @@ -1,3 +1,16 @@ +#-------------------------------------------------------------- +# Locals +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Provides an IAM role. #-------------------------------------------------------------- @@ -19,7 +32,7 @@ resource "aws_iam_role" "this" { } POLICY path = lookup(var.aws_iam_role, "path", "/") - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Generates an IAM policy document in JSON format for use with resources that expect policy documents such as aws_iam_policy. diff --git a/modules/aws/recipes/security/default_vpc/flow_log.tf b/modules/aws/recipes/security/default_vpc/flow_log.tf index d2f1342..0e712ea 100644 --- a/modules/aws/recipes/security/default_vpc/flow_log.tf +++ b/modules/aws/recipes/security/default_vpc/flow_log.tf @@ -1,3 +1,16 @@ +#-------------------------------------------------------------- +# Locals +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # CloudWatch Log Group for flow log #-------------------------------------------------------------- @@ -6,7 +19,7 @@ resource "aws_cloudwatch_log_group" "this" { name = lookup(var.aws_cloudwatch_log_group, "name") retention_in_days = lookup(var.aws_cloudwatch_log_group, "retention_in_days") kms_key_id = lookup(var.aws_cloudwatch_log_group, "kms_key_id", null) - tags = var.tags + tags = local.tags lifecycle { create_before_destroy = true } @@ -35,7 +48,7 @@ resource "aws_iam_role" "this" { POLICY path = lookup(var.aws_iam_role, "path", "/") force_detach_policies = true - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Generates an IAM policy document in JSON format for use with resources that expect policy documents such as aws_iam_policy. diff --git a/modules/aws/recipes/security/guardduty/main.tf b/modules/aws/recipes/security/guardduty/main.tf index 42b8b58..493c15c 100644 --- a/modules/aws/recipes/security/guardduty/main.tf +++ b/modules/aws/recipes/security/guardduty/main.tf @@ -1,3 +1,16 @@ +#-------------------------------------------------------------- +# Locals +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Provides a resource to manage a GuardDuty detector. #-------------------------------------------------------------- @@ -45,7 +58,7 @@ resource "aws_cloudwatch_event_rule" "this" { EVENT_PATTERN description = lookup(var.aws_cloudwatch_event_rule, "description", "This cloudwatch event used for GuardDuty.") is_enabled = lookup(var.aws_cloudwatch_event_rule, "is_enabled", true) - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an EventBridge Target resource. diff --git a/modules/aws/recipes/security/iam/main.tf b/modules/aws/recipes/security/iam/main.tf index 13e5674..a124912 100644 --- a/modules/aws/recipes/security/iam/main.tf +++ b/modules/aws/recipes/security/iam/main.tf @@ -1,3 +1,16 @@ +#-------------------------------------------------------------- +# Locals +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Manages Password Policy for the AWS Account. See more about Account Password Policy in the official AWS docs. #-------------------------------------------------------------- @@ -38,7 +51,7 @@ resource "aws_iam_role" "this" { assume_role_policy = var.is_enabled ? data.aws_iam_policy_document.this[0].json : null force_detach_policies = true path = lookup(var.aws_iam_role, "path", "/") - tags = var.tags + tags = local.tags } resource "aws_iam_role_policy_attachment" "support_policy" { diff --git a/modules/aws/recipes/security/securityhub/main.tf b/modules/aws/recipes/security/securityhub/main.tf index 52c7ab0..64ba41c 100644 --- a/modules/aws/recipes/security/securityhub/main.tf +++ b/modules/aws/recipes/security/securityhub/main.tf @@ -2,8 +2,16 @@ # Local #-------------------------------------------------------------- locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } region = var.region == null ? data.aws_region.current.name : var.region } +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Current Region #-------------------------------------------------------------- @@ -116,7 +124,7 @@ resource "aws_securityhub_action_target" "this" { # EVENT_PATTERN # description = lookup(var.aws_cloudwatch_event_rule, "description", null) # is_enabled = true -# tags = var.tags +# tags = local.tags # } #-------------------------------------------------------------- # Provides an EventBridge Target resource. diff --git a/modules/aws/recipes/sns/subscription/main.tf b/modules/aws/recipes/sns/subscription/main.tf index c37a73e..605ffd2 100644 --- a/modules/aws/recipes/sns/subscription/main.tf +++ b/modules/aws/recipes/sns/subscription/main.tf @@ -1,3 +1,16 @@ +#-------------------------------------------------------------- +# Locals +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Provides a KMS customer master key. #-------------------------------------------------------------- @@ -55,7 +68,7 @@ POLICY deletion_window_in_days = lookup(var.aws_kms_key, "deletion_window_in_days", 7) is_enabled = lookup(var.aws_kms_key, "is_enabled", true) enable_key_rotation = lookup(var.aws_kms_key, "enable_key_rotation", true) - tags = merge(var.tags, { + tags = merge(local.tags, { Name = lookup(var.aws_kms_key, "alias_name") } ) @@ -90,7 +103,7 @@ resource "aws_sns_topic" "this" { sqs_success_feedback_role_arn = lookup(var.aws_sns_topic, "sqs_success_feedback_role_arn", null) sqs_success_feedback_sample_rate = lookup(var.aws_sns_topic, "sqs_success_feedback_sample_rate", null) sqs_failure_feedback_role_arn = lookup(var.aws_sns_topic, "sqs_failure_feedback_role_arn", null) - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides a resource for subscribing to SNS topics. diff --git a/modules/aws/recipes/synthetics_canary/main.tf b/modules/aws/recipes/synthetics_canary/main.tf new file mode 100644 index 0000000..0f5c701 --- /dev/null +++ b/modules/aws/recipes/synthetics_canary/main.tf @@ -0,0 +1,192 @@ +#-------------------------------------------------------------- +# Locals +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } + set_canary_run_config_command = "aws synthetics update-canary --name ${var.aws_synthetics_canary.name} --run-config '${jsonencode({ TimeoutInSeconds : var.aws_synthetics_canary.run_config[0].timeout_in_seconds, MemoryInMB : var.aws_synthetics_canary.run_config[0].memory_in_mb, ActiveTracing : var.aws_synthetics_canary.run_config[0].active_tracing, EnvironmentVariables : var.aws_synthetics_canary.env })}'" +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + +#-------------------------------------------------------------- +# Provides an IAM role. +#-------------------------------------------------------------- +resource "aws_iam_role" "this" { + count = var.is_enabled && var.aws_synthetics_canary.execution_role_arn == null ? 1 : 0 + description = lookup(var.aws_iam_role, "description", null) + name = lookup(var.aws_iam_role, "name") + assume_role_policy = < v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Provides an EventBridge Rule resource. #-------------------------------------------------------------- @@ -7,7 +20,7 @@ resource "aws_cloudwatch_event_rule" "this" { schedule_expression = lookup(var.aws_cloudwatch_event_rule, "schedule_expression", "cron(*/5 * * * ? *)") description = lookup(var.aws_cloudwatch_event_rule, "description", "Trusted Advisor event rule.") is_enabled = lookup(var.aws_cloudwatch_event_rule, "is_enabled", true) - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Provides an EventBridge Target resource. diff --git a/modules/aws/recipes/vpc/create/flow_log.tf b/modules/aws/recipes/vpc/create/flow_log.tf index 749e174..8fd84f3 100644 --- a/modules/aws/recipes/vpc/create/flow_log.tf +++ b/modules/aws/recipes/vpc/create/flow_log.tf @@ -5,7 +5,7 @@ resource "aws_cloudwatch_log_group" "this" { name = lookup(var.aws_cloudwatch_log_group, "name") retention_in_days = lookup(var.aws_cloudwatch_log_group, "retention_in_days") kms_key_id = lookup(var.aws_cloudwatch_log_group, "kms_key_id", null) - tags = merge(var.tags, { "Name" = lookup(var.aws_cloudwatch_log_group, "name") }) + tags = merge(local.tags, { "Name" = lookup(var.aws_cloudwatch_log_group, "name") }) lifecycle { create_before_destroy = true } @@ -34,7 +34,7 @@ resource "aws_iam_role" "this" { EOF path = lookup(var.aws_iam_role, "path", "/") force_detach_policies = true - tags = var.tags + tags = local.tags } #-------------------------------------------------------------- # Generates an IAM policy document in JSON format for use with resources that expect policy documents such as aws_iam_policy. diff --git a/modules/aws/recipes/vpc/create/main.tf b/modules/aws/recipes/vpc/create/main.tf index 8fe4d69..cf401d9 100755 --- a/modules/aws/recipes/vpc/create/main.tf +++ b/modules/aws/recipes/vpc/create/main.tf @@ -2,8 +2,16 @@ # Locals #-------------------------------------------------------------- locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } name_prefix = trimsuffix(var.name_prefix, "-") } +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Create VPC # https://www.terraform.io/docs/providers/aws/r/vpc.html @@ -13,7 +21,7 @@ resource "aws_vpc" "this" { instance_tenancy = "default" enable_dns_support = "true" enable_dns_hostnames = "true" - tags = merge(var.tags, { "Name" = "${local.name_prefix}-vpc" }) + tags = merge(local.tags, { "Name" = "${local.name_prefix}-vpc" }) } #-------------------------------------------------------------- @@ -22,7 +30,7 @@ resource "aws_vpc" "this" { #-------------------------------------------------------------- resource "aws_internet_gateway" "igw" { vpc_id = aws_vpc.this.id - tags = merge(var.tags, { "Name" = "${local.name_prefix}-igw" }) + tags = merge(local.tags, { "Name" = "${local.name_prefix}-igw" }) } #-------------------------------------------------------------- @@ -34,7 +42,7 @@ resource "aws_subnet" "igw" { cidr_block = var.igw_cidr_block[count.index] availability_zone = var.availability_zone[count.index] map_public_ip_on_launch = true - tags = merge(var.tags, { "Name" = format("%v-igw-subnet-%d", local.name_prefix, count.index + 1) }) + tags = merge(local.tags, { "Name" = format("%v-igw-subnet-%d", local.name_prefix, count.index + 1) }) } #-------------------------------------------------------------- @@ -44,14 +52,14 @@ resource "aws_subnet" "igw" { resource "aws_eip" "nat" { count = length(var.nat_cidr_block) vpc = true - tags = merge(var.tags, { "Name" = format("%v-nat-%d", local.name_prefix, count.index + 1) }) + tags = merge(local.tags, { "Name" = format("%v-nat-%d", local.name_prefix, count.index + 1) }) } resource "aws_nat_gateway" "nat" { count = length(var.nat_cidr_block) allocation_id = element(aws_eip.nat.*.id, count.index) subnet_id = element(aws_subnet.igw.*.id, count.index) - tags = merge(var.tags, { "Name" = format("%v-nat-%d", local.name_prefix, count.index + 1) }) + tags = merge(local.tags, { "Name" = format("%v-nat-%d", local.name_prefix, count.index + 1) }) } #-------------------------------------------------------------- @@ -63,7 +71,7 @@ resource "aws_subnet" "nat" { cidr_block = var.nat_cidr_block[count.index] availability_zone = var.availability_zone[count.index] map_public_ip_on_launch = false - tags = merge(var.tags, { "Name" = format("%v-nat-subnet-%d", local.name_prefix, count.index + 1) }) + tags = merge(local.tags, { "Name" = format("%v-nat-subnet-%d", local.name_prefix, count.index + 1) }) } #-------------------------------------------------------------- @@ -79,7 +87,7 @@ resource "aws_route_table" "private" { cidr_block = "0.0.0.0/0" nat_gateway_id = element(aws_nat_gateway.nat.*.id, count.index) } - tags = merge(var.tags, { "Name" = format("%v-private-routetable-%d", local.name_prefix, count.index + 1) }) + tags = merge(local.tags, { "Name" = format("%v-private-routetable-%d", local.name_prefix, count.index + 1) }) } resource "aws_route_table" "public" { @@ -88,7 +96,7 @@ resource "aws_route_table" "public" { cidr_block = "0.0.0.0/0" gateway_id = aws_internet_gateway.igw.id } - tags = merge(var.tags, { "Name" = format("%v-public-routetable-1", local.name_prefix) }) + tags = merge(local.tags, { "Name" = format("%v-public-routetable-1", local.name_prefix) }) } #-------------------------------------------------------------- diff --git a/modules/aws/recipes/vpc/endpoint/dynamodb/main.tf b/modules/aws/recipes/vpc/endpoint/dynamodb/main.tf index 24544d2..c1bad4d 100644 --- a/modules/aws/recipes/vpc/endpoint/dynamodb/main.tf +++ b/modules/aws/recipes/vpc/endpoint/dynamodb/main.tf @@ -1,3 +1,16 @@ +#-------------------------------------------------------------- +# Locals +#-------------------------------------------------------------- +locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } +} +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Provides a VPC Endpoint resource. #-------------------------------------------------------------- @@ -10,6 +23,6 @@ resource "aws_vpc_endpoint" "this" { private_dns_enabled = var.private_dns_enabled # subnet_ids = var.subnet_ids # security_group_ids = var.security_group_ids - tags = var.tags + tags = local.tags vpc_endpoint_type = "Gateway" } diff --git a/modules/aws/recipes/vpc/subnet/main.tf b/modules/aws/recipes/vpc/subnet/main.tf index 776b4bd..47348e3 100644 --- a/modules/aws/recipes/vpc/subnet/main.tf +++ b/modules/aws/recipes/vpc/subnet/main.tf @@ -2,8 +2,16 @@ # Locals #-------------------------------------------------------------- locals { + tags = { + for k, v in(var.tags == null ? {} : var.tags) : k => v if lookup(data.aws_default_tags.provider.tags, k, null) == null || lookup(data.aws_default_tags.provider.tags, k, null) != v + } name_prefix = trimsuffix(var.name_prefix, "-") } +#-------------------------------------------------------------- +# Use this data source to get the default tags configured on the provider. +#-------------------------------------------------------------- +data "aws_default_tags" "provider" {} + #-------------------------------------------------------------- # Provides an VPC subnet resource. #-------------------------------------------------------------- @@ -14,7 +22,7 @@ resource "aws_subnet" "this" { map_public_ip_on_launch = lookup(var.aws_subnet[count.index], "map_public_ip_on_launch", false) outpost_arn = lookup(var.aws_subnet[count.index], "outpost_arn", null) vpc_id = lookup(var.aws_subnet[count.index], "vpc_id", null) - tags = merge(var.tags, { "Name" = format("%v-subnet-%d", local.name_prefix, count.index + 1) }) + tags = merge(local.tags, { "Name" = format("%v-subnet-%d", local.name_prefix, count.index + 1) }) } #-------------------------------------------------------------- diff --git a/nodejs/node_modules/heartbeat.js b/nodejs/node_modules/heartbeat.js new file mode 100644 index 0000000..5719cdd --- /dev/null +++ b/nodejs/node_modules/heartbeat.js @@ -0,0 +1,102 @@ +const { URL } = require('url'); +const synthetics = require('Synthetics'); +const log = require('SyntheticsLogger'); +const syntheticsConfiguration = synthetics.getConfiguration(); +const syntheticsLogHelper = require('SyntheticsLogHelper'); + +const loadBlueprint = async function () { + const urls = process.env.URLS.split(","); + const statusCodeRanges = process.env.STATUS_CODE_RANGES.split(","); + + // Set screenshot option + const takeScreenshot = true; + + /* Disabling default step screen shots taken during Synthetics.executeStep() calls + * Step will be used to publish metrics on time taken to load dom content but + * Screenshots will be taken outside the executeStep to allow for page to completely load with domcontentloaded + * You can change it to load, networkidle0, networkidle2 depending on what works best for you. + */ + syntheticsConfiguration.disableStepScreenshots(); + syntheticsConfiguration.setConfig({ + continueOnStepFailure: true, + includeRequestHeaders: true, // Enable if headers should be displayed in HAR + includeResponseHeaders: true, // Enable if headers should be displayed in HAR + restrictedHeaders: [], // Value of these headers will be redacted from logs and reports + restrictedUrlParameters: [] // Values of these url parameters will be redacted from logs and reports + + }); + + let page = await synthetics.getPage(); + + for (let i = 0; i < urls.length; ++i) { + await loadUrl(page, urls[i], statusCodeRanges[i], takeScreenshot); + } +}; + +// Reset the page in-between +const resetPage = async function(page) { + try { + await page.goto('about:blank',{waitUntil: ['load', 'networkidle0'], timeout: 30000} ); + } catch(ex) { + synthetics.addExecutionError('Unable to open a blank page ', ex); + } +} + +const loadUrl = async function (page, url, statusCodeRanges, takeScreenshot) { + let stepName = null; + let domcontentloaded = false; + let statusCodeRange = statusCodeRanges.split("-") + try { + stepName = new URL(url).hostname; + } catch (error) { + const errorString = `Error parsing url: ${url}. ${error}`; + log.error(errorString); + /* If we fail to parse the URL, don't emit a metric with a stepName based on it. + It may not be a legal CloudWatch metric dimension name and we may not have an alarms + setup on the malformed URL stepName. Instead, fail this step which will + show up in the logs and will fail the overall canary and alarm on the overall canary + success rate. + */ + throw error; + } + + await synthetics.executeStep(stepName, async function () { + const sanitizedUrl = syntheticsLogHelper.getSanitizedUrl(url); + + /* You can customize the wait condition here. For instance, using 'networkidle2' or 'networkidle0' to load page completely. + networkidle0: Navigation is successful when the page has had no network requests for half a second. This might never happen if page is constantly loading multiple resources. + networkidle2: Navigation is successful when the page has no more then 2 network requests for half a second. + domcontentloaded: It's fired as soon as the page DOM has been loaded, without waiting for resources to finish loading. Can be used and then add explicit await page.waitFor(timeInMs) + */ + const response = await page.goto(url, { waitUntil: ['domcontentloaded'], timeout: 30000}); + if (response) { + domcontentloaded = true; + const status = response.status(); + const statusText = response.statusText(); + + logResponseString = `Response from url: ${sanitizedUrl} Status: ${status} Status Text: ${statusText}`; + + //If the response status code is not a success code + if (response.status() < statusCodeRange[0] || response.status() > statusCodeRange[1]) { + throw `Failed to load url: ${sanitizedUrl} ${response.status()} ${response.statusText()}`; + } + } else { + const logNoResponseString = `No response returned for url: ${sanitizedUrl}`; + log.error(logNoResponseString); + throw new Error(logNoResponseString); + } + }); + + // Wait for 15 seconds to let page load fully before taking screenshot. + if (domcontentloaded && takeScreenshot) { + await page.waitFor(15000); + await synthetics.takeScreenshot(stepName, 'loaded'); + await resetPage(page); + } +}; + +const urls = []; + +exports.handler = async () => { + return await loadBlueprint(); +}; diff --git a/scripts/terraform/integration_push.sh b/scripts/terraform/integration_push.sh index 994b86c..39cd3f7 100755 --- a/scripts/terraform/integration_push.sh +++ b/scripts/terraform/integration_push.sh @@ -4,7 +4,7 @@ DIR=${1:-./} cd $DIR echo "#--------------------------------------------------------------" -echo "# tfenv ($PWD)" +echo "# tfenv install ($PWD)" echo "#--------------------------------------------------------------" tfenv install echo "#--------------------------------------------------------------" diff --git a/terraform/base/main_check_budgets.tf b/terraform/base/main_check_budgets.tf index 8cbf952..e6eb976 100644 --- a/terraform/base/main_check_budgets.tf +++ b/terraform/base/main_check_budgets.tf @@ -4,13 +4,13 @@ #-------------------------------------------------------------- # Provides a resource to manage CloudWatch Rule and CloudWatch Event. #-------------------------------------------------------------- -module "aws_recipes_budgets_budgets" { - source = "../../modules/aws/recipes/budgets" +module "aws_recipes_budgets_create_v4" { + source = "../../modules/aws/recipes/budgets/create-v4" is_enabled = lookup(var.budgets, "is_enabled", true) aws_budgets_budget = { name = "${var.name_prefix}${lookup(var.budgets.aws_budgets_budget, "name", "budgets-monthly")}" budget_type = "COST" - cost_filters = lookup(var.budgets.aws_budgets_budget, "cost_filters", null) + cost_filter = lookup(var.budgets.aws_budgets_budget, "cost_filter", []) cost_types = {} limit_amount = lookup(var.budgets.aws_budgets_budget, "limit_amount") time_unit = lookup(var.budgets.aws_budgets_budget, "time_unit", "MONTHLY") @@ -65,7 +65,7 @@ module "aws_recipes_lambda_create_budgets" { principal = "events.amazonaws.com" qualifier = null source_account = null - source_arn = module.aws_recipes_budgets_budgets.arn + source_arn = module.aws_recipes_budgets_create_v4.arn statement_id = "BudgetsDetectUnexpectedUsage" statement_id_prefix = null } diff --git a/terraform/base/main_common_log.tf b/terraform/base/main_common_log.tf index 1ffb579..d25c13d 100644 --- a/terraform/base/main_common_log.tf +++ b/terraform/base/main_common_log.tf @@ -2,37 +2,43 @@ # Local #-------------------------------------------------------------- locals { - aws_s3_bucket_common = merge(var.common_log.aws_s3_bucket_common, { "bucket" = "${var.name_prefix}${var.common_log.aws_s3_bucket_common.bucket}-${random_id.this.dec}" }) - aws_s3_bucket_cloudtrail = merge(var.common_log.aws_s3_bucket_cloudtrail, { "bucket" = "${var.name_prefix}${var.common_log.aws_s3_bucket_cloudtrail.bucket}-${random_id.this.dec}" }) + aws_s3_bucket_common = merge(var.common_log.aws_s3_bucket_common.aws_s3_bucket, { "bucket" = "${var.name_prefix}${var.common_log.aws_s3_bucket_common.aws_s3_bucket.bucket}-${random_id.this.dec}" }) + aws_s3_bucket_cloudtrail = merge(var.common_log.aws_s3_bucket_cloudtrail.aws_s3_bucket, { "bucket" = "${var.name_prefix}${var.common_log.aws_s3_bucket_cloudtrail.aws_s3_bucket.bucket}-${random_id.this.dec}" }) config_role_names = var.security_config_us_east_1.is_enabled ? [ - module.aws_recipes_security_config_create.config_role_name, + module.aws_recipes_security_config_create_v4.config_role_name, # for CloudFront - module.aws_recipes_security_config_create_us_east_1.config_role_name, + module.aws_recipes_security_config_create_v4_us_east_1.config_role_name, ] : [ - module.aws_recipes_security_config_create.config_role_name, + module.aws_recipes_security_config_create_v4.config_role_name, ] } #-------------------------------------------------------------- # Provides a S3 bucket resource. # For log #-------------------------------------------------------------- -module "aws_recipes_s3_bucket_log_common" { - source = "../../modules/aws/recipes/s3/bucket/log" - bucket = lookup(local.aws_s3_bucket_common, "bucket") - acl = lookup(local.aws_s3_bucket_common, "acl", "log-delivery-write") - tags = var.tags - force_destroy = lookup(local.aws_s3_bucket_common, "force_destroy", false) - versioning = lookup(local.aws_s3_bucket_common, "versioning", [ - { - enabled = true +module "aws_recipes_s3_bucket_log_v4_common" { + source = "../../modules/aws/recipes/s3/bucket/log-v4" + tags = var.tags + + aws_s3_bucket = local.aws_s3_bucket_common + aws_s3_bucket_acl = lookup(var.common_log.aws_s3_bucket_common, "aws_s3_bucket_acl", { + acl = "log-delivery-write" } + ) + aws_s3_bucket_versioning = lookup(var.common_log.aws_s3_bucket_common, "aws_s3_bucket_versioning", { + versioning_configuration = [ + { + status = "Enabled" + mfa_delete = "Disabled" + } ] + } ) - logging = lookup(local.aws_s3_bucket_common, "logging", []) - lifecycle_rule = lookup(local.aws_s3_bucket_common, "lifecycle_rule", []) - replication_configuration = lookup(local.aws_s3_bucket_common, "replication_configuration", []) - server_side_encryption_configuration = lookup(local.aws_s3_bucket_common, "server_side_encryption_configuration", []) - object_lock_configuration = lookup(local.aws_s3_bucket_common, "object_lock_configuration", []) + aws_s3_bucket_logging = lookup(var.common_log.aws_s3_bucket_common, "aws_s3_bucket_logging", null) + aws_s3_bucket_lifecycle_configuration = lookup(var.common_log.aws_s3_bucket_common, "aws_s3_bucket_lifecycle_configuration") + aws_s3_bucket_server_side_encryption_configuration = lookup(var.common_log.aws_s3_bucket_common, "aws_s3_bucket_server_side_encryption_configuration", null) + s3_replication_configuration_role_arn = lookup(var.common_log.aws_s3_bucket_common, "s3_replication_configuration_role_arn", null) + aws_s3_bucket_replication_configuration = lookup(var.common_log.aws_s3_bucket_common, "aws_s3_bucket_replication_configuration", null) } #-------------------------------------------------------------- @@ -41,42 +47,44 @@ module "aws_recipes_s3_bucket_log_common" { #-------------------------------------------------------------- module "aws_recipes_s3_policy_config_common" { source = "../../modules/aws/recipes/s3/policy/config" - bucket = module.aws_recipes_s3_bucket_log_common.id - bucket_arn = module.aws_recipes_s3_bucket_log_common.arn + bucket = module.aws_recipes_s3_bucket_log_v4_common.id + bucket_arn = module.aws_recipes_s3_bucket_log_v4_common.arn account_id = data.aws_caller_identity.current.account_id config_role_names = local.config_role_names depends_on = [ - module.aws_recipes_s3_bucket_log_common + module.aws_recipes_s3_bucket_log_v4_common ] } #-------------------------------------------------------------- # Provides a S3 bucket resource. # For CloudTrail #-------------------------------------------------------------- -module "aws_recipes_s3_bucket_log_cloudtrail" { - source = "../../modules/aws/recipes/s3/bucket/log" - bucket = lookup(local.aws_s3_bucket_cloudtrail, "bucket") - acl = lookup(local.aws_s3_bucket_cloudtrail, "acl", "log-delivery-write") - tags = var.tags - force_destroy = lookup(local.aws_s3_bucket_cloudtrail, "force_destroy", false) - versioning = lookup(local.aws_s3_bucket_cloudtrail, "versioning", [ - { - enabled = true +module "aws_recipes_s3_bucket_log_v4_cloudtrail" { + source = "../../modules/aws/recipes/s3/bucket/log-v4" + tags = var.tags + + aws_s3_bucket = local.aws_s3_bucket_cloudtrail + aws_s3_bucket_acl = lookup(var.common_log.aws_s3_bucket_cloudtrail, "aws_s3_bucket_acl", { + acl = "log-delivery-write" } - ] ) - logging = lookup(local.aws_s3_bucket_cloudtrail, "logging", [ - { - target_bucket = module.aws_recipes_s3_bucket_log_common.id - target_prefix = "AWSLogs/${data.aws_caller_identity.current.account_id}/CloudTrail/AccessLog/" + aws_s3_bucket_versioning = lookup(var.common_log.aws_s3_bucket_cloudtrail, "aws_s3_bucket_versioning", { + versioning_configuration = [ + { + status = "Enabled" + mfa_delete = "Disabled" + } + ] } - ]) - lifecycle_rule = lookup(local.aws_s3_bucket_cloudtrail, "lifecycle_rule", []) - replication_configuration = lookup(local.aws_s3_bucket_cloudtrail, "replication_configuration", []) - server_side_encryption_configuration = lookup(local.aws_s3_bucket_cloudtrail, "server_side_encryption_configuration", []) - object_lock_configuration = lookup(local.aws_s3_bucket_cloudtrail, "object_lock_configuration", []) + ) + aws_s3_bucket_logging = lookup(var.common_log.aws_s3_bucket_cloudtrail, "aws_s3_bucket_logging", null) + aws_s3_bucket_lifecycle_configuration = lookup(var.common_log.aws_s3_bucket_cloudtrail, "aws_s3_bucket_lifecycle_configuration") + aws_s3_bucket_server_side_encryption_configuration = lookup(var.common_log.aws_s3_bucket_cloudtrail, "aws_s3_bucket_server_side_encryption_configuration", null) + s3_replication_configuration_role_arn = lookup(var.common_log.aws_s3_bucket_cloudtrail, "s3_replication_configuration_role_arn", null) + aws_s3_bucket_replication_configuration = lookup(var.common_log.aws_s3_bucket_cloudtrail, "aws_s3_bucket_replication_configuration", null) + depends_on = [ - module.aws_recipes_s3_bucket_log_common, + module.aws_recipes_s3_bucket_log_v4_common, ] } @@ -86,11 +94,11 @@ module "aws_recipes_s3_bucket_log_cloudtrail" { #-------------------------------------------------------------- module "aws_recipes_s3_policy_cloudtrail_cloudtrail" { source = "../../modules/aws/recipes/s3/policy/cloudtrail" - bucket = module.aws_recipes_s3_bucket_log_cloudtrail.id - bucket_arn = module.aws_recipes_s3_bucket_log_cloudtrail.arn + bucket = module.aws_recipes_s3_bucket_log_v4_cloudtrail.id + bucket_arn = module.aws_recipes_s3_bucket_log_v4_cloudtrail.arn account_id = data.aws_caller_identity.current.account_id depends_on = [ - module.aws_recipes_s3_bucket_log_common, - module.aws_recipes_s3_bucket_log_cloudtrail + module.aws_recipes_s3_bucket_log_v4_common, + module.aws_recipes_s3_bucket_log_v4_cloudtrail ] } diff --git a/terraform/base/main_provider.tf.example b/terraform/base/main_provider.tf.example index a87a3d9..41e975f 100644 --- a/terraform/base/main_provider.tf.example +++ b/terraform/base/main_provider.tf.example @@ -6,7 +6,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">=3.70.0" + version = ">=4.0.0" } } backend "s3" { @@ -30,9 +30,15 @@ provider "aws" { profile = "default" # TODO: need to change region. region = "ap-northeast-1" + # default_tags { + # tags = var.tags + # } } # Need to add aws provider(us-east-1) for CloudFront Metric. provider "aws" { region = "us-east-1" alias = "us-east-1" + # default_tags { + # tags = var.tags + # } } diff --git a/terraform/base/main_security_cloudtrail.tf b/terraform/base/main_security_cloudtrail.tf index 44adcff..f747a48 100644 --- a/terraform/base/main_security_cloudtrail.tf +++ b/terraform/base/main_security_cloudtrail.tf @@ -26,7 +26,7 @@ locals { for r in var.security_cloudtrail.aws_cloudwatch_log_metric_filter : { name = "${var.name_prefix}${lookup(r, "name")}" pattern = lookup(r, "pattern", null) - log_group_name = module.aws_recipes_security_cloudtrail.log_group_name + log_group_name = module.aws_recipes_security_cloudtrail_v4.log_group_name metric_transformation = [ { name = "${var.name_prefix}${lookup(r.metric_transformation[0], "name", null)}" @@ -59,7 +59,7 @@ locals { evaluate_low_sample_count_percentiles = lookup(r, "evaluate_low_sample_count_percentiles", null) metric_query = lookup(r, "metric_query", []) extended_statistic = lookup(r, "extended_statistic", null) - alarm_actions = [module.aws_recipes_security_cloudtrail.sns_topic_arn] + alarm_actions = [module.aws_recipes_security_cloudtrail_v4.sns_topic_arn] } ]) aws_sns_topic_cloudtrail = merge(var.security_cloudtrail.aws_sns_topic, { @@ -101,8 +101,8 @@ locals { #-------------------------------------------------------------- # Provides a CloudTrail. #-------------------------------------------------------------- -module "aws_recipes_security_cloudtrail" { - source = "../../modules/aws/recipes/security/cloudtrail" +module "aws_recipes_security_cloudtrail_v4" { + source = "../../modules/aws/recipes/security/cloudtrail-v4" is_enabled = lookup(var.security_cloudtrail, "is_enabled", true) is_s3_enabled = lookup(var.security_cloudtrail, "is_s3_enabled", false) aws_kms_key = local.aws_kms_key_cloudtrail @@ -114,9 +114,9 @@ module "aws_recipes_security_cloudtrail" { # aws_s3_bucket = local.aws_s3_bucket_cloudtrail aws_s3_bucket_existing = { # The S3 bucket id - bucket_id = module.aws_recipes_s3_bucket_log_cloudtrail.id + bucket_id = module.aws_recipes_s3_bucket_log_v4_cloudtrail.id # The S3 bucket arn - bucket_arn = module.aws_recipes_s3_bucket_log_cloudtrail.arn + bucket_arn = module.aws_recipes_s3_bucket_log_v4_cloudtrail.arn } aws_cloudtrail = local.aws_cloudtrail_cloudtrail cis_name_prefix = var.name_prefix @@ -125,7 +125,7 @@ module "aws_recipes_security_cloudtrail" { user = var.deploy_user tags = var.tags depends_on = [ - module.aws_recipes_s3_bucket_log_cloudtrail, + module.aws_recipes_s3_bucket_log_v4_cloudtrail, module.aws_recipes_s3_policy_cloudtrail_cloudtrail ] } @@ -178,7 +178,7 @@ module "aws_recipes_lambda_create_cloudtrail" { principal = "sns.amazonaws.com" qualifier = null source_account = null - source_arn = module.aws_recipes_security_cloudtrail.sns_topic_arn + source_arn = module.aws_recipes_security_cloudtrail_v4.sns_topic_arn statement_id = "CloudTrailDetectUnexpectedUsage" statement_id_prefix = null } diff --git a/terraform/base/main_security_config.tf b/terraform/base/main_security_config.tf index 9e2a24a..9328576 100644 --- a/terraform/base/main_security_config.tf +++ b/terraform/base/main_security_config.tf @@ -30,8 +30,8 @@ locals { #-------------------------------------------------------------- # Provides AWS Config. #-------------------------------------------------------------- -module "aws_recipes_security_config_create" { - source = "../../modules/aws/recipes/security/config/create" +module "aws_recipes_security_config_create_v4" { + source = "../../modules/aws/recipes/security/config/create-v4" is_enabled = lookup(var.security_config, "is_enabled", true) is_s3_enabled = lookup(var.security_config, "is_s3_enabled", false) aws_config_configuration_recorder = local.aws_config_configuration_recorder_config @@ -39,9 +39,9 @@ module "aws_recipes_security_config_create" { # aws_s3_bucket = local.aws_s3_bucket_config aws_s3_bucket_existing = { # The S3 bucket id - bucket_id = module.aws_recipes_s3_bucket_log_common.id + bucket_id = module.aws_recipes_s3_bucket_log_v4_common.id # The S3 bucket arn - bucket_arn = module.aws_recipes_s3_bucket_log_common.arn + bucket_arn = module.aws_recipes_s3_bucket_log_v4_common.arn } aws_config_delivery_channel = local.aws_config_delivery_channel_config aws_config_configuration_recorder_status = lookup(var.security_config, "aws_config_configuration_recorder_status") @@ -75,7 +75,7 @@ module "aws_recipes_security_config_rule_api_gateway" { name_prefix = var.name_prefix tags = var.tags depends_on = [ - module.aws_recipes_security_config_create + module.aws_recipes_security_config_create_v4 ] } #-------------------------------------------------------------- @@ -87,7 +87,7 @@ module "aws_recipes_security_config_rule_rds" { name_prefix = var.name_prefix tags = var.tags depends_on = [ - module.aws_recipes_security_config_create + module.aws_recipes_security_config_create_v4 ] } #-------------------------------------------------------------- @@ -99,7 +99,7 @@ module "aws_recipes_security_config_rule_load_balancer" { name_prefix = var.name_prefix tags = var.tags depends_on = [ - module.aws_recipes_security_config_create + module.aws_recipes_security_config_create_v4 ] } #-------------------------------------------------------------- @@ -113,7 +113,7 @@ module "aws_recipes_security_config_rule_ec2" { is_disable_public_access_for_security_group = lookup(var.security_config.remediation.ec2, "is_disable_public_access_for_security_group", false) tags = var.tags depends_on = [ - module.aws_recipes_security_config_create + module.aws_recipes_security_config_create_v4 ] } #-------------------------------------------------------------- @@ -147,7 +147,7 @@ module "aws_recipes_security_config_rule_s3" { is_configure_s3_bucket_versioning = lookup(var.security_config.remediation.s3, "is_configure_s3_bucket_versioning", false) tags = var.tags depends_on = [ - module.aws_recipes_security_config_create + module.aws_recipes_security_config_create_v4 ] } @@ -188,7 +188,7 @@ module "aws_recipes_lambda_create_config" { principal = "events.amazonaws.com" qualifier = null source_account = null - source_arn = module.aws_recipes_security_config_create.arn + source_arn = module.aws_recipes_security_config_create_v4.arn statement_id = "configDetectUnexpectedUsage" statement_id_prefix = null } diff --git a/terraform/base/main_security_config_us_east_1.tf b/terraform/base/main_security_config_us_east_1.tf index 58a0b5b..a0ceec3 100644 --- a/terraform/base/main_security_config_us_east_1.tf +++ b/terraform/base/main_security_config_us_east_1.tf @@ -23,8 +23,8 @@ locals { #-------------------------------------------------------------- # Provides AWS Config. #-------------------------------------------------------------- -module "aws_recipes_security_config_create_us_east_1" { - source = "../../modules/aws/recipes/security/config/create" +module "aws_recipes_security_config_create_v4_us_east_1" { + source = "../../modules/aws/recipes/security/config/create-v4" providers = { aws = aws.us-east-1 } @@ -35,9 +35,9 @@ module "aws_recipes_security_config_create_us_east_1" { # aws_s3_bucket = local.aws_s3_bucket_config_us_east_1 aws_s3_bucket_existing = { # The S3 bucket id - bucket_id = module.aws_recipes_s3_bucket_log_common.id + bucket_id = module.aws_recipes_s3_bucket_log_v4_common.id # The S3 bucket arn - bucket_arn = module.aws_recipes_s3_bucket_log_common.arn + bucket_arn = module.aws_recipes_s3_bucket_log_v4_common.arn } aws_config_delivery_channel = local.aws_config_delivery_channel_config_us_east_1 aws_config_configuration_recorder_status = lookup(var.security_config_us_east_1, "aws_config_configuration_recorder_status") @@ -65,7 +65,7 @@ module "aws_recipes_security_config_rule_cloudfront_us_east_1" { is_enable_cloudfront_viewer_policy_https = lookup(var.security_config_us_east_1.remediation.cloudfront, "is_enable_cloudfront_viewer_policy_https", false) tags = var.tags depends_on = [ - module.aws_recipes_security_config_create_us_east_1 + module.aws_recipes_security_config_create_v4_us_east_1 ] } @@ -109,7 +109,7 @@ module "aws_recipes_lambda_create_config_us_east_1" { principal = "events.amazonaws.com" qualifier = null source_account = null - source_arn = module.aws_recipes_security_config_create_us_east_1.arn + source_arn = module.aws_recipes_security_config_create_v4_us_east_1.arn statement_id = "configDetectUnexpectedUsage" statement_id_prefix = null } diff --git a/terraform/base/main_security_security_hub.tf b/terraform/base/main_security_security_hub.tf index 53c74a0..1bc9062 100644 --- a/terraform/base/main_security_security_hub.tf +++ b/terraform/base/main_security_security_hub.tf @@ -5,7 +5,9 @@ # Enables Security Hub for this AWS account. #-------------------------------------------------------------- module "aws_recipes_security_securityhub" { - source = "../../modules/aws/recipes/security/securityhub" + source = "../../modules/aws/recipes/security/securityhub" + tags = var.tags + is_enabled = lookup(var.security_securityhub, "is_enabled", true) # aws_securityhub_member aws_securityhub_member = lookup(var.security_securityhub, "aws_securityhub_member", {}) @@ -22,6 +24,6 @@ module "aws_recipes_security_securityhub" { # } depends_on = [ - module.aws_recipes_security_config_create + module.aws_recipes_security_config_create_v4 ] } diff --git a/terraform/base/terraform.example.tfvars b/terraform/base/terraform.example.tfvars index 3341e26..8a4e1c3 100644 --- a/terraform/base/terraform.example.tfvars +++ b/terraform/base/terraform.example.tfvars @@ -711,112 +711,159 @@ common_lambda = { common_log = { # A bucket that mainly stores common logs, such as Config logs and CloudTrail access logs. aws_s3_bucket_common = { - bucket = "aws-log-common" - acl = "log-delivery-write" - force_destroy = true - versioning = [ - { - enabled = true - } - ] - logging = [] - lifecycle_rule = [ - { - id = "default" - abort_incomplete_multipart_upload_days = 7 - enabled = true - prefix = null - expiration = [ - { - # TODO: need to change days. default 3 years. - days = 1095 - expired_object_delete_marker = false - } - ] - transition = [ - { - # TODO: need to change days. default 30 days. - days = 30 - storage_class = "ONEZONE_IA" - } - ] - noncurrent_version_expiration = [ - { - # TODO: need to change days. default 30 days. - days = 30 - } - ] - } - ] - server_side_encryption_configuration = [ - { - rule = [ - { - apply_server_side_encryption_by_default = [ - { - sse_algorithm = "AES256" - kms_master_key_id = null - } - ] - } - ] - } - ] + aws_s3_bucket = { + bucket = "aws-log-common" + force_destroy = true + object_lock_configuration = [] + } + aws_s3_bucket_acl = { + acl = "log-delivery-write" + access_control_policy = [] + expected_bucket_owner = null + } + aws_s3_bucket_versioning = { + versioning_configuration = [ + { + status = "Enabled" + mfa_delete = "Disabled" + } + ] + } + aws_s3_bucket_server_side_encryption_configuration = { + expected_bucket_owner = null + rule = [ + { + apply_server_side_encryption_by_default = [ + { + sse_algorithm = "AES256" + kms_master_key_id = null + } + ] + bucket_key_enabled = null + } + ] + } + aws_s3_bucket_logging = null + aws_s3_bucket_lifecycle_configuration = { + expected_bucket_owner = null + rule = [ + { + abort_incomplete_multipart_upload_days = [ + { + days_after_initiation = 7 + } + ] + expiration = [ + { + date = null + # TODO: need to change days. default 3 years. + days = 1095 + expired_object_delete_marker = false + } + ] + filter = [] + id = "default" + noncurrent_version_expiration = [ + { + newer_noncurrent_versions = null + # TODO: need to change days. default 30 days. + noncurrent_days = 30 + } + ] + noncurrent_version_transition = [] + prefix = null + status = "Enabled" + transition = [ + { + date = null + # TODO: need to change days. default 30 days. + days = 30 + storage_class = "ONEZONE_IA" + } + ] + } + ] + } + s3_replication_configuration_role_arn = null + aws_s3_bucket_replication_configuration = null } # Mainly stores CloudTrail logs. aws_s3_bucket_cloudtrail = { - bucket = "aws-log-cloudtrail" - acl = "log-delivery-write" - force_destroy = true - versioning = [ - { - enabled = true - } - ] - # If you comment out, the log will be automatically set to the common bucket. - # logging = [] - lifecycle_rule = [ - { - id = "default" - abort_incomplete_multipart_upload_days = 7 - enabled = true - prefix = null - expiration = [ - { - # TODO: need to change days. default 3 years. - days = 1095 - expired_object_delete_marker = false - } - ] - transition = [ - { - # TODO: need to change days. default 30 days. - days = 30 - storage_class = "ONEZONE_IA" - } - ] - noncurrent_version_expiration = [ - { - # TODO: need to change days. default 30 days. - days = 30 - } - ] - } - ] - server_side_encryption_configuration = [ - { - rule = [ - { - apply_server_side_encryption_by_default = [ - { - sse_algorithm = "AES256" - kms_master_key_id = null - } - ] - } - ] - } - ] + aws_s3_bucket = { + bucket = "aws-log-cloudtrail" + force_destroy = true + object_lock_configuration = [] + } + aws_s3_bucket_acl = { + acl = "log-delivery-write" + access_control_policy = [] + expected_bucket_owner = null + } + aws_s3_bucket_versioning = { + versioning_configuration = [ + { + status = "Enabled" + mfa_delete = "Disabled" + } + ] + } + aws_s3_bucket_server_side_encryption_configuration = { + expected_bucket_owner = null + rule = [ + { + apply_server_side_encryption_by_default = [ + { + sse_algorithm = "AES256" + kms_master_key_id = null + } + ] + bucket_key_enabled = null + } + ] + } + aws_s3_bucket_logging = null + aws_s3_bucket_lifecycle_configuration = { + expected_bucket_owner = null + rule = [ + { + abort_incomplete_multipart_upload_days = [ + { + days_after_initiation = 7 + } + ] + expiration = [ + { + date = null + # TODO: need to change days. default 3 years. + days = 1095 + expired_object_delete_marker = false + } + ] + filter = [] + id = "default" + noncurrent_version_expiration = [ + { + newer_noncurrent_versions = null + # TODO: need to change days. default 30 days. + noncurrent_days = 30 + } + ] + noncurrent_version_transition = [] + prefix = null + status = "Enabled" + transition = [ + { + date = null + # TODO: need to change days. default 30 days. + days = 30 + storage_class = "ONEZONE_IA" + } + ] + } + ] + } + s3_replication_configuration_role_arn = null + aws_s3_bucket_replication_configuration = null } } #-------------------------------------------------------------- diff --git a/terraform/monitor/.terraform-version b/terraform/monitor/.terraform-version index c24a395..45a1b3f 100644 --- a/terraform/monitor/.terraform-version +++ b/terraform/monitor/.terraform-version @@ -1 +1 @@ -0.14.7 +1.1.2 diff --git a/terraform/monitor/main_common_lambda.tf b/terraform/monitor/main_common_lambda.tf index dee4ba8..c713b95 100644 --- a/terraform/monitor/main_common_lambda.tf +++ b/terraform/monitor/main_common_lambda.tf @@ -93,7 +93,7 @@ module "aws_recipes_sns_subscription_lambda_metric" { aws_sns_topic = local.aws_sns_topic_lambda_metric aws_sns_topic_subscription = { protocol = lookup(var.common_lambda.aws_sns_topic_subscription, "protocol") - endpoint = module.aws_recipes_lambda_create_lambda_log.arn + endpoint = module.aws_recipes_lambda_create_lambda_metric.arn endpoint_auto_confirms = lookup(var.common_lambda.aws_sns_topic_subscription, "endpoint_auto_confirms") confirmation_timeout_in_minutes = lookup(var.common_lambda.aws_sns_topic_subscription, "confirmation_timeout_in_minutes") raw_message_delivery = lookup(var.common_lambda.aws_sns_topic_subscription, "raw_message_delivery") diff --git a/terraform/monitor/main_common_log.tf b/terraform/monitor/main_common_log.tf index a8f1178..4644b3e 100644 --- a/terraform/monitor/main_common_log.tf +++ b/terraform/monitor/main_common_log.tf @@ -2,29 +2,34 @@ # Local #-------------------------------------------------------------- locals { - aws_s3_bucket_application = merge(var.common_log.aws_s3_bucket_application, { "bucket" = "${var.name_prefix}${var.common_log.aws_s3_bucket_application.bucket}-${random_id.this.dec}" }) + aws_s3_bucket = merge(var.common_log.aws_s3_bucket_application.aws_s3_bucket, { "bucket" = "${var.name_prefix}${var.common_log.aws_s3_bucket_application.aws_s3_bucket.bucket}-${random_id.this.dec}" }) } #-------------------------------------------------------------- # Provides a S3 bucket resource. # For application log. #-------------------------------------------------------------- module "aws_recipes_s3_bucket_log_application" { - source = "../../modules/aws/recipes/s3/bucket/log" - bucket = lookup(local.aws_s3_bucket_application, "bucket") - acl = lookup(local.aws_s3_bucket_application, "acl", "private") + source = "../../modules/aws/recipes/s3/bucket/log-v4" tags = var.tags - force_destroy = lookup(local.aws_s3_bucket_application, "force_destroy", false) - versioning = lookup(local.aws_s3_bucket_application, "versioning", [ - { - enabled = true + aws_s3_bucket = local.aws_s3_bucket + aws_s3_bucket_acl = lookup(var.common_log.aws_s3_bucket_application, "aws_s3_bucket_acl", { + acl = "log-delivery-write" } + ) + aws_s3_bucket_versioning = lookup(var.common_log.aws_s3_bucket_application, "aws_s3_bucket_versioning", { + versioning_configuration = [ + { + status = "Enabled" + mfa_delete = "Disabled" + } ] + } ) - logging = lookup(local.aws_s3_bucket_application, "logging", []) - lifecycle_rule = lookup(local.aws_s3_bucket_application, "lifecycle_rule", []) - replication_configuration = lookup(local.aws_s3_bucket_application, "replication_configuration", []) - server_side_encryption_configuration = lookup(local.aws_s3_bucket_application, "server_side_encryption_configuration", []) - object_lock_configuration = lookup(local.aws_s3_bucket_application, "object_lock_configuration", []) + aws_s3_bucket_logging = lookup(var.common_log.aws_s3_bucket_application, "aws_s3_bucket_logging", null) + aws_s3_bucket_lifecycle_configuration = lookup(var.common_log.aws_s3_bucket_application, "aws_s3_bucket_lifecycle_configuration") + aws_s3_bucket_server_side_encryption_configuration = lookup(var.common_log.aws_s3_bucket_application, "aws_s3_bucket_server_side_encryption_configuration", null) + s3_replication_configuration_role_arn = lookup(var.common_log.aws_s3_bucket_application, "s3_replication_configuration_role_arn", null) + aws_s3_bucket_replication_configuration = lookup(var.common_log.aws_s3_bucket_application, "aws_s3_bucket_replication_configuration", null) } #-------------------------------------------------------------- diff --git a/terraform/monitor/main_metric_synthetics_canary.tf b/terraform/monitor/main_metric_synthetics_canary.tf new file mode 100644 index 0000000..0673f78 --- /dev/null +++ b/terraform/monitor/main_metric_synthetics_canary.tf @@ -0,0 +1,16 @@ +#-------------------------------------------------------------- +# For Synthetics Canary metric +#-------------------------------------------------------------- +#-------------------------------------------------------------- +# Provides a CloudWatch Alarm resource. +#-------------------------------------------------------------- +module "aws_recipes_metric_synthetics_canary" { + source = "../../modules/aws/recipes/metric/synthetics_canary" + is_enabled = lookup(var.metric_synthetics_canary, "is_enabled", true) + period = lookup(var.metric_synthetics_canary, "period") + threshold = lookup(var.metric_synthetics_canary, "threshold") + alarm_actions = [module.aws_recipes_sns_subscription_lambda_metric.arn] + dimensions = lookup(var.metric_synthetics_canary, "dimensions") + name_prefix = var.name_prefix + tags = var.tags +} diff --git a/terraform/monitor/main_provider.tf.example b/terraform/monitor/main_provider.tf.example index 732a7d3..a3d5ee2 100644 --- a/terraform/monitor/main_provider.tf.example +++ b/terraform/monitor/main_provider.tf.example @@ -6,7 +6,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">=3.29.1" + version = ">=4.0.0" } } backend "s3" { @@ -30,9 +30,15 @@ provider "aws" { profile = "default" # TODO: need to change region. region = "ap-northeast-1" + # default_tags { + # tags = var.tags + # } } # Need to add aws provider(us-east-1) for CloudFront Metric. provider "aws" { region = "us-east-1" alias = "us-east-1" + # default_tags { + # tags = var.tags + # } } diff --git a/terraform/monitor/main_synthetics_canary.tf b/terraform/monitor/main_synthetics_canary.tf new file mode 100644 index 0000000..c69adfc --- /dev/null +++ b/terraform/monitor/main_synthetics_canary.tf @@ -0,0 +1,31 @@ +#-------------------------------------------------------------- +# For Synthetics Canary +#-------------------------------------------------------------- +locals { + aws_synthetics_canary = merge(var.synthetics_canary.aws_synthetics_canary, { + artifact_s3_location = var.synthetics_canary.aws_synthetics_canary.artifact_s3_location == null ? "s3://${module.aws_recipes_s3_bucket_log_application.id}/" : var.synthetics_canary.aws_synthetics_canaryartifact_s3_location + name = "${var.name_prefix}${var.synthetics_canary.aws_synthetics_canary.name}" + } + ) + aws_iam_role_synthetics_canary = merge(var.synthetics_canary.aws_iam_role, { + name = "${var.name_prefix}${var.synthetics_canary.aws_iam_role.name}" + }) + aws_iam_policy_synthetics_canary = merge(var.synthetics_canary.aws_iam_policy, { + name = "${var.name_prefix}${var.synthetics_canary.aws_iam_policy.name}" + }) + s3_bucket_arn = var.synthetics_canary.aws_synthetics_canary.execution_role_arn == null ? module.aws_recipes_s3_bucket_log_application.arn : null +} +#-------------------------------------------------------------- +#️ Provides a Synthetics Canary resource. +#-------------------------------------------------------------- +module "aws_recipes_synthetics_canary" { + source = "../../modules/aws/recipes/synthetics_canary" + is_enabled = lookup(var.synthetics_canary, "is_enabled", true) + aws_iam_role = local.aws_iam_role_synthetics_canary + account_id = data.aws_caller_identity.current.account_id + region = var.region + s3_bucket_arn = local.s3_bucket_arn + aws_iam_policy = local.aws_iam_policy_synthetics_canary + aws_synthetics_canary = local.aws_synthetics_canary + tags = var.tags +} diff --git a/terraform/monitor/terraform.example.tfvars b/terraform/monitor/terraform.example.tfvars index 4e1f426..967d7e1 100644 --- a/terraform/monitor/terraform.example.tfvars +++ b/terraform/monitor/terraform.example.tfvars @@ -35,57 +35,81 @@ region = "ap-northeast-1" common_log = { # A bucket that mainly stores application logs. aws_s3_bucket_application = { - bucket = "aws-log-application" - acl = "log-delivery-write" - force_destroy = true - versioning = [ - { - enabled = true - } - ] - logging = [] - lifecycle_rule = [ - { - id = "default" - abort_incomplete_multipart_upload_days = 7 - enabled = true - prefix = null - expiration = [ - { - # TODO: need to change days. default 3 years. - days = 1095 - expired_object_delete_marker = false - } - ] - transition = [ - { - # TODO: need to change days. default 30 days. - days = 30 - storage_class = "ONEZONE_IA" - } - ] - noncurrent_version_expiration = [ - { - # TODO: need to change days. default 30 days. - days = 30 - } - ] - } - ] - server_side_encryption_configuration = [ - { - rule = [ - { - apply_server_side_encryption_by_default = [ - { - sse_algorithm = "AES256" - kms_master_key_id = null - } - ] - } - ] - } - ] + aws_s3_bucket = { + bucket = "aws-log-application" + force_destroy = true + object_lock_configuration = [] + } + aws_s3_bucket_acl = { + acl = "log-delivery-write" + access_control_policy = [] + expected_bucket_owner = null + } + aws_s3_bucket_versioning = { + versioning_configuration = [ + { + status = "Enabled" + mfa_delete = "Disabled" + } + ] + } + aws_s3_bucket_server_side_encryption_configuration = { + expected_bucket_owner = null + rule = [ + { + apply_server_side_encryption_by_default = [ + { + sse_algorithm = "AES256" + kms_master_key_id = null + } + ] + bucket_key_enabled = null + } + ] + } + aws_s3_bucket_logging = null + aws_s3_bucket_lifecycle_configuration = { + expected_bucket_owner = null + rule = [ + { + abort_incomplete_multipart_upload_days = [ + { + days_after_initiation = 7 + } + ] + expiration = [ + { + date = null + # TODO: need to change days. default 3 years. + days = 1095 + expired_object_delete_marker = false + } + ] + filter = [] + id = "default" + noncurrent_version_expiration = [ + { + newer_noncurrent_versions = null + # TODO: need to change days. default 30 days. + noncurrent_days = 30 + } + ] + noncurrent_version_transition = [] + prefix = null + status = "Enabled" + transition = [ + { + date = null + # TODO: need to change days. default 30 days. + days = 30 + storage_class = "ONEZONE_IA" + } + ] + } + ] + } + s3_replication_configuration_role_arn = null + aws_s3_bucket_replication_configuration = null } } #-------------------------------------------------------------- @@ -666,3 +690,109 @@ metric_resource_ses = { dimensions = [ ] } +#-------------------------------------------------------------- +# Metric: Synthetics Canary +#-------------------------------------------------------------- +metric_synthetics_canary = { + # TODO: need to set is_enabled for Metric of Synthetics Canary. + is_enabled = true + # TODO: need to set period for Synthetics Canary. + period = 300 + # TODO: need to set threshold for Synthetics Canary. + threshold = { + # (Required) SuccessPercent threshold (unit=Percent) + enabled_success_percent = true + success_percent = 99 + } + # TODO: need to set dimensions for monitor of Synthetics Canary. + # Specify the instance of the target Synthetics Canary Name to be monitored by Map. + # ex) + # dimensions = [ + # { + # "CanaryName" = "base-heartbeat" + # } + # ] + dimensions = [ + { + "CanaryName" = "base-heartbeat" + } + ] +} +#-------------------------------------------------------------- +# Synthetics Canary +#-------------------------------------------------------------- +synthetics_canary = { + # TODO: need to set is_enabled for monitor of Synthetics Canary. + is_enabled = false + aws_iam_role = { + description = "Role for Synthetics Canaly." + name = "monitor-synthetics-canary-role" + path = "/" + } + aws_iam_policy = { + description = "Policy for Synthetics Canaly." + name = "monitor-synthetics-canary-policy" + path = "/" + } + aws_synthetics_canary = { + # Location in Amazon S3 where Synthetics stores artifacts from the test runs of this canary. + # If not specified, the log bucket is automatically specified. + artifact_s3_location = null + # ARN of the IAM role to be used to run the canary. see AWS Docs for permissions needs for IAM Role. + # If not specified, a role policy is automatically created. + execution_role_arn = null + # (Required) Entry point to use for the source code when running the canary. This value must end with the string .handler . + handler = "heartbeat.handler" + # (Required) Name for this canary. Has a maximum length of 21 characters. Valid characters are lowercase alphanumeric, hyphen, or underscore. + name = "heartbeat" + # (Required) Runtime version to use for the canary. Versions change often so consult the Amazon CloudWatch documentation for the latest valid versions. Values include syn-python-selenium-1.0, syn-nodejs-puppeteer-3.0, syn-nodejs-2.2, syn-nodejs-2.1, syn-nodejs-2.0, and syn-1.0. + runtime_version = "syn-nodejs-puppeteer-3.4" + # (Required) Configuration block providing how often the canary is to run and when these test runs are to stop. Detailed below. + schedule = [ + { + expression = "cron(*/5 * * * ? *)" + } + ] + # (Optional) Configuration block. Detailed below. + vpc_config = [] + # (Optional) Number of days to retain data about failed runs of this canary. If you omit this field, the default of 31 days is used. The valid range is 1 to 455 days. + failure_retention_period = 7 + # (Optional) Configuration block for individual canary runs. Detailed below. + run_config = [ + { + timeout_in_seconds = 60 + memory_in_mb = 960 + active_tracing = false + } + ] + # (Optional) Full bucket name which is used if your canary script is located in S3. The bucket must already exist. Specify the full bucket name including s3:// as the start of the bucket name. Conflicts with zip_file. + s3_bucket = null + # (Optional) S3 key of your script. Conflicts with zip_file. + s3_key = null + # (Optional) S3 version ID of your script. Conflicts with zip_file. + s3_version = null + # (Optional) Whether to run or stop the canary. + start_canary = true + # (Optional) Number of days to retain data about successful runs of this canary. If you omit this field, the default of 31 days is used. The valid range is 1 to 455 days. + success_retention_period = 7 + # (Optional) configuration for canary artifacts, including the encryption-at-rest settings for artifacts that the canary uploads to Amazon S3. See Artifact Config. + artifact_config = [ + { + s3_encryption = [ + { + encryption_mode = "SSE-S3" + } + ] + } + ] + # (Optional) ZIP file that contains the script, if you input your canary script directly into the canary instead of referring to an S3 location. It can be up to 5 MB. Conflicts with s3_bucket, s3_key, and s3_version. + # zip -r lambda/outputs/heartbeat.zip ./nodejs/* + zip_file = "../../lambda/outputs/heartbeat.zip" + # TODO: Set the Heartbeat URL and list of acceptable status codes. + # (Optional) URLS/STATUS_CODE_RANGES is an environment variable that can be specified as a delimited string to allow heart beats to be thrown to multiple URLs. + env = { + URLS = "https://yahoo.co.jp/,https://google.com/" + STATUS_CODE_RANGES = "200-299,200-299" + } + } +} diff --git a/terraform/monitor/variables.tf b/terraform/monitor/variables.tf index 64daff2..b1eeb92 100644 --- a/terraform/monitor/variables.tf +++ b/terraform/monitor/variables.tf @@ -15,3 +15,5 @@ variable "metric_resource_elasticache" {} variable "metric_resource_lambda" {} variable "metric_resource_rds" {} variable "metric_resource_ses" {} +variable "metric_synthetics_canary" {} +variable "synthetics_canary" {}