Errata

Terraform: Up and Running

Errata for Terraform: Up and Running, Third Edition

Submit your own errata for this product.

The errata list is a list of errors and their corrections that were found after the product was released. If the error was corrected in a later version or reprint the date of the correction will be displayed in the column titled "Date Corrected".

The following errata were submitted by our customers and approved as valid errors by the author or editor.

Color key: Serious technical mistake Minor technical mistake Language or formatting error Typo Question Note Update

Version Location Description Submitted By Date submitted Date corrected
Page Chapter 1, Server Templating Tools section
Chapter 1, 3rd paragraph in Server Templating Tools section

VMware is referred to as VMWare in Chapter 1 which is incorrect. The "W" should be lower case.

Note from the Author or Editor:
This is correct. I believe we already fixed this in copyediting though!

Anonymous  Aug 14, 2022 
Page chapter 5
Loops with for_each Expressions

"The for_each expression allows you to loop over lists, sets, and maps"

"COLLECTION is a set or map to loop over (lists are not supported when using for_each on a resource)"

i suppose there is a contradiction

Note from the Author or Editor:
Good point, it should say "allows you to loop over sets and maps."

Michele Sartor  Sep 22, 2022 
Page Chapter 2, Deploying a Configurable Web Server
3rd terraform apply snippet

It might worth to mention that the first time `terraform apply` is used after output variable is declared (with no changes to any resources) the question to save new output value to the Terraform state is appeared.

```
$ terraform apply
aws_security_group.instance: Refreshing state... [id=sg-0942e8axxxxxxxxxx]
aws_instance.example: Refreshing state... [id=i-085601cxxxxxxxxxx]

Changes to Outputs:
+ public_ip = "16.xx.xx.xx"

You can apply this plan to save these new output values to the Terraform state, without changing any real infrastructure.

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


Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

public_ip = "16.xx.xx.xx"
```

Note from the Author or Editor:
Yes, it's a good idea to clarify this, thanks!

Michael Loginovsky  Mar 11, 2023 
Page Chapter 3, Limitations with Terraform’s Backends
2nd paragraph

It seems that for terraform version 1.4.0, to copy the Terraform state back to local disk after removing the `backend` configuration from `main.tf`, it is necessary to run the mentioned command with `-migrate-state` flag, like: `terraform init -migrate-state`

Note from the Author or Editor:
You're right, the "-migrate-state" flag is now necessary to move the state.

Michael Loginovsky  Mar 12, 2023 
Page Chapter 4, Module basics
Fourth paragraph

Both the provider definition and the backend need to be removed and added to the environment-specific main.tf files. Running the module with the backend in the module configuration will generate an error, and the configuration will be saved locally.

Note from the Author or Editor:
The text does tell you to move the provider definition:

"Open up the main.tf file in modules/services/webserver-cluster, and remove the provider definition. Providers should be configured only in root modules and not in reusable modules (you’ll learn a lot more about working with providers in Chapter 7)."

However, it looks like I missed the instruction to move the backend configuration! That should indeed be only in the root module, not the reusable modules.

Grant Palmer  Aug 08, 2023 
Page Deploying a Single Web Server
6th Paragraph

When discussing how to interact with a simple web server, the book states:

"By default, AWS does not allow any incoming or outgoing traffic from an EC2 Instance."

My understanding is that an EC2 Instance without security group would use the default security group, and that this security group does:

