Terraform access map - terraform

I am trying to access all groups and create groups in the below terraform code. But I am facing error This object does not have an attribute named "groups". Is there any logic I am missing here in the resource "og" "example"
for_each=toset(flatten(local.instances[*].groups)). Thanks
locals {
instances = {
test1 = {
baseUrl = "url1"
subDomain = "sd1"
groups = [
"app1",
"app2",
],
}
test2 = {
baseUrl = "url2"
subDomain = "sd2"
groups = [
"t1",
"t2",
],
}
}
}
resource "og" "example" {
for_each = toset(flatten(local.instances[*].groups))
name = each.value
description = "${each.value}-access"
}

Your local variable is a map, not a list. So it should be:
for_each = toset(flatten(values(local.instances)[*].groups))

Related

Terraform - Output a map with key as value of for_each while resource creation

I am trying to solve below :
At first, Create resources based on the entries of the list provided to the resource. Below is the tf code, i have written for it :
resource "azurerm_key_vault" "application_key_vault" {
foreach = toset(var.app_names)
name = "${each.value}-kv"
resource_group_name = azurerm_resource_group.aks_resource_group.name
location = var.location
tenant_id = local.tenant_id
sku_name = "standard"
dynamic "contact" {
for_each = var.key_vault_contact_emails
content {
email = contact.value
}
}
network_acls {
default_action = "Deny"
bypass = "AzureServices"
virtual_network_subnet_ids = local.key_vault_allowed_subnets_set
}
tags = local.all_tags
depends_on = [azurerm_resource_group.aks_resource_group]
}
Now, lets say "app_names" has values ["app1", "app2", "app3"]. And the keyvaults created have ids ["id1", "id2", "id3"].
Is there a way i can create a map of above dynamically , which looks like this :
{
"app1" : "id1",
"app2" : "id2",
"app3" : "id3",
}
I tried using "output" something like this, but not able to figure out how should I get app_name which is used in creation of each keyvault :
output "application_app_name_by_key_vault_id_map" {
value = { for akv in azurerm_key_vault.application_key_vault : <not sure how to get app_name here> => akv.id }
}
Since you are creating the azurerm_key_vault resource with for_each, it acts like any other key value map. In other words, you can do the following:
output "application_app_name_by_key_vault_id_map" {
value = { for k, v in azurerm_key_vault.application_key_vault: k => v.id }
}

Terraform - Reference a for_each resource from another for_each resource

I have a terraform file with the following contents:
resource "aws_iam_group" "developers" {
name = each.value
for_each = toset(var.groups)
}
resource "aws_iam_group_membership" "developers_team" {
name = "Developers Team"
users = [each.value]
for_each = toset(var.group_users)
group = aws_iam_group.developers.name
}
I would like to reference aws_iam_group from aws_iam_group_membership. How would I do that? The current terraform file is not working.
I tried this:
group = aws_iam_group.developers[each.value] //This will not work since it uses the for_each of
its own code block
The variable file is as below:
variable "groups" {
type = list(string)
default = [
"terraform_group1",
"terraform_group2",
"terraform_group3",
]
}
variable "group_users" {
type = list(string)
default = [
"terraform_test_user1",
"terraform_test_user2"
]
}
Edit:
I tried the below, but it is not working
resource "aws_iam_group_membership" "developers_team" {
name = "Developers Team"
users = [for group_user in var.group_users : group_user]
for_each = toset(var.groups)
group = aws_iam_group.developers[each.key]
}
Apparently, this is working:
resource "aws_iam_group" "developer" {
name = "truedeveloper"
}
resource "aws_iam_group_membership" "developers_team" {
name = "Developers_Team"
users = [for group_user in var.group_users : group_user]
for_each = toset(var.groups)
group = aws_iam_group.developer.name
}

It's this possible? - terraform

