How to create if statement in Terraform for LogicApps - azure

I'm creating LogicApps with Terraform. Logic Apps will do webhook and I would like to post text.
I would like to customize text field of Terraform code with If statement.
I would like to certain part of text to be displayed at only prod environment.
However my terraform code with pass entire if statement to LogicApps and I get payload error with LogicApps execution.
resource "azurerm_logic_app_action_http" "example" {
name = "webhook"
logic_app_id = azurerm_logic_app_workflow.example.id
method = "GET"
uri = "http://example.com/some-webhook"
method = "POST"
headers = { "Content-Type" = "application/json" }
body = <<-BODY
{
"blocks": [
{
"text": {
"text": "[${var.environment_name}] == "prod" ? *This is prod alert* : *---*",
"type": "mrkdwn"
}
}

You can use conditions in your BODY as follows:
body = <<-BODY
{
"blocks": [
{
"text": {
"text": "Alert: ${var.environment_name == "prod" ? "*This is prod alert*" : "*---*"}",
"type": "mrkdwn"
}
}
BODY

Related

Appending values to a JSON key with terraform?

I am quite new to terraform. I have a provider that will accept JSON as input.
I have stored JSON config files in my project folder, eg:
{
"id": 58187729,
"name": "My dashboard",
"tags": ["mytag1", "mytag2"]
}
and load them into the resource with the below code:
resource "datadog_monitor_json" "monitor_json" {
for_each = fileset(path.module, "/monitors/*.json")
monitor = file("${path.module}/${each.key}")
}
Is there anyway I can easily append to the "tags" key or will the entire JSON need parsing somehow?
Thanks.
Here is an example on how to add extra tags:
locals {
example = jsondecode(file("${path.module}/myfile.json"))
with_extra_tags = merge(local.example,
{tags = concat(
local.example["tags"],["mytag4", "mytag3"])})
}
gives:
test = {
"id" = 58187729
"name" = "My dashboard"
"tags" = [
"mytag1",
"mytag2",
"mytag4",
"mytag3",
]
}

locals.tf file - parsing jsonencode body

Wondering if anyone has ran tackled it. So, I need to be able to generate list of egress CIDR blocks that is currently available for listing over an API. Sample output is the following:
[
{
"description": "blahnet-public-acl",
"metadata": {
"broadcast": "192.168.1.191",
"cidr": "192.168.1.128/26",
"ip": "192.168.1.128",
"ip_range": {
"start": "192.168.1.128",
"end": "192.168.1.191"
},
"netmask": "255.255.255.192",
"network": "192.168.1.128",
"prefix": "26",
"size": "64"
}
},
{
"description": "blahnet-public-acl",
"metadata": {
"broadcast": "192.168.160.127",
"cidr": "192.168.160.0/25",
"ip": "192.168.160.0",
"ip_range": {
"start": "192.168.160.0",
"end": "192.168.160.127"
},
"netmask": "255.255.255.128",
"network": "192.168.160.0",
"prefix": "25",
"size": "128"
}
}
]
So, I need convert it to Azure Firewall
###############################################################################
# Firewall Rules - Allow Access To TEST VMs
###############################################################################
resource "azurerm_firewall_network_rule_collection" "azure-firewall-azure-test-access" {
for_each = local.egress_ips
name = "azure-firewall-azure-test-rule"
azure_firewall_name = azurerm_firewall.public_to_test.name
resource_group_name = var.resource_group_name
priority = 105
action = "Allow"
rule {
name = "test-access"
source_addresses = local.egress_ips[each.key]
destination_ports = ["43043"]
destination_addresses = ["172.16.0.*"]
protocols = [ "TCP"]
}
}
So, bottom line is that allowed IP addresses have to be a list of strings for the "source_addresses" parameter, such as this:
["192.168.44.0/24","192.168.7.0/27","192.168.196.0/24","192.168.229.0/24","192.168.138.0/25",]
I configured data_sources.tf file:
data "http" "allowed_networks_v1" {
url = "https://testapiserver.com/api/allowed/networks/v1"
}
...and in locals.tf, I need to configure
locals {
allowed_networks_json = jsondecode(data.http.allowed_networks_v1.body)
egress_ips = ...
}
...and that's where I am stuck. How can parse that data in locals.tf file so I can reference it from within TF ?
Thanks a metric ton!!
I'm assuming that the list of string you are referring to are the objects under: metadata.cidr we can extract that with a for loop in a local, and also do a distinct just in case we get duplicates.
Here is a sample code
data "http" "allowed_networks_v1" {
url = "https://raw.githack.com/heldersepu/hs-scripts/master/json/networks.json"
}
locals {
allowed_networks_json = jsondecode(data.http.allowed_networks_v1.body)
distinct_cidrs = distinct(flatten([
for key, value in local.allowed_networks_json : [
value.metadata.cidr
]
]))
}
output "data" {
value = local.distinct_cidrs
}
and here is the output of a plan on that:
terraform plan
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
Terraform will perform the following actions:
Plan: 0 to add, 0 to change, 0 to destroy.
Changes to Outputs:
+ data = [
+ "192.168.1.128/26",
+ "192.168.160.0/25",
]
Here is the code for your second sample:
data "http" "allowed_networks_v1" {
url = "https://raw.githack.com/akamalov/testfile/master/networks.json"
}
locals {
allowed_networks_json = jsondecode(data.http.allowed_networks_v1.body)
distinct_cidrs = distinct(flatten([
for key, value in local.allowed_networks_json.egress_nat_ranges : [
value.metadata.cidr
]
]))
}
output "data" {
value = local.distinct_cidrs
}

Failed to create AWSConfig rule: InvalidParameterValueException: Blank spaces are not acceptable for input parameter: threshold

I am trying to create an aws config rule for checking that cloudtrail alarms are enabled. I get the following error Error: Error creating AWSConfig rule: Failed to create AWSConfig rule: InvalidParameterValueException: Blank spaces are not acceptable for input parameter: threshold. when I run terraform apply. I'm not sure what the formatting issue is in the input parameters argument (see input_parameters). The apply works if I remove everything except for metricName i.e
input_parameters = "{\"metricName\":\"CloudTrailConfigChanges\"}"
Any help would be greatly appreciated.
resource aws_config_config_rule ensure-log-alarm-exists-for-cloudtrail {
name = "ensure-log-alarm-exists-for-cloudtrail"
description = "Checks whether cloudwatch alarm is on for cloudtrail configuration changes"
source {
owner = "AWS"
source_identifier = "CLOUDWATCH_ALARM_SETTINGS_CHECK"
}
input_parameters = "{\"metricName\":\"CloudTrailConfigChanges\",\"threshold\":1,\"evaluationPeriod\":1,\"period\":300,\"comparisionOperator\":\"GreaterThanOrEqualToThreshold\",\"statistic\":\"Sum\"}"
}
It seems like there is an issue parsing type ints from json strings: https://github.com/hashicorp/terraform-provider-aws/issues/773#issuecomment-385454229
I get the same error even with
input_parameters =<<EOF
{
"metricName":"CloudTrailConfigChanges",
"threshold":1
}
EOF
or
input_parameters = jsonencode({"metricName":"CloudTrailConfigChanges","threshold"=1})
Converting wrapping the int value in quotes does not work either.
resource "aws_config_config_rule" "ensure-log-alarm-exists-for-cloudtrail" {
name = "ensure-log-alarm-exists-for-cloudtrail"
description = "Checks whether cloudwatch alarm is on for cloudtrail configuration changes"
source {
owner = "AWS"
source_identifier = "CLOUDWATCH_ALARM_SETTINGS_CHECK"
}
input_parameters = jsonencode({
metricName = "CloudTrailConfigChanges"
threshold = "1"
})
}
The code above produces the following error:
Unknown parameters provided in the inputParameters:
With your examples you're still specifying the threshold as an integer. Try making it a string.
resource "aws_config_config_rule" "ensure-log-alarm-exists-for-cloudtrail" {
name = "ensure-log-alarm-exists-for-cloudtrail"
description = "Checks whether cloudwatch alarm is on for cloudtrail configuration changes"
source {
owner = "AWS"
source_identifier = "CLOUDWATCH_ALARM_SETTINGS_CHECK"
}
input_parameters = jsonencode({
metricName = "CloudTrailConfigChanges"
threshold = "1"
})
}
I ran into an error like this, and what resolved it for me was to add a condition. I don't fully understand why this worked and why it caused this error without the condition, but I saw the condition used in an AWS example.
For example, I first tried using something straightforward like this to reference a parameter:
"InputParameters": {
"appNames": {
"Ref": "ApplicationNames"
}
}
When my resource referenced the ApplicationNames parameter directly like this, it was giving that error. But using Conditions and referencing the parameter this way caused it to work, as in this full template example:
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Just a stripped-down example",
"Parameters": {
"ApplicationNames": {
"Type": "String",
"Default": "This Has Spaces",
"MinLength": "1",
"ConstraintDescription": "This parameter is required."
}
},
"Conditions": {
"ApplicationNamesDefined": {
"Fn::Not": [
{
"Fn::Equals": [
"",
{
"Ref": "ApplicationNames"
}
]
}
]
}
},
"Resources": {
"SampleRule": {
"Type": "AWS::Config::ConfigRule",
"DependsOn": "SecurityHubCustomUpdaterFunction",
"Properties": {
"ConfigRuleName": "TheName",
"Description": "It was here that I was getting 'Blank spaces are not acceptable for input parameter: applicationNames' before I added the Conditions and Fn::If to reference it",
"InputParameters": {
"appNames": {
"Fn::If": [
"ApplicationNamesDefined",
{
"Ref": "ApplicationNames"
},
{
"Ref": "AWS::NoValue"
}
]
}
},
"Scope": {
"ComplianceResourceTypes": [
"AWS::SSM::ManagedInstanceInventory"
]
},
"Source": {
"Owner": "AWS",
"SourceIdentifier": "EC2_MANAGEDINSTANCE_APPLICATIONS_REQUIRED"
}
}
}
}
}
So you may want to try with Conditions usage.

How do I make my data template file recognise a number in terraform

THe problem I am facing now is this. I am trying to make my policy more flexible. So I shifted them into a file instead of using EOF.
How to make the template file recognise a number value?
"${max_untagged_images}" and "${max_tagged_images}" are suppose to be numbers.
Aws lifecycle policy:
resource "aws_ecr_lifecycle_policy" "lifecycle" {
count = length(aws_ecr_repository.repo)
repository = aws_ecr_repository.repo[count.index].name
depends_on = [aws_ecr_repository.repo]
policy = var.policy_type == "app" ? data.template_file.lifecycle_policy_app.rendered : data.template_file.lifecycle_policy_infra.rendered
}
Data template:
data "template_file" "lifecycle_policy_app" {
template = file("lifecyclePolicyApp.json")
vars = {
max_untagged_images = var.max_untagged_images
max_tagged_images = var.max_tagged_images
env = var.env
}
}
Policy:
{
"rules": [
{
"rulePriority": 1,
"description": "Expire untagged images older than ${max_untagged_images} days",
"selection": {
"tagStatus": "untagged",
"countType": "sinceImagePushed",
"countUnit": "days",
"countNumber": "${max_untagged_images}"
},
"action": {
"type": "expire"
}
},
{
"rulePriority": 2,
"description": "Expire tagged images of ${env}, older than ${max_tagged_images} days",
"selection": {
"tagStatus": "tagged",
"countType": "imageCountMoreThan",
"countNumber": "${max_tagged_images}",
"tagPrefixList": [
"${env}"
]
},
"action": {
"type": "expire"
}
}
]
}
I would try the following 2 steps:
Remove the double quotes that around the "${max_tagged_images}"
Use terraform function called tonumber in order to convert it to a number:
tonumber("1")
(Follow the official documentation: https://www.terraform.io/docs/configuration/functions/tonumber.html)

Terraform - Passing type Object as a parameter to Azure Template Deployment

I am tying to to provision Azure AD Domain Service using Terraform by giving Terraform the Azure ARM template, this is because Terrafrom does not support provisioning Azure AD Domain Service natively.
I have exported the ARM Template and it's parameters, one of the parameters is called "notificationSettings" which is a type Object and looks like below :
"notificationSettings": {
"value": {
"notifyGlobalAdmins": "Enabled",
"notifyDcAdmins": "Enabled",
"additionalRecipients": []
}
}
Other parameters are all strings and I can pass them without any issue, for example:
"apiVersion" = "2017-06-01"
I have tried passing this object to parameters like below :
"notificationSettings" = [{
"notifyGlobalAdmins" = "Enabled"
"notifyDcAdmins" ="Enabled"
"additionalRecipients" = []
}]
However, when I execute terrafrom apply, terrafrom complains and say:
Inappropriate value for attribute "parameters": element
"notificationSettings": string required.
How do I pass parameters type of Object to template body?
I have also tried giving the entire ARM json parameter as a file to terrafrom by using parameters_body option like below :
parameters_body = "${file("${path.module}/temp/params.json")}"
however, I am getting the followig error when executing the terrafrom script:
The request content was invalid and could not be deserialized: 'Error
converting value
"https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#"
to type
'Microsoft.WindowsAzure.ResourceStack.Frontdoor.Data.Definitions.DeploymentParameterDefinition'.
Path 'properties.parameters.$schema', line 1, position 2952.'.
Below is the params.json file:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"apiVersion": {
"value": "2017-06-01"
},
"sku": {
"value": "Standard"
"location": {
"value": "westus"
},
"notificationSettings": {
"value": {
"notifyGlobalAdmins": "Enabled",
"notifyDcAdmins": "Enabled",
"additionalRecipients": []
}
},
"subnetName": {
"value": "xxxx"
},
"vnetName": {
"value": "xxxx"
},
"vnetAddressPrefixes": {
"value": [
"10.0.1.0/24"
]
},
"subnetAddressPrefix": {
"value": "10.0.1.0/24"
},
"nsgName": {
"value": "xxxxx"
}
}
}
There is a way to pass arbitrary data structures from Terraform to ARM.
There are two ways to pass data to the ARM template within the azure_template_deployment provider
use the parameters block, which is limited to string parameters only
use the parameters_body block, which is pretty much arbitrary JSON.
I find the easiest way to use the parameters block is to create a local variable with the structure I require, then call jsonencode on it. I also like to keep the ARM template in a separate file and pull it in via a file() call, reducing the complexity of the terraform.
locals {
location = "string"
members = [
"array",
"of",
"members"
]
enabled = true
tags = {
"key" = "value",
"simple" = "store"
}
# this is the format required by ARM templates
parameters_body = {
location = {
value = "${local.location}"
},
properties = {
value = {
users = {
members = "${local.members}"
}
boolparameter = "${local.enabled}"
}
}
tags = {
value = "${module.global.tags}"
}
}
}
resource "azurerm_template_deployment" "sample" {
name = "sample"
resource_group_name = "rg"
deployment_mode = "Incremental"
template_body = "${file("${path.module}/arm/sample_arm.json")}"
parameter_body = "${jsonencode(local.parameters_body)}"
}
The only caveat I've found is that the bool parameters pass as a string, so declare them as a string in the ARM parameters section, then use a ARM function to convert to bool
"parameters: {
"boolParameter": {
"type": "string"
}
},
"variables": {
"boolVariable": "[bool(parameters('boolParameter'))]"
},
"resources": [
...
"boolArm": "[variables('boolVariable')]",
...
]

Resources