Terraform uses resource
blocks to manage infrastructure, such as virtualnetworks, compute instances, or higher-level components such as DNS records.Resource blocks represent one or more infrastructure objects in your Terraformconfiguration.
Most Terraform providers have a number of different resources that map to the appropriateAPIs to manage that particular infrastructure type.
Generic | AWS Provider Resource | AWS Infrastructure |
---|---|---|
Resource A | aws_instance | EC2 Instance |
Resource B | aws_security_group | Security Group |
In this tutorial, you will create an EC2 instance that runs a PHP webapplication. You will then refer to documentation in the Terraform Registry tocreate a security group to make the application publicly accessible.
You can complete this tutorial using the same workflow with either TerraformCommunity Edition or Terraform Cloud. Terraform Cloud is a platform that you can use tomanage and execute your Terraform projects. It includes features like remotestate and execution, structured plan output, workspace resource summaries, andmore.
Select the Terraform Cloud tab to complete this tutorial using Terraform Cloud.
This tutorial assumes that you are familiar with the Terraform workflow. If you are new to Terraform, complete the Get Started collection first.
In order to complete this tutorial, you will need the following:
- Terraform v1.2+ installed locally.
- An AWS account with local credentials configured for use withTerraform.
This tutorial assumes that you are familiar with the Terraform and TerraformCloud workflows. If you are new to Terraform, complete the Get Started collection first. If you are new to Terraform Cloud, complete the Terraform Cloud Get Startedtutorials first.
In order to complete this tutorial, you will need the following:
- Terraform v1.2+ installed locally.
- An AWS account.
- A Terraform Cloud account with Terraform Cloud locally authenticated.
- A Terraform Cloud variable set configured with your AWS credentials.
Clone the example repository
Clone the Learn TerraformResources repository,which contains example configuration to provision an AWS EC2 instance.
$ git clone https://github.com/hashicorp/learn-terraform-resources.git
Navigate to the repository directory in your terminal.
$ cd learn-terraform-resources
There are five files in this directory:
- init-script.sh contains the provisioning script to install dependencies and start a sample PHP application
- terraform.tf contains the
terraform
block that defines the providers required by your configuration - main.tf contains the configuration for an EC2 instance
- outputs.tf contains the definitions for the output values of your resources
- README.md describes the repository and its contents
Open main.tf
to review the two resource blocks: random_pet.name
and aws_instance.web
.
Review the random_pet
resource
The first resource block defines a random_pet
resource named name
, whichgenerates a random pet name. You can use the name generated by this resource toensure that your other resources have unique names.
resource "random_pet" "name" {}
Resource blocks declare a resource type and name. Together, the type and nameform a resource identifier (ID) in the format resource_type.resource_name
, inthis case random_pet.name
. The resource's ID must be unique within aworkspace. When Terraform displays information about this resource in itsoutput it will use the resource ID.
Resource types always start with the provider name followed by an underscore.The random_pet
resource type belongs to the random
provider.
The Terraform Registry houses the documentation for Terraform providers and their associated resources. Open the random_pet
documentation page and notice that it is nested under the documentation for the random
provider. The page contains a description of the random_pet
resource, an example usage, argument reference, and attribute reference.
Resources have arguments, attributes, and meta-arguments.
- Arguments configure a particular resource; because of this, many arguments are resource-specific. Arguments can be
required
oroptional
, as specified by the provider. If you do not supply a required argument, Terraform will give an error and not apply the configuration. - Attributes are values exposed by an existing resource. References to resource attributes take the format
resource_type.resource_name.attribute_name
. Unlike arguments which specify an infrastructure object's configuration, a resource's attributes are often assigned to it by the underlying cloud provider or API. - Meta-arguments change a resource's behavior, such as using a
count
meta-argument to create multiple resources. Meta-arguments are a function of Terraform itself and are not resource or provider-specific.
The random_pet
resource has four optional arguments and exposes one attribute. Because there are no required arguments, you can define the random_pet.name
resource without arguments.
Review the EC2 instance resource
The aws_instance.web
resource block defines an aws_instance
resource named web
to create an AWS EC2 instance.
resource "aws_instance" "web" { ami = "ami-a0cfeed8" instance_type = "t2.micro" user_data = file("init-script.sh") tags = { Name = random_pet.name.id }}
The arguments inside the aws_instance.web
resource block specify what type of resource to create.
The
instance_type
andami
arguments tell the AWS provider to create at2.micro
EC2 instance using theami-a0cfeed8
machine image.Note
If you use a different AMI, you may need to update the
init-script.sh
. Connect to your EC2 instance and review/var/log/cloud-init-output.log
to debug any errors.The
user_data
argument uses thefile()
function to return the contents ofinit-script.sh
.The
tags
argument specifies this EC2 instance's name. Notice that the argument references therandom_pet.name
's ID attribute (random_pet.name.id
) to give the EC2 instance a unique name. This defines an implicit dependency between the EC2 instance and therandom_pet
resource; Terraform cannot create the instance until it has a name for it.
These are only a subset of the available aws_instances
arguments. Refer to the aws_instance
documentation page for a complete list.
Initialize this configuration.
$ terraform initInitializing the backend...##...Terraform has been successfully initialized!You may now begin working with Terraform. Try running "terraform plan" to seeany changes that are required for your infrastructure. All Terraform commandsshould now work.If you ever set or change modules or backend configuration for Terraform,rerun this command to reinitialize your working directory. If you forget, othercommands will detect it and remind you to do so if necessary.
Open your terraform.tf
file and uncomment the cloud
block. Replace theorganization
name with your own Terraform Cloud organization.
terraform.tf
terraform { cloud { organization = "organization-name" workspaces { name = "learn-terraform-resource" } } required_providers { aws = { source = "hashicorp/aws" version = "~> 4.4.0" } } required_version = ">= 1.2"}
Initialize your configuration. Terraform will automatically create the learn-terraform-resource
workspace in your Terraform Cloud organization.
$ terraform initInitializing Terraform Cloud...Initializing provider plugins...- Reusing previous version of hashicorp/aws from the dependency lock file- Installing hashicorp/aws v4.4.0...- Installed hashicorp/aws v4.4.0 (signed by HashiCorp)Terraform Cloud has been successfully initialized!You may now begin working with Terraform Cloud. Try running "terraform plan" tosee any changes that are required for your infrastructure.If you ever set or change modules or Terraform Settings, run "terraform init"again to reinitialize your working directory.
Note This tutorial assumes that you are using a tutorial-specificTerraform Cloud organization with a global variable set of your AWScredentials. Review the Create a Credential VariableSet for detailed guidance. If you are using a scoped variable set, assign it to your new workspace now.
Apply your configuration to create the two resources. Confirm the operation with a yes
.
$ terraform apply## ...Plan: 2 to add, 0 to change, 0 to destroy.## ...Apply complete! Resources: 2 added, 0 changed, 0 destroyed.Outputs:application-url = "ec2-18-236-123-132.us-west-2.compute.amazonaws.com/index.php"domain-name = "ec2-18-236-123-132.us-west-2.compute.amazonaws.com"
The domain-name
output will display your EC2 instance's endpoint upon completion. However, if you try to visit the URL, it will not resolve. This is because you have not yet configured access to port 80
of the instance.
This tutorial shows the output for Terraform commands run with Terraform Community Edition. If you are following the Terraform Cloud workflow, the output may differ slightly but the results will be the same.
If you use Terraform Cloud to provision your resources, your workspace now displays the list of all of the resources it manages and the outputs for your configuration.
Associate security group with instance
To enable access to the EC2 instance's web server, you must define a security group that allows ingress traffic on port 80
and all egress traffic, and associate the security group with your instance.
Open the AWS Provider documentation page. Search for security_group
and select the aws_security_group
resource.
Review the configuration options available on the aws_security_group
documentationpage.Then, define a new aws_security_group
resource named web-sg
in main.tf
that allows ingress traffic on port 80
and all egress traffic for all CIDR blocks.
Your security group resource should be similar to the following:
resource "aws_security_group" "web-sg" { name = "${random_pet.name.id}-sg" ingress { from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] }}
Then, update your aws_instance.web
resource to use this security group. Asspecified in the aws_instance
Argument Referencesection,thevpc_security_group_ids
argument requires a list of security group IDs.
Add the vpc_security_group_ids
argument to the aws_instance.web
resource as a list by placing the aws_security_group.web-sg.id
attribute inside square brackets.
resource "aws_instance" "web" { ami = "ami-a0cfeed8" instance_type = "t2.micro" user_data = file("init-script.sh")+ vpc_security_group_ids = [aws_security_group.web-sg.id] tags = { Name = random_pet.name.id }}
Save your changes.
Next, apply your configuration. Remember to confirm your apply with a yes
.
$ terraform apply## ...Apply complete! Resources: 1 added, 1 changed, 0 destroyed.Outputs:application-url = "ec2-18-236-123-132.us-west-2.compute.amazonaws.com/index.php"domain-name = "ec2-18-236-123-132.us-west-2.compute.amazonaws.com"
Verify that your EC2 instance is now publicly accessible.
In your browser, visit the application-url
address from Terraform's output to view the PHP application. The address should start with http
, not https
.
To view your application-url
output again, run the following command.
$ terraform output application-url"ec2-18-236-123-132.us-west-2.compute.amazonaws.com/index.php"
It may take about 10 minutes for the EC2 instance to completely deploy the PHP application. If you receive a ... took too long to respond.
message, please wait a few minutes before trying again.
Use curl
to send an HTTP request to the domain-name
output endpoint. It should return your EC2 instance ID.
$ curl $(terraform output -raw domain-name)i-035bf5dddf1361364
Now that you have verified that the EC2 instance is publicly available, runterraform destroy
to destroy the resources. Remember to respond to theconfirmation prompt with yes
.
$ terraform destroyAn execution plan has been generated and is shown below.Resource actions are indicated with the following symbols: - destroyTerraform will perform the following actions:##...Plan: 0 to add, 0 to change, 3 to destroy.Changes to Outputs: - application-url = "ec2-18-236-123-132.us-west-2.compute.amazonaws.com/index.php" - domain-name = "ec2-18-236-123-132.us-west-2.compute.amazonaws.com"Do you really want to destroy all resources? Terraform will destroy all your managed infrastructure, as shown above. There is no undo. Only 'yes' will be accepted to confirm. Enter a value: yesaws_security_group.web-sg: Destroying... [id=sg-0cd7b5ebfafbe3d7f]aws_instance.web: Destroying... [id=i-0798dc10162db25f3]aws_security_group.web-sg: Destruction complete after 1saws_instance.web: Still destroying... [id=i-0798dc10162db25f3, 10s elapsed]aws_instance.web: Still destroying... [id=i-0798dc10162db25f3, 20s elapsed]aws_instance.web: Still destroying... [id=i-0798dc10162db25f3, 30s elapsed]aws_instance.web: Still destroying... [id=i-0798dc10162db25f3, 40s elapsed]aws_instance.web: Destruction complete after 42srandom_pet.name: Destroying... [id=pleasing-swine]random_pet.name: Destruction complete after 0sDestroy complete! Resources: 3 destroyed.
If you used Terraform Cloud for this tutorial, after destroying your resources, delete the learn-terraform-resource
workspace from your Terraform Cloud organization.
Next steps
In this tutorial, you made an EC2 instance publicly available by referencingthe Terraform Registry to define a securitygroup. You also reviewed resource arguments and attributes and defined a dependency between resources.
To learn more about the Terraform configuration language, check out the following resources:
- Learn more about resource dependencies in the Create Resource Dependencies tutorial.
- Review the Perform Dynamic Operations with Functions and Create Dynamic Expressions tutorials.
- Review the difference between resource arguments, attributes, and meta-arguments in the Terraform documentation.