I will like to create a policy resource depending on how many projects are described. Also, the policy must be different between these projects, for example, I have this far:
projects = ["project1", "project2"]
projects_resources = ["project1/X", "project1/Y", "project2/X", "project2/Y"]
data source:
data "template_file" "project_policy" {
template = file("${path.module}/project_policy.tpl")
vars = {
projects_resources = join(",", var.projects_resources)
}
}
project_policy.tpl:
...
"Resource": [
%{ for projects_resources in slice(split(",", projects_resources), 0, length(split(",", projects_resources))-1) }
"arn:aws:...${projects_resources}}",
%{ endfor }
%{ for projects_resources in slice(split(",", projects_resources), length(split(",", projects_resources))-1, length(split(",", projects_resources))) }
"arn:aws:...${projects_resources}}"
%{ endfor }
policy resource:
resource "aws_iam_policy" "iam_policies_projects" {
count = length(var.projects)
name = "policy_${var.projects[count.index]}"
policy = data.template_file.policy_projects.rendered
}
Current Outcome:
policy_proyect1 and policy_proyect2 created with:
"Resource":
"arn:aws:...proyect1/X",
"arn:aws:...proyect1/Y",
"arn:aws:...proyect2/X",
"arn:aws:...proyect2/Y"
what I would like to achieve:
policy_proyect1 with:
"Resource":
"arn:aws:...proyect1/X",
"arn:aws:...proyect1/Y",
policy_proyect2 with:
"Resource":
"arn:aws:...proyect2/X",
"arn:aws:...proyect2/Y",
I don't know if there is a way to create 2 rendered files for each policy in which only the values that correspond to the projects are passed as arguments.
Thanks!
You can create new local map and then use that for the template:
variable "projects" {
default = ["project1", "project2"]
}
variable "projects_resources" {
default = ["project1/X", "project1/Y", "project2/X", "project2/Y", "project2/Z"]
}
locals {
proj_res_map = {for p in var.projects:
p => [for v in var.projects_resources : v if length(regexall("${p}.*", v)) > 0]
}
}
which gives:
proj_res_map = {
"project1" = [
"project1/X",
"project1/Y",
]
"project2" = [
"project2/X",
"project2/Y",
"project2/Z",
]
}
Then use it:
data "template_file" "project_policy" {
for_each = local.proj_res_map
template = file("${path.module}/project_policy.tpl")
vars = {
projects_resources = join(",", each.value)
}
}
Then iam_policies_projects probably will also need to be adjusted to account for for_each in template_file:
resource "aws_iam_policy" "iam_policies_projects" {
for_each = local.proj_res_map
name = "policy_${each.key}"
policy = data.template_file.policy_projects[each.key].rendered
}

Terraform AWS IAM Iterate Over Rendered JSON Policies

How can I iterate over the JSON rendered data.aws_iam_policy_document documents within an aws_iam_policy?
data "aws_iam_policy_document" "role_1" {
statement {
sid = "CloudFront1"
actions = [
"cloudfront:ListDistributions",
"cloudfront:ListStreamingDistributions"
]
resources = ["*"]
}
}
data "aws_iam_policy_document" "role_2" {
statement {
sid = "CloudFront2"
actions = [
"cloudfront:CreateInvalidation",
"cloudfront:GetDistribution",
"cloudfront:GetInvalidation",
"cloudfront:ListInvalidations"
]
resources = ["*"]
}
}
variable "role_policy_docs" {
type = list(string)
description = "Policies associated with Role"
default = [
"data.aws_iam_policy_document.role_1.json",
"data.aws_iam_policy_document.role_2.json",
]
}
locals {
role_policy_docs = { for s in var.role_policy_docs: index(var.role_policy_docs, s) => s}
}
resource "aws_iam_policy" "role" {
for_each = local.role_policy_docs
name = format("RolePolicy-%02d", each.key)
description = "Custom Policies for Role"
policy = each.value
}
resource "aws_iam_role_policy_attachment" "role" {
for_each = { for p in aws_iam_policy.role : p.name => p.arn }
role = aws_iam_role.role.name
policy_arn = each.value
}
This example has been reduced down to the very basics. The policy documents are dynamically generated with the source_json and override_json conventions. I cannot simply combine the statements into a single policy document.
Terraform Error:
Error: "policy" contains an invalid JSON policy
on role.tf line 35, in resource "aws_iam_policy" "role":
35: policy = each.value
This:
variable "role_policy_docs" {
type = list(string)
description = "Policies associated with Role"
default = [
"data.aws_iam_policy_document.role_1.json",
"data.aws_iam_policy_document.role_2.json",
]
}
Is literally defining those default values as strings, so what you're getting is this:
+ role_policy_docs = {
+ 0 = "data.aws_iam_policy_document.role_1.json"
+ 1 = "data.aws_iam_policy_document.role_2.json"
}
If you tried removing the quotations around the data blocks, it will not be valid because you cannot use variables in default definitions. Instead, assign your policy documents to a new local, and use that local in your for loop instead:
locals {
role_policies = [
data.aws_iam_policy_document.role_1.json,
data.aws_iam_policy_document.role_2.json,
]
role_policy_docs = {
for s in local.role_policies :
index(local.role_policies, s) => s
}
}

How to get Subnet list from VPC with terraform

I've tried to get all subnet ids to add aws batch with terraform with following code:
data "aws_subnet_ids" "test_subnet_ids" {
vpc_id = "default"
}
data "aws_subnet" "test_subnet" {
count = "${length(data.aws_subnet_ids.test_subnet_ids.ids)}"
id = "${tolist(data.aws_subnet_ids.test_subnet_ids.ids)[count.index]}"
}
output "subnet_cidr_blocks" {
value = ["${data.aws_subnet.test_subnet.*.id}"]
}
Fortunately, it was working fine when I've tested like that. But when I tried to integrate with batch terraform like:
resource "aws_batch_compute_environment" "test-qr-processor" {
compute_environment_name = "test-qr-processor-test"
compute_resources {
instance_role = "${aws_iam_instance_profile.test-ec2-role.arn}"
instance_type = [
"optimal"
]
max_vcpus = 256
min_vcpus = 0
security_group_ids = [
"${aws_security_group.test-processor-batch.id}"
]
subnets = ["${data.aws_subnet.test_subnet.*.id}"]
type = "EC2"
}
service_role = "${aws_iam_role.test-batch-service-role.arn}"
type = "MANAGED"
depends_on = [ "aws_iam_role_policy_attachment.test-batch-service-role" ]
}
I've encountered following error message,
Error: Incorrect attribute value type
on terraform.tf line 142, in resource
"aws_batch_compute_environment" "test-processor": 142: subnets =
["${data.aws_subnet.test_subnet.*.id}"]
Inappropriate value for attribute "subnets": element 0: string
required.
Please let me know why, thanks.
"${data.aws_subnet.test_subnet.*.id}" is already string array type.
you should input value without [ ]
write code like :
subnets = "${data.aws_subnet.test_subnet.*.id}"
See :
Here's A document about Resource: aws_batch_compute_environment

Resources