running Terraform 1.7.4
for each row in arg map my SSM automation needs
{
"description": "Invoke Lambda Function ${key}",
"name": "InvokeLambdaFunction${key}",
"action": "aws:invokeLambdaFunction",
"inputs": {
"FunctionName": "arn:aws:lambda:us-east-1:${account_number}:function:hello",
"InvocationType": "RequestResponse",
"Payload": "{\"key1\": \"${account_number}\", \"key2\": \"<first value from arg_map>\", \"key3\": \"<second value from arg_map>\"}"
}
}
main.tf
provider "aws" {
region = "us-east-1" # Set your desired region here
}
variable "account_number" {
default = "123456789"
}
variable "arg_map" {
type = map(list(string))
default = {
"key" = ["a", "b"]
"key" = ["d", "e"]
"key" = ["g", "h"]
"key" = ["j", "k"]
}
}
resource "aws_ssm_document" "sync_epv2asm" {
name = "sync_epv2asm"
document_type = "Automation"
content = templatefile("${path.module}/ssm_document_template.tftpl", {
account_number = var.account_number
arg_map = var.arg_map
})
}
ssm_document_template.tftpl
{
"schemaVersion": "0.3",
"description": "My description.",
"mainSteps": [
% for key, values in arg_map:
{
"description": "Invoke Lambda Function ${key}",
"name": "InvokeLambdaFunction${key}",
"action": "aws:invokeLambdaFunction",
"inputs": {
"FunctionName": "arn:aws:lambda:us-east-1:${account_number}:function:hello",
"InvocationType": "RequestResponse",
"Payload": "{\"key1\": \"${account_number}\", \"key2\": \"${values[0]}\", \"key3\": \"${values[1]}\"}"
}
}% if not loop.last %,
% endif
% endfor
]
}
running terraform apply
│ Error: Invalid function argument │ │ on main.tf line 23, in resource "aws_ssm_document" "sync_epv2asm": │ 23: content = templatefile("${path.module}/ssm_document_template.tftpl", { │ 24: account_number = var.account_number │ 25: arg_map = var.arg_map │ 26: }) │ ├──────────────── │ │ while calling templatefile(path, vars) │ │ var.arg_map is a map of list of string │ │ Invalid value for "vars" parameter: vars map does not contain key "key", referenced at ./ssm_document_template.tftpl:7,44-47.
googling around is not finding anything. I even tried some of the AI to see if they and identify my problem.
some of the things on the internet were showing "{}" the template around the "%". that did not change my error.
any thoughts on why I cannot get the template to work?
Since you are trying to create a JSON document, templatefile
is almost never enough by itself to achieve that. Based on the documentation for templatefile
, you can also use the built-in jsonencode
function with the template. It should look something like the following:
${jsonencode({
"schemaVersion": "0.3",
"description": "My description.",
"mainSteps": [
for key, values in arg_map:
{
"description": "Invoke Lambda Function ${key}",
"name": "InvokeLambdaFunction${key}",
"action": "aws:invokeLambdaFunction",
"inputs": {
"FunctionName": "arn:aws:lambda:us-east-1:${account_number}:function:hello:$LATEST",
"InvocationType": "RequestResponse",
"Payload": "{\"key1\": \"${account_number}\", \"key2\": \"${values[0]}\", \"key3\": \"${values[1]}\"}"
}
}
]
})}
The plan output shows the result like this:
# aws_ssm_document.sync_epv2asm will be created
+ resource "aws_ssm_document" "sync_epv2asm" {
+ arn = (known after apply)
+ content = jsonencode(
{
+ description = "My description."
+ mainSteps = [
+ {
+ action = "aws:invokeLambdaFunction"
+ description = "Invoke Lambda Function key1"
+ inputs = {
+ FunctionName = "arn:aws:lambda:us-east-1:123456789:function:hello:$LATEST"
+ InvocationType = "RequestResponse"
+ Payload = jsonencode(
{
+ key1 = "123456789"
+ key2 = "a"
+ key3 = "b"
}
)
}
+ name = "InvokeLambdaFunctionkey1"
},
+ {
+ action = "aws:invokeLambdaFunction"
+ description = "Invoke Lambda Function key2"
+ inputs = {
+ FunctionName = "arn:aws:lambda:us-east-1:123456789:function:hello:$LATEST"
+ InvocationType = "RequestResponse"
+ Payload = jsonencode(
{
+ key1 = "123456789"
+ key2 = "d"
+ key3 = "e"
}
)
}
+ name = "InvokeLambdaFunctionkey2"
},
]
+ schemaVersion = "0.3"
}
)
+ created_date = (known after apply)
+ default_version = (known after apply)
+ description = (known after apply)
+ document_format = "JSON"
+ document_type = "Automation"
+ document_version = (known after apply)
+ hash = (known after apply)
+ hash_type = (known after apply)
+ id = (known after apply)
+ latest_version = (known after apply)
+ name = "sync_epv2asm"
+ owner = (known after apply)
+ parameter = (known after apply)
+ platform_types = (known after apply)
+ schema_version = (known after apply)
+ status = (known after apply)
+ tags_all = (known after apply)
}
I've trimmed the example to use only two keys, but this should work for any number of keys.
NOTE: You also have to append the Lambda version to the Lambda ARN, either using $LATEST
or a version number, otherwise, the SSM document will throw an error:
Error: creating SSM Document (sync_epv2asm): InvalidDocumentContent: Input arn:aws:lambda:us-east-1:123456789:function:hello failed to match regex defined in document: (arn:aws)?(-[a-z]+)?(-[a-z]+)?(:lambda:)?([a-z]{2}-[a-z]+(-[a-z]+)?-\d{1}:)?(\d{12}:)?(function:)?([a-zA-Z0-9-]+)(:($LATEST|[a-zA-Z0-9-]+))?.
Apply output:
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_ssm_document.sync_epv2asm will be created
+ resource "aws_ssm_document" "sync_epv2asm" {
+ arn = (known after apply)
+ content = jsonencode(
{
+ description = "My description."
+ mainSteps = [
+ {
+ action = "aws:invokeLambdaFunction"
+ description = "Invoke Lambda Function key1"
+ inputs = {
+ FunctionName = "arn:aws:lambda:us-east-1:123456789:function:hello:$LATEST"
+ InvocationType = "RequestResponse"
+ Payload = jsonencode(
{
+ key1 = "123456789"
+ key2 = "a"
+ key3 = "b"
}
)
}
+ name = "InvokeLambdaFunctionkey1"
},
+ {
+ action = "aws:invokeLambdaFunction"
+ description = "Invoke Lambda Function key2"
+ inputs = {
+ FunctionName = "arn:aws:lambda:us-east-1:123456789:function:hello:$LATEST"
+ InvocationType = "RequestResponse"
+ Payload = jsonencode(
{
+ key1 = "123456789"
+ key2 = "d"
+ key3 = "e"
}
)
}
+ name = "InvokeLambdaFunctionkey2"
},
]
+ schemaVersion = "0.3"
}
)
+ created_date = (known after apply)
+ default_version = (known after apply)
+ description = (known after apply)
+ document_format = "JSON"
+ document_type = "Automation"
+ document_version = (known after apply)
+ hash = (known after apply)
+ hash_type = (known after apply)
+ id = (known after apply)
+ latest_version = (known after apply)
+ name = "sync_epv2asm"
+ owner = (known after apply)
+ parameter = (known after apply)
+ platform_types = (known after apply)
+ schema_version = (known after apply)
+ status = (known after apply)
+ tags_all = (known after apply)
}
Plan: 1 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
aws_ssm_document.sync_epv2asm: Creating...
aws_ssm_document.sync_epv2asm: Creation complete after 0s [id=sync_epv2asm]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.