Terraform Resource attribute not being removed when passing in empty values - google-cloud-platform

I am working with a GCP Cloud Composer resource and added in a dynamic block to create an attribute for the resource to set allowed_ip_ranges which can be used as an IP filter for accessing the Apache Airflow Web UI.
I was able to get the allowed ranges setup and can update them in place to new values also.
If I attempt to pass in a blank list I am expecting the IP address(es) to be removed as attributes for the resource but Terraform seems to think that no changes are needed.
There is probably something wrong in my code but I am not sure what exactly I would need to do. Does it involve adding in a conditional expression to the for_each loop in the dynamic block?
Child module main.tf
web_server_network_access_control {
dynamic "allowed_ip_range" {
for_each = var.allowed_ip_range
content {
value = allowed_ip_range.value["value"]
description = allowed_ip_range.value["description"]
}
}
}
Child module variables.tf
variable "allowed_ip_range" {
description = "The IP ranges which are allowed to access the Apache Airflow Web Server UI."
type = list(map(string))
default = []
}
Parent module terraform.tfvars
allowed_ip_range = [
{
value = "11.0.0.2/32"
description = "Test dynamic block 1"
},
]

You can set the default value in your variables.tf file:
variable "allowed_ip_range" {
description = "The IP ranges which are allowed to access the Apache Airflow Web Server UI"
type = list(map(string))
default = [
{
value = "0.0.0.0/0"
description = "Allows access from all IPv4 addresses (default value)"
},
{
value = "::0/0"
description = "Allows access from all IPv6 addresses (default value)"
},
]
}
And when you will delete your variable from terraform.tfvars, you will have the default values

Related

How can terraform loop huge comma separated list counting the first 5 items assigning to dynamic subnet block?

