Hi @apparentlymart ,
This is a concrete example of my problem with using JSON for my Terraform configuration files.
I am using Terraform v0.12.26 + provider.aws v2.66.0. I work locally on a desktop with Linux fedora 32; put up servers in AWS which are based on CentOS, at the moment mainly for running a few simple websites. Security is quite important for me. I want to automate my server provision set-up for the longer term.
I set up a small basic “test ground” which creates one web server, using IPv4 and IPv6, with a NAT instance, custom gateways, custom VPC, and a public and private subnet.
The config I created is composed of the following files, which are I think fairly self-explanatory:
main.tf.json
vars.all.tf.json
terraform.tfvars.json
vpc_and_gateways.tf.json
subnet_public.tf
subnet_private.tf
web_server.tf.json
web_secgroup.tf
NAT_instance.tf.json
NAT_secgroup.tf
Originally I had (my full version of) this with all the files created in JSON. I could not make that work - it basically stalled at the terraform validate
stage.
I have now converted the main JSON files which produced error messages to HCL; and created a mixed JSON / HCL setup as listed above. This does work, and I have deployed the server, the NAT instance, and the different customised networking components - all verifiable in the console.
I have also identified that some of my problems were a struggle with the different interpolation syntax styles: especially in terraform 0.12, in HCL you hardly use the old forms with ${ }
, and also dispense with many of the quotation marks, e.g. both for aws_vpc.vp3333.id
and for var.port_http
or var.ami_id
However, even under 0.12, in the JSON config files you need to use the syntax with ${ }
, or else the files get rejected by terraform validate
.
These interpolation problems I think I now have under control, and I can produce valid expressions in JSON as well as in HCL.
My current main example problem is the following - illustrated by trying to convert one file from HCL to JSON.
I tried to convert the web_secgroup.tf file to JSON - while leaving the rest of the files - which produce a functioning deployment. The HCL file was as follows:
web_secgroup.tf
resource "aws_security_group" "Web_server_SG333" {
name = "sec group web server SG333"
vpc_id = aws_vpc.vp3333.id
revoke_rules_on_delete = true
ingress {
description = "http-4"
from_port = var.port_http
to_port = var.port_http
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "http-6"
from_port = var.port_http
to_port = var.port_http
protocol = "tcp"
ipv6_cidr_blocks = ["::/0"]
}
egress {
description = "http-4"
from_port = var.port_http
to_port = var.port_http
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
description = "http-6"
from_port = var.port_http
to_port = var.port_http
protocol = "tcp"
ipv6_cidr_blocks = ["::/0"]
}
ingress {
description = "ssh-in-fr-outside-4"
from_port = var.port_ssh
to_port = var.port_ssh
protocol = "tcp"
cidr_blocks = [
"193.36.0.0/27",
"185.159.0.0/27"
]
}
ingress {
description = "ssh-in-fr-outside-6"
from_port = var.port_ssh
to_port = var.port_ssh
protocol = "tcp"
ipv6_cidr_blocks = ["2a00:c98:2050:a02f:xxxx:yyyy:6b38:2ba/128"]
}
tags = {
Name = "Security group for web server SG333"
}
}
I have experimented with various different approaches of putting in more or fewer brackets and braces. Especially if you would use JSON files in an automated environment, I would expect there to be some conversion tool or tools. I would dearly like to have one at my disposal. I have found an old (and perhaps by now unmaintained?) Linux tool called json2hcl , which converts in both directions. However, this is clearly pre-0.12, and works badly with variable expressions… However, I can utilise it to some extent. One of the existing web tools converting between HCL and JSON was worse.
So using mainly this json2hcl tool, and adjusting the expressions, I have converted the HCL above to the following JSON file:
web_secgroup.tf.json
{
"resource": [
{
"aws_security_group": [
{
"Web_server_SG333": [
{
"egress": [
{
"cidr_blocks": [
"0.0.0.0/0"
],
"description": "http-4",
"from_port": "${var.port_http}",
"protocol": "tcp",
"to_port": "${var.port_http}"
},
{
"description": "http-6",
"from_port": "${var.port_http}",
"ipv6_cidr_blocks": [
"::/0"
],
"protocol": "tcp",
"to_port": "${var.port_http}"
}
],
"ingress": [
{
"cidr_blocks": [
"0.0.0.0/0"
],
"description": "http-4",
"from_port": "${var.port_http}",
"protocol": "tcp",
"to_port": "${var.port_http}"
},
{
"description": "http-6",
"from_port": "${var.port_http}",
"ipv6_cidr_blocks": [
"::/0"
],
"protocol": "tcp",
"to_port": "${var.port_http}"
},
{
"cidr_blocks": [
"193.36.0.0/27",
"185.159.0.0/27"
],
"description": "ssh-in-fr-outside-4",
"from_port": "${var.port_ssh}",
"protocol": "tcp",
"to_port": "${var.port_ssh}"
},
{
"description": "ssh-in-fr-outside-6",
"from_port": "${var.port_ssh}",
"ipv6_cidr_blocks": [
"2a00:c98:2050:a02f:xxxx:yyyy:6b38:2ba/128"
],
"protocol": "tcp",
"to_port": "${var.port_ssh}"
}
],
"name": "sec group web server SG333",
"revoke_rules_on_delete": true,
"tags":
{
"Name": "Security group for web server SG333"
},
"vpc_id": "${aws_vpc.vp3333.id}"
}
]
}
]
}
]
}
How can I make a JSON file that does the same as the HCL file, and that is accepted by terraform? If you can answer that question, I can probably generalise from there to my other “problem files”, and revive my project and my favoured way of working.
I know that this conversion is a bit top-heavy in the alternation between and {} brackets. And can simplify that myself. I have tried a number of variations, but I did not get any of them to work.
The error message produced by terraform validate
to the full set of files, including above web_secgroup.tf.json file, is as follows:
Error: Incorrect attribute value type
on web_sec_group.tf.json line 8, in resource[0].aws_security_group[0].Web_server_SG333[0]:
<< I omit the print-out of the egress portion of the file - lines 8-27 >>
Inappropriate value for attribute "egress": element 0: attributes "ipv6_cidr_blocks", "prefix_list_ids", "security_groups", and "self" are required.
Error: Incorrect attribute value type
on web_sec_group.tf.json line 28, in resource[0].aws_security_group[0].Web_server_SG333[0]:
<< I omit the print-out of the ingress part of the file; lines 28-66 >>
Inappropriate value for attribute "ingress": element 0: attributes "ipv6_cidr_blocks", "prefix_list_ids", "security_groups", and "self" are required.
I hope the above reasonably describes the problem I encounter. It may be that the solution is simple. But it left me stumped. I have spent probably hours on the clearly important documentation about JSON configuration syntax, including the bit on Nested block mapping, which I believe probably contains the answer that I am looking for; but I have not been able to work it out with that as help. There seems to be a reference document of the full HCL2 JSON syntax somewhere in Github, but the link to that is broken. Otherwise I would have tried to dive into that, too.
I am most grateful for your or anyone’s help with this.