25
loading...
This website collects cookies to deliver better user experience
jsondecode()
. Documentation here. This interprets a given string as JSON
from the documentation. But, the most important part is that jsondecode
maps JSON values to Terraform language values. Meaning, you can now use loops, store specific values in maps and arrays, or anything you can think of using HCL (the language of Terraform). {
"users": [
{
"user_name": "user_1",
"role": "admin",
"ssh_key": "ssh-rsa [shortened]"
},
{
"user_name": "user_2",
"role": "dev",
"ssh_key": "ssh-rsa [shortened]"
},
{
"user_name": "user_3",
"role": "read_only",
"ssh_key": "ssh-rsa [shortened]"
},
{
"user_name": "user_4",
"role": "dev",
"ssh_key": "ssh-rsa [shortened]"
}
]
}
main.tf
file and a users.json
file that hosts the above JSON. Within the Terraform file, add the following block:locals {
# get json
user_data = jsondecode(file("${path.module}/users.json"))
# get all users
all_users = [for user in local.user_data.users : user.user_name]
}
output "users" {
value = local.all_users
}
terraform init
and then terraform plan
! It should output something like this:Changes to Outputs:
+ users = [
+ "user_1",
+ "user_2",
+ "user_3",
+ "user_4",
]
terraform.tfvars
file that will automatically hold environment variables. Here is the content of the file that can be added:users = {
"users": [
{
"user_name": "user_1",
"role": "admin",
"ssh_key": "ssh-rsa [shortened]"
},
{
"user_name": "user_2",
"role": "dev",
"ssh_key": "ssh-rsa [shortened]"
},
{
"user_name": "user_3",
"role": "read_only",
"ssh_key": "ssh-rsa [shortened]"
},
{
"user_name": "user_4",
"role": "dev",
"ssh_key": "ssh-rsa [shortened]"
}
]
}
main.tf
can be replaced with the following:locals {
uniq_dev_roles = distinct(
[for user in var.users.users : user.role]
)
}
variable "users" {}
output "roles" {
value = local.uniq_dev_roles
}
terraform plan -var-file="terraform.tfvars"
terraform plan
load variable values from the given file, in addition to the default files terraform.tfvars...
So you'll only need to pass in the file name if it's different. A common pattern could be something like this: prod.terraform.tfvars
, staging.terraform.tfvars
, testing.terraform.tfvars
.admin
, dev
, and read_only
.users
is now where the user json is located. As you can see in the for loop, we are now looping over var.users.users
. This is because we are no longer parsing a file and instead parsing a variable. In our case, we are not stating a type so Terraform is inherently inferring the types of the object. Because it interprets users as an array still, we are able to loop over it. main.tf
file for a functional example (in my own local dev environment) of utilizing an S3 bucket:terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 3.0"
}
}
}
provider "aws" {
region = "us-west-2"
profile = "shannon" # change this to your own aws credentials or profile
}
# use a data object instead of a resource
data "aws_s3_bucket_object" "user_access_data" {
bucket = "shannon-terraform"
key = "user_access/users.json"
}
locals {
user_data = jsondecode(data.aws_s3_bucket_object.user_access_data.body)
users = [for user in local.user_data.users: user.user_name]
}
# create an IAM user for each user found in the JSON
resource "aws_iam_user" "user" {
for_each = toset(local.users)
name = each.value
}
for_each
to loop over the users from the JSON in order to create an IAM user for each one. Because it's a list of strings, we'll specifically need to wrap it in toset()
. Docs on how to use for_each
can be found here.terraform plan
and you should have a Terraform plan for 4 new IAM resources!