I am trying to create multiple packet mirror resources, using for_each
However in GCP packet mirror policy is restricted to only 5 subnets per policy
Now I am stumped how I can create multiple packet mirror policies referencing lets say from variable mirror_vpc_subnets below
variable "mirror_vpc_subnets" {
description = "Mirror VPC Subnets list to be mirrored."
type = list(string)
default = []
}
Now the objective is to get terraform to loop the huge list in my tfvars below and loop, but cherry picking the 1st 5 then assigning it to the 1st packet mirror resource I want to create called lets say packetmirror1
Then it looks again starting from the next list with appworkstream6-subnet and creates me packetmirror2
Then it looks again starting from the next list with appworkstream11-subnet and creates me packetmirror3
Hope this makes sense...
TFVARS here
mirror_vpc_subnets = [
"projects/gcp_project_name/regions/europe-west2/subnetworks/appworkstream1-subnet",
"projects/gcp_project_name/regions/europe-west2/subnetworks/appworkstream2-subnet",
"projects/gcp_project_name/regions/europe-west2/subnetworks/appworkstream3-subnet",
"projects/gcp_project_name/regions/europe-west2/subnetworks/appworkstream4-subnet",
"projects/gcp_project_name/regions/europe-west2/subnetworks/appworkstream5-subnet"
"projects/gcp_project_name/regions/europe-west2/subnetworks/appworkstream6-subnet",
"projects/gcp_project_name/regions/europe-west2/subnetworks/appworkstream7-subnet",
"projects/gcp_project_name/regions/europe-west2/subnetworks/appworkstream8-subnet",
"projects/gcp_project_name/regions/europe-west2/subnetworks/appworkstream9-subnet",
"projects/gcp_project_name/regions/europe-west2/subnetworks/appworkstream10-subnet"
"projects/gcp_project_name/regions/europe-west2/subnetworks/appworkstream11-subnet",
"projects/gcp_project_name/regions/europe-west2/subnetworks/appworkstream12-subnet",
"projects/gcp_project_name/regions/europe-west2/subnetworks/appworkstream13-subnet",
"projects/gcp_project_name/regions/europe-west2/subnetworks/appworkstream14-subnet",
"projects/gcp_project_name/regions/europe-west2/subnetworks/appworkstream15-subnet"
]
Please advise how this resource can be created in a loop also incrementing the packetmirror name on that creation loop
resource "google_compute_packet_mirroring" "main" {
name = var.packet_mirror_policy_name
project = var.gcp_project_id
region = var.region
network {
url = var.collector_mirror_network_selflink
}
collector_ilb {
url = var.forwarding_rule
}
mirrored_resources {
tags = var.mirrored_tags
dynamic "subnetworks" {
for_each = var.mirror_vpc_subnets
content {
url = subnetworks.value
}
}
dynamic "instances" {
for_each = var.mirror_vpc_instances
content {
url = instances.value
}
}
}

terraform: tfsec not able to read EKS cluster encryption configuration

I have an EKS cluster resource to which the team has added encryption_config, We are adding a dynamic block probably to add multiple configurations. Now when I am trying to run tfsec ( version 1.28.0 ) on my code I get a Cluster does not have secret encryption enabled.
Here is the dynamic block
resource "aws_eks_cluster" "this" {
...
dynamic "encryption_config" {
for_each = toset(var.cluster_encryption_config)
content {
provider {
key_arn = encryption_config.value["provider_key_arn"]
}
resources = encryption_config.value["resources"]
}
}
}
definition inside variables.tf
variable "cluster_encryption_config" {
description = "Configuration block with encryption configuration for the cluster. See examples/secrets_encryption/main.tf for example format"
type = list(object({
provider_key_arn = string
resources = list(string)
}))
default = []
}
From what you write cluster_encryption_config is set to empty list []. Therefore, encryption_config block does not run, and there is no encryption configured. You have to setup cluster_encryption_config to something with valid values (not an empty list).

Nesting for_each loops and configuring multiple regions in Python

We have a long(ish) list of ip addresses to trust, for services published by CloudFlare, and rather than asking each team that publishes a service from an account in aws to implement this in their security groups / acls etc. I thought a prefix list would be perfect. I would like to set this up in a central account, that is then shared to all the child accounts across the aws Organisation. Ideally, I would like to avoid declaring more resources than necessary, so I am using for_each loops and a dynamic entry. So far so good.
However, prefix lists are not a global object, meaning they need to be created per region, and Terraform requires that this is set on the Provider level.
Is there a way to have a single resource declaration work with a single local map to dynamically manage all these moving parts?
It seems the fewest steps I can do, is to have a resource declaration per region, and then a local map per provider, which is already making 6 "blocks" for only 3 regions, + 2 lists for ipv4 and ipv6...
Here's the code example:
locals {
# The two ip lists to add to appropriate prefix lists
cloudflare-ips = {
prefixlist_cloudflare_ipv4 = {
ips = [
"10.0.0.0/32",
"173.245.48.0/20",
...
],
type = "IPv4",
},
prefixlist_cloudflare_ipv6 = {
ips = [
"2400:cb00::/32",
"2606:4700::/32",
...
],
type = "IPv6",
}
}
}
# Generate multipel predix lists from the map of ipv4 and ipv6 addresses
resource "aws_ec2_managed_prefix_list" "cloudflare-ipv4" {
for_each = local.cloudflare-ips
name = "cloudflare_${each.value.type}"
# Here is where I have to add a provider for the region, and this cannot be done within any type of loop ?
provider = aws.ap-southeast-1
address_family = each.value.type
max_entries = 50
dynamic "entry" {
for_each = tolist( each.value.ips )
content {
cidr = entry.value
description = "CloudFlare ${entry.key}"
}
}
}
I've tried including a list of strings with region / provider names and calling these directly from inside the loop, but even though it can evaluate a string (e.g. provider = "aws.ap-southeast-1") it does not accept reading from the local map like so:
provider = each.value.region
with error:
│ The provider argument requires a provider type name, optionally followed by a period and then a configuration alias.
I guess the next step would be to make this into a module ? Any other suggestions... ?
this cannot be done within any type of loop
That's correct. You can't have dynamic provider, thus you can't use any loops and variables. Its value must be hardcoded.

Terraform aws_wafv2_ip_set delete ip on apply

I have a resource aws_wafv2_ip_set that is used by many different modules.
variable "addresses" {
type = set(string)
default = []
}
resource "aws_wafv2_ip_set" "ip_set" {
ip_address_version = "IPV4"
name = var.name
scope = "REGIONAL"
addresses = var.addresses
}
I need to create different ip sets that will be filled by a dynamic script from our admin section or directly from AWS console (not from terraform).
The problem is that every single apply detect that the ip set is not empty (like the var address), and so it delete all ip address added by console or by script.
How can I add aws_wafv2_ip_set without delete ip address on apply?
Thank you
According to the docs, adresses is an array of strings and is required.
Why don't you just go with the tf example:
resource "aws_wafv2_ip_set" "ip_set" {
name = "example"
description = "Example IP set"
scope = "REGIONAL"
ip_address_version = "IPV4"
addresses = ["YOUR_IP_1", "YOUR_IP_2"]
}

GCP Terraform Forwarding Rule Target

Hey Terraform friends;
Trying to navigate my way through some basic load balancing in the GCP environment. First time doing it, so, still trying to pick up on some of the nuances between the various types and environments.
My goal is to have a target pool of hosts be the destination recipient for connections made to the forwarding rule, in whatever load balancing policy the business needs.
The setup is a bit awkward, because I have the project that I'm doing the work in, but the destination subnetworks are in a shared VPC in another project. Now, according to powers that implemented, the project has permissions to use that subnetwork, which, so far is accurate (I've deployed compute instances to it).
Here's my code:
#target pool
resource "google_compute_target_pool" "target_pool" {
name = "${var.name}-pool"
instances = var.instances
session_affinity = var.session_affinity
}
resource "google_compute_address" "lb_address" {
name = "${var.name}-load-balancer"
address_type = "INTERNAL"
address = "10.129.48.250" //cause fuck it I'm trying to figure it out
subnetwork = data.google_compute_subnetwork.gcp_subnetwork.name
project = var.subnetwork_project
}
#load balancer
resource "google_compute_forwarding_rule" "basic_load_balancer" {
name = var.name
target = google_compute_target_pool.target_pool.id
ip_address = google_compute_address.lb_address.address
port_range = join(",", var.port_range)
labels = var.labels
subnetwork = data.google_compute_subnetwork.gcp_subnetwork.name
project = var.subnetwork_project
load_balancing_scheme = var.lb_scheme
}
With the relevant data:
data "google_compute_subnetwork" "gcp_subnetwork" {
name = var.subnetwork
project = var.subnetwork_project
}
And variables:
variable "name" {
description = "Name of the application usage"
type = string
}
variable "port_range" {
description = "List of ports to load balance"
}
variable "port_range_health" {
description = "List of ports to health check"
type = list(string)
default = [ "" ]
}
variable "instances" {
description = "List of Instances by Zone/Name value"
type = list(string)
}
variable "backup_instances" {
description = "List of Instances by Zone/Name value for backup use"
type = list(string)
default = []
}
variable "session_affinity" {
description = "Load balancer session affinity type"
type = string
default = "NONE"
}
variable "labels" {
description = "Labels to apply to the load balancer"
type = map
default = {}
}
variable "lb_scheme" {
description = "What the LB Forwarding rule is to be used for"
type = string
default = "INTERNAL"
}
variable "subnetwork" {
description = "What network the load balancer should be deployed into"
type = string
}
variable "subnetwork_project" {
description = "Project that contains the subnetwork to deploy into"
type = string
default = ""
}
variable "project" {
description = "Project supplied by user"
type = string
}
My subnetwork project is set to the project id of my shared VPC, and I specify the name of the subnetwork. Instance
And when I try to apply, I keep getting hit with an error message about the structure of the target:
Error: Error creating ForwardingRule: googleapi: Error 400: Invalid value for field 'resource.target': 'projects/insight-dev-272215/regions/us-central1/targetPools/insight-dev-pool'. The URL is malformed. Must be a valid In-Project Target Proxy URL or a supported Google API bundle., invalid
│
│ with module.insight_solr_lb.google_compute_forwarding_rule.basic_load_balancer,
│ on ..\..\..\modules\load_balancer\gcp\basic\main.tf line 29, in resource "google_compute_forwarding_rule" "basic_load_balancer":
│ 29: resource "google_compute_forwarding_rule" "basic_load_balancer" {
│
I've beaten my head around a few times for a few things, but I'm not making much progress. Anyone experienced in the GCP Forwarding rules see my issue?
I've tried to pass the URI of the target group to the target, but it didn't like that either.
Thanks!