In this example, I will first demonstrate how to conditionally create a terraform resource. Then how to add a configuration block inside a resource conditionally.
Conditional resource
When developing terraform modules, it is desirable to tell the module whether to create a resource based on input variable. Let’s review the following example, which creates a SNS topic.
resource aws_sns_topic sns-topic { name = "cloudtrail-sns" display_name = "cloudtrail-sns" tags = var.default-tags }
To make this optional, we can pass a variable to the module. In this example, the deciding variable is cloudtrail-subscribe-sns. When it is true, count will be assigned a value of 1. When it is false, count will be assigned a value of 0, which means no resource will be created.
resource aws_sns_topic sns-topic { count = var.cloudtrail-subscribe-sns ? 1 : 0 name = "cloudtrail-sns" display_name = "cloudtrail-sns" tags = var.default-tags }
Conditional block
Sometimes, we want to enable certain setting inside a resource. Some settings come in form of a block. So we will need to use dynamic blocks. In this example, cloudtrail will be created with all data events enabled.
resource "aws_cloudtrail" "my-trail" { name = "my-trail" enable_logging = true ... event_selector { read_write_type = "All" include_management_events = true data_resource { type = "AWS::S3::Object" values = ["arn:aws:s3:::"] } data_resource { type = "AWS::Lambda::Function" values = ["arn:aws:lambda"] } } }
AWS offers to log one copy of management events for free. Data events however are not free. My cloudtrail module needs to optionally enable logging of data events. In the code below, 2 dynamic blocks will enable s3 data events and lambda data events, depending on the value of cloudtrail-log-s3-data-events
and cloudtrail-log-lambda-data-events.
resource "aws_cloudtrail" "my-trail" { name = "my-trail" enable_logging = true ... event_selector { read_write_type = "All" include_management_events = true dynamic data_resource { for_each = var.cloudtrail-log-s3-data-events ? [1] : [] content { type = "AWS::S3::Object" values = ["arn:aws:s3:::"] } } dynamic data_resource { for_each = var.cloudtrail-log-lambda-data-events ? [1] : [] content { type = "AWS::Lambda::Function" values = ["arn:aws:lambda"] } } } }
The data_resource blocks are now dynamic blocks. The size of the dynamic block can be empty or 1, depending on the value of the 2 boolean variables. If true, for_each will get an array with 1 element. That means 1 copy of the data_resource block will be created with key values inside content. If false, for_each will get an empty array, which means the dynamic block will not be generated.
Wrapping up
HashiCorp is continuously making improvements. As the engine is refined, you may start to see some resource settings are externalized as additional resources. For example, aws_s3_bucket_versioning is now a dedicated resource instead of a setting inside aws_s3_bucket. This gives developer easy control. Some other resources are controlled by inner config blocks and we will need to make use of dynamic blocks to toggle the settings.