- deny all inbound traffic (the book would be correct here)
- allow all outbound traffic (the book would be incorrect here)
- allow all traffic between instances assigned to the security group (the book doesn't state anything, at least in this section)

AWS's VPC userguide includes details about the default security group.

Note from the Author or Editor:
You're right! If you don't specify a security group, it does use the default security group, and while that blocks all inbound traffic (by default), it does allow outbound traffic. It's also worth noting the default security group can be modified.

Eduardo Garabito  Nov 26, 2024 
Page Ch 3. How to Manage Terraform State: The terraform_remote_state Data Source
Code block: resource "aws_db_instance" "example" {...

The db.t2.micro instance_class is not compatible with the database engine version.

aws_db_instance.example: Creating...
╷
│ Error: creating RDS DB Instance (terraform-up-and-running20250909022018074000000001): operation error RDS: CreateDBInstance, https response error StatusCode: 400, RequestID: d5584828-db34-4367-9942-8627b8aa48f4, api error InvalidParameterCombination: RDS does not support creating a DB instance with the following combination: DBInstanceClass=db.t2.micro, Engine=mysql, EngineVersion=8.0.42, LicenseModel=general-public-license. For supported combinations of instance class and database engine version, see the documentation.
│
│ with aws_db_instance.example,
│ on main.tf line 16, in resource "aws_db_instance" "example":
│ 16: resource "aws_db_instance" "example" {
│
╵

It can be fixed by changing instance_class = "db.t3.micro", for example:

resource "aws_db_instance" "example" {
identifier_prefix = "terraform-up-and-running"
engine = "mysql"
allocated_storage = 10
instance_class = "db.t3.micro"
skip_final_snapshot = true
db_name = "example_database"

username = var.db_username
password = var.db_password
}

Note from the Author or Editor:
Looks like in June, 2024, AWS ended support for db.t2.xxx instance types with RDS: https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/WhatsNew.html

So, yes, updating to db.t3.xxx is the right solution!

Alex Kraker  Sep 09, 2025 
Page 1. Why Terraform
Immediately following "terraform plan"

The text describes adding 5 servers, the output shows 4 instances, then says 5 were created. Full incorrect text is here:

$ terraform plan

# aws_instance.example[11] will be created
+ resource "aws_instance" "example" {
+ ami = "ami-0fb653ca2d3203ac1"
+ instance_type = "t2.micro"
+ (...)
}

# aws_instance.example[12] will be created
+ resource "aws_instance" "example" {
+ ami = "ami-0fb653ca2d3203ac1"
+ instance_type = "t2.micro"
+ (...)
}

# aws_instance.example[13] will be created
+ resource "aws_instance" "example" {
+ ami = "ami-0fb653ca2d3203ac1"
+ instance_type = "t2.micro"
+ (...)
}

# aws_instance.example[14] will be created
+ resource "aws_instance" "example" {
+ ami = "ami-0fb653ca2d3203ac1"
+ instance_type = "t2.micro"
+ (...)
}

Plan: 5 to add, 0 to change, 0 to destroy.

Note from the Author or Editor:
True, looks like the plan output is missing aws_instance.example[10].

Dave Jagoda  Jun 22, 2024 
Page 68
3rd paragraph

Due to aws no longer accepting resource aws_launch_configuration, switched to aws_launch_template:
resource "aws_launch_template" "example" {
# image_id = "ami-0fb653ca2d3203ac1"
image_id = "ami-0efc43a4067fe9a3e"
instance_type = "t2.micro"


user_data = base64encode(
<<-EOF
#!/bin/bash
echo "Hello, World" > index.html
nohup busybox httpd -f -p ${var.server_port} &
EOF
)


# Required when using a launch configuration with an auto scaling group.
lifecycle {
create_before_destroy = true
}
security_group_names = [aws_security_group.instance.id]

}
aws_autoscaling_group.example: Creating...
╷
│ Error: creating Auto Scaling Group (terraform-20250328181831484400000001): operation error Auto Scaling: CreateAutoScalingGroup, https response error StatusCode: 400, RequestID: 75dcef72-779b-4f1c-a164-6754a94ca304, api error ValidationError: You must use a valid fully-formed launch template. The parameter groupName cannot be used with the parameter subnet
│
│ with aws_autoscaling_group.example,
│ on main.tf line 11, in resource "aws_autoscaling_group" "example":
│ 11: resource "aws_autoscaling_group" "example" {


here is the complete code from chapter 2, 3rd edition: Deploying a cluster of webservers:
provider "aws" {
region = "us-east-2"
}

resource "aws_autoscaling_group" "example" {
depends_on = [aws_launch_template.example]
lifecycle {
create_before_destroy = true
}
launch_template {
id = aws_launch_template.example.id
version = "$Latest"
}
vpc_zone_identifier = data.aws_subnets.default.ids

target_group_arns = [aws_lb_target_group.asg.arn]
health_check_type = "ELB"

max_size = 10
min_size = 2
tag {
key = "Name"
value = "terraform-asg-example-run"
propagate_at_launch = true
}
}

resource "aws_launch_template" "example" {
# image_id = "ami-0fb653ca2d3203ac1"
image_id = "ami-0efc43a4067fe9a3e"
instance_type = "t2.micro"


user_data = base64encode(
<<-EOF
#!/bin/bash
echo "Hello, World" > index.html
nohup busybox httpd -f -p ${var.server_port} &
EOF
)


# Required when using a launch configuration with an auto scaling group.
lifecycle {
create_before_destroy = true
}
security_group_names = [aws_security_group.instance.id]

}

/*
resource "aws_launch_configuration" "example" {
image_id = "ami-0fb653ca2d3203ac1"
instance_type = "t2.micro"


user_data = <<-EOF
#!/bin/bash
echo "Hello, World" > index.html
nohup busybox httpd -f -p ${var.server_port} &
EOF
# Required when using a launch configuration with an auto scaling group.
lifecycle {
create_before_destroy = true
}
security_groups = [aws_security_group.instance.id]

}
*/

resource "aws_security_group" "instance" {
name = "terraform-example-instance"
ingress {
from_port = var.server_port
to_port = var.server_port
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}

data "aws_vpc" "default" {
default = true
}

data "aws_subnets" "default" {
filter {
name = "vpc-id"
values = [data.aws_vpc.default.id]
}
}

resource "aws_lb" "example" {
name = "terraform-asg-example"
load_balancer_type = "application"
subnets = data.aws_subnets.default.ids
security_groups = [aws_security_group.alb.id]
}

# define listeners for the resource.aws_lb.example
resource "aws_lb_listener" "http" {
load_balancer_arn = aws_lb.example.arn
port = 80
protocol = "HTTP"
# By default, return a simple 404 page
default_action {
type = "fixed-response"

fixed_response {
content_type = "text/plain"
message_body = "404: page not found"
status_code = "404"
}
}
}

# by default all AWS resources including ALBs, don't allow any incoming or outgoing traffic
# so you need to create a new security group specifically for the ALB. This sg should allow
# incoming requests on port 80 so that you can access the load balancer over HTTP, and allow
# outgoing requests on all ports so that the load balancer can perform health checks.
resource "aws_security_group" "alb" {
name = "terraform-example-alb"

# Allow inbound HTTP requests
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}

# Allow all outbound requests
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}

resource "aws_lb_target_group" "asg" {
name = "terraform-asg-example"
port = var.server_port
protocol = "HTTP"
vpc_id = data.aws_vpc.default.id

health_check {
path = "/"
protocol = "HTTP"
matcher = "200"
interval = 15
timeout = 3
healthy_threshold = 2
unhealthy_threshold = 2

}
}

# finally tie all these resources together
resource "aws_lb_listener_rule" "asg" {
listener_arn = aws_lb_listener.http.arn
priority = 100

condition {
path_pattern {
values = ["*"]
}
}

action {
type = "forward"
target_group_arn = aws_lb_target_group.asg.arn
}
}

output "alb_dns_name" {
value = aws_lb.example.dns_name
description = "The domain name of the load balancer"
}

Note from the Author or Editor:
Yes, AWS dropped support for launch configurations in 2024. The work around is to move to launch templates. I've also documented this here: https://github.com/brikis98/terraform-up-and-running-code/issues/118#issuecomment-2476154890

Anonymous  Mar 28, 2025 
Page 127
The whole section 2 is non functional.

aws_launch_configuration.example: Creating...
╷
│ Error: creating Auto Scaling Launch Configuration (terraform-20251115220954098700000001): operation error Auto Scaling: CreateLaunchConfiguration, https response error StatusCode: 400, RequestID: 95257006-ca9a-4934-a88b-88d6101dc91c, api error UnsupportedOperation: The Launch Configuration creation operation is not available in your account. Use launch templates to create configuration templates for your Auto Scaling groups.
│
│ with aws_launch_configuration.example,
│ on main.tf line 2, in resource "aws_launch_configuration" "example":
│ 2: resource "aws_launch_configuration" "example" {







New accounts only support launch templates: Starting on October 1, 2024, Amazon EC2 Auto Scaling will no longer support the creation of launch configurations for new accounts. Existing environments will not be impacted. For more information about other situations that are impacted, including temporary option settings required for new accounts, refer to Launch templates in the Elastic Beanstalk Developer Guide.

Note from the Author or Editor:
This is due to a change that AWS made near the end of 2024. The workaround is here: https://github.com/brikis98/terraform-up-and-running-code/issues/118#issuecomment-2476154890

Jason  Nov 15, 2025 
Page 284
The first list in the page (resources needed to be moved)

The list of resources that need to be moved contains "aws_cloudwatch_metric_alarm (both of them)" but this resource hasn't been created anywhere in the book. It seems this was created in Chapter 5 in the 2nd edition while it isn't in the 3rd edition. Note that the sample code for the 3rd edition also contains the resource aws_cloudwatch_metric_alarm.

Note from the Author or Editor:
You're right, this is a left over from the 2nd edition. In that edition, I used the aws_cloudwatch_metric_alarm resource to demonstrate an example of conditionals. I changed those examples in the 3rd edition, but forgot to remove the aws_cloudwatch_metric_alarm resource from the sample code and text.

Hayato Matsuura  Jul 29, 2023