DEV Community

Revathi Joshi for AWS Community Builders

Posted on

Using Terraform Dynamic Blocks and Built-in Functions to Deploy Resources to AWS

Terraform offers a strong set of features to help optimize your Terraform code. Two really useful features are

  • dynamic blocks, which allow you to generate static repeated blocks within resources in Terraform.

You can dynamically construct repeatable nested blocks like ingress using a special dynamic block type, which is supported inside resource, data, provider, and provisioner blocks.

A dynamic block acts much like a for expression, but produces nested blocks instead of a complex typed value. It iterates over a given complex value, and generates a nested block for each element of that complex value.

  • built-in functions, which help you manipulate variables and data to suit your needs and help make your Terraform deployments better automated and more fault resilient.

The Terraform language includes a number of built-in functions that you can call from within expressions to transform and combine values.

The general syntax for function calls is a function name followed by comma-separated arguments in parentheses - timestamp()

Please visit my GitHub Repository for Terraform articles on various topics being updated on constant basis.

Let’s get started!

Objectives:

1. Login to AWS Management Console

2. Create infrastructure for application block

3. Under terraform_files application directory - Create 4 files - main.tf, apache.sh, variables.tf, outputs.tf

4. Initialize Terraform

5. To generate the action plans

6. Create all the resources declared in main.tf configuration file

7. Validate all resources created

Pre-requisites:

  • AWS user account with admin access, not a root account.
  • Cloud9 IDE with AWS CLI.

Resources Used:

Terraform documentation.
Terraform documentation for AMI.
dynamic Blocks
Built-in Functions

Steps for implementation to this project:

1. Login to AWS Management Console

  • Make sure you're in the N. Virginia (us-east-1) region

2. Create infrastructure for application block

  • Let’s create the following organizational structure as shown below.

3. Under terraform_files application directory - Create 4 files - main.tf, apache.sh, variables.tf, outputs.tf.

  • Create a directory - terraform-files

  • Create 4 files - main.tf, apache.sh, variables.tf, outputs.tf.

    1. main.tf

Data Source: aws_ssm_parameter
ssm_parameter public endpoint resource is to get the AMI ID of the Amazon Linux 2 image that will spin up the EC2 webserver.

Resource: aws_security_group

security_group resource uses a dynamic block on the ingress attribute to dynamically generate as many ingress blocks as we need. The dynamic block includes the var.rules complex variable configured in the variables.tf file.

join Function
for_each Meta-Argument

built-in functions like the join function for the name attribute in the security group resource, and the fileexists and file functions for the user_data parameter in the EC2 instance resource and which then installs the Apache webserver and starts up the service.

provider "aws" {
  region = "us-east-1"
}

data "aws_ssm_parameter" "ami_id" {
  name = "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2"
}

module "vpc" {
  source = "terraform-aws-modules/vpc/aws"

  name = "my-vpc"
  cidr = "10.0.0.0/16"

  azs            = ["us-east-1a"]
  public_subnets = ["10.0.1.0/24"]
}

resource "aws_security_group" "my-sg" {
  vpc_id = module.vpc.vpc_id
  name   = join("_", ["sg", module.vpc.vpc_id])
  dynamic "ingress" {
    for_each = var.rules
    content {
      from_port   = ingress.value["port"]
      to_port     = ingress.value["port"]
      protocol    = ingress.value["protocol"]
      cidr_blocks = ingress.value["cidr_blocks"]
    }
  }
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "Dynamic-SG"
  }
}

resource "aws_instance" "my-instance" {
  ami                         = data.aws_ssm_parameter.ami_id.value
  subnet_id                   = module.vpc.public_subnets[0]
  instance_type               = "t2.micro"
  security_groups             = [aws_security_group.my-sg.id]
  associate_public_ip_address = true
  user_data  = fileexists("script.sh") ? file("script.sh") : null
}
Enter fullscreen mode Exit fullscreen mode
  • 2. apache.sh
#!/bin/bash
sudo yum -y install httpd
sudo systemctl start httpd && sudo systemctl enable httpd
Enter fullscreen mode Exit fullscreen mode
  • 3. variables.tf

variable "rules" - Declaring an Input Variable

variable "rules" {
  type = list(object({
    port        = number
    protocol       = string
    cidr_blocks = list(string)
  }))
  default = [
    {
      port        = 80
      protocol       = "tcp"
      cidr_blocks = ["0.0.0.0/0"]
    },
    {
      port        = 22
      protocol      = "tcp"
      cidr_blocks = ["0.0.0.0/0"]
    },
    {
      port        = 3689
      protocol       = "tcp"
      cidr_blocks = ["101.34.81.98/32"]
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode
  • 4. outputs.tf

timestamp Function

output "Web-Server-URL" {
  description = "Web-Server-URL"
  value       = join("", ["http://", aws_instance.my-instance.public_ip])
}

output "Time-Date" {
  description = "Date/Time of Execution"
  value       = timestamp()
}
Enter fullscreen mode Exit fullscreen mode

4. Initialize Terraform

cd terraform-files

  • terraform status
terraform version
Enter fullscreen mode Exit fullscreen mode

Since the Terraform version is returned, you have validated that the Terraform binary is installed and functioning properly.

Note:

If you receive a notification that there is a newer version of Terraform available, you can ignore it — it will run safely with the version installed on the VM.

Image description

  • terraform init will check for all the plugin dependencies and download them if required, this will be used for creating a deployment plan.
terraform init
Enter fullscreen mode Exit fullscreen mode

Image description

5. To generate the action plans, run the below command:

terraform plan
Enter fullscreen mode Exit fullscreen mode

Image description

6. Create all the resources declared in main.tf configuration file

Note:

The --auto-approve flag will prevent Terraform from prompting you to enter yes explicitly before it deploys the code.

terraform apply --auto-approve
Enter fullscreen mode Exit fullscreen mode

Image description

terraform state list
Enter fullscreen mode Exit fullscreen mode

Image description

  1. Validate all resources created
  • VPC

Image description

  • EC2

Image description

Image description

Image description

  • Security Group and Inbound rules

Image description

Image description

Image description

Cleanup

  • terraform destroy

What we have done so far

We have successfuly deployed AWS resources using Terraform Dynamic Blocks ingress and Built-in Functions join, fileexists and file.

Top comments (0)