LAB-07: Provisioners (file, remote-exec), Null Resources (local-exec) => Provision Key-Pair, SSH Connection
This scenario shows:
- how to create file, run command using "remote-exec" provisioners on remote instance,
- how to create file using provisioner "file" on remote instance,
- how to create file, run command using "local-exec" on local pc,
- how to create key-pairs for SSH connection.
Code: https://github.com/omerbsezer/Fast-Terraform/blob/main/labs/provisioners-nullresources/main.tf
- You should have a look following lab:
-
SSH key-pairs (public and private key) are used to connect remote server. Public key (xx.pub) is on the remote server, with private key, user can connect using SSH.
-
There are 2 ways of creating key-pairs (public and private key):
- Creating them on cloud (AWS)
- EC2 > Key-pairs > Create Key-Pair
- Creating them on on-premise
- "ssh-keygen -t rsa -b 2048"
- Creating them on cloud (AWS)
-
Creating key-pairs on AWS: Go to EC2 > Key-pairs
- After creating key-pairs, public key is listed on AWS:
- Private key (testkey.pem) is downloaded on your PC:
- Copy this testkey.pem into your directory on which main.tf exists.
- With provisioner "file", on the remote instance, new file can be created
- With provisioner "remote-exec", on the remote instance, any command can be run
- With provisioner "local-exec", on the local PC, any command can be run on any shell (bash, powershell)
- With "null_resource", without creating any resource, any command can be run.
- Provisioners in the resource only runs once while creating resource on remote instance
- Provisioners in the "null_resource" run multiple times and it doesn't depend on the resource.
...
resource "aws_instance" "ubuntu2204" {
...
provisioner "file" {
source = "test-file.txt"
destination = "/home/ubuntu/test-file.txt"
}
provisioner "file" {
content = "I want to copy this string to the destination file => server.txt (using provisioner file content)"
destination = "/home/ubuntu/server.txt"
}
provisioner "remote-exec" {
inline = [
"touch hello.txt",
"echo helloworld remote-exec provisioner >> hello.txt",
]
}
connection {
type = "ssh"
host = self.public_ip
user = "ubuntu"
private_key = file("testkey.pem")
timeout = "4m"
}
}
resource "null_resource" "example" {
provisioner "local-exec" {
command = "'This is test file for null resource local-exec' >> nullresource-generated.txt"
interpreter = ["PowerShell", "-Command"]
}
}
...
- Create main.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.16"
}
}
required_version = ">= 1.2.0"
}
provider "aws" {
region = "eu-central-1"
}
resource "aws_vpc" "my_vpc" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
tags = {
Name = "My VPC"
}
}
resource "aws_subnet" "public" {
vpc_id = aws_vpc.my_vpc.id
cidr_block = "10.0.0.0/24"
availability_zone = "eu-central-1c"
tags = {
Name = "Public Subnet"
}
}
resource "aws_internet_gateway" "my_vpc_igw" {
vpc_id = aws_vpc.my_vpc.id
tags = {
Name = "My VPC - Internet Gateway"
}
}
resource "aws_route_table" "my_vpc_eu_central_1c_public" {
vpc_id = aws_vpc.my_vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.my_vpc_igw.id
}
tags = {
Name = "Public Subnet Route Table"
}
}
resource "aws_route_table_association" "my_vpc_eu_central_1c_public" {
subnet_id = aws_subnet.public.id
route_table_id = aws_route_table.my_vpc_eu_central_1c_public.id
}
resource "aws_security_group" "allow_ssh" {
name = "allow_ssh_sg"
description = "Allow SSH inbound connections"
vpc_id = aws_vpc.my_vpc.id
# for SSH
ingress {
from_port = 22
to_port = 22
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"]
}
tags = {
Name = "allow_ssh_sg"
}
}
resource "aws_instance" "ubuntu2204" {
ami = "ami-0d1ddd83282187d18" # Ubuntu 22.04 eu-central-1 Frankfurt
instance_type = "t2.nano"
key_name = "testkey"
vpc_security_group_ids = [aws_security_group.allow_ssh.id]
subnet_id = aws_subnet.public.id
associate_public_ip_address = true
tags = {
Name = "Ubuntu 22.04"
}
provisioner "file" {
source = "test-file.txt"
destination = "/home/ubuntu/test-file.txt"
}
provisioner "file" {
content = "I want to copy this string to the destination file => server.txt (using provisioner file content)"
destination = "/home/ubuntu/server.txt"
}
provisioner "remote-exec" {
inline = [
"touch hello.txt",
"echo helloworld remote-exec provisioner >> hello.txt",
]
}
connection {
type = "ssh"
host = self.public_ip
user = "ubuntu"
private_key = file("testkey.pem")
timeout = "4m"
}
}
resource "null_resource" "example" {
provisioner "local-exec" {
command = "'This is test file for null resource local-exec' >> nullresource-generated.txt"
interpreter = ["PowerShell", "-Command"]
}
}
Code: https://github.com/omerbsezer/Fast-Terraform/blob/main/labs/provisioners-nullresources/main.tf
- Run init, validate command:
terraform init
terraform validate
- Run plan, apply command:
terraform plan
terraform apply
- On AWS EC2 Instance:
- Make SSH connection:
ssh -i testkey.pem ubuntu@<PublicIP>
- Provisioners run and files were created on remote instance:
- On local PC, local provisioner also created file:
- Destroy infrastructure:
terraform destroy
- On AWS EC2 Instance: