In this article, ec2 (Amazon Linux) will be configured with Cloud Watch to send its logs.
All the resources will be created with Terraform.
Let's start with VPC, subnet, route tables & etc..
resource "aws_vpc" "vpc" {
cidr_block = var.vpc_cidr
instance_tenancy = "default"
tags = {
Name = "${var.environment}-vpc"
}
}
resource "aws_internet_gateway" "igw" {
vpc_id = aws_vpc.vpc.id
depends_on = [
aws_vpc.vpc
]
tags = {
"Name" = "${var.environment}-igw"
}
}
resource "aws_subnet" "subnet" {
vpc_id = aws_vpc.vpc.id
cidr_block = var.subnet_cidr
tags = {
Name = "${var.environment}-subnet"
}
}
resource "aws_route_table" "public-rt" {
vpc_id = aws_vpc.vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.igw.id
}
tags = {
"Name" = "${var.environment}-public-route-table"
}
}
resource "aws_route_table_association" "rta-sub" {
subnet_id = aws_subnet.subnet.id
route_table_id = aws_route_table.public-rt.id
}
resource "aws_security_group" "sg" {
name = "${var.environment}-demo-sg"
vpc_id = aws_vpc.vpc.id
ingress {
from_port = var.security_group_open_port[0]
to_port = var.security_group_open_port[1]
protocol = "tcp"
cidr_blocks = [local.workstation_external_ip]
}
egress {
from_port = 0
to_port = 0
protocol = -1
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_security_group_rule" "access_for_ip" {
for_each = toset(var.security_group_allow_ip)
type = "ingress"
from_port = var.security_group_open_port[0]
to_port = var.security_group_open_port[1]
protocol = "tcp"
cidr_blocks = [each.value]
security_group_id = aws_security_group.sg.id
}
In security group block, ingress cidr_block is configured to local.workstation_external_ip. This will be your local-machine public IP, which you can see at whatismyipaddress.com
Now, we have to get the IP through terraform.
get_external_ip.tf
data "http" "workstation-external-ip" {
url = "http://ipv4.icanhazip.com"
}
locals {
workstation_external_ip = "${chomp(data.http.workstation-external-ip.body)}/32"
}
resource "tls_private_key" "ssh" {
algorithm = "RSA"
rsa_bits = "4096"
}
resource "local_file" "ssh_private_key" {
content = tls_private_key.ssh.private_key_pem
filename = "./tls/private.pem"
file_permission = "0600"
}
resource "aws_key_pair" "tf-ssh-key" {
key_name = "${var.environment}-ssh-key"
public_key = tls_private_key.ssh.public_key_openssh
}
resource "aws_instance" "ec2" {
count = var.instance_count
ami = var.instance_ami
instance_type = var.instance_type
key_name = aws_key_pair.tf-ssh-key.key_name
vpc_security_group_ids = [aws_security_group.sg.id]
tags = {
Name = "${var.environment}-vm"
}
associate_public_ip_address = true
subnet_id = aws_subnet.subnet.id
iam_instance_profile = aws_iam_instance_profile.profile.id
user_data = <<-EOF
#!/bin/bash
yum update -y
yum install -y awslogs
systemctl start awslogsd
EOF
}
resource "aws_iam_policy" "logs-push-policy" {
name = "cw-policy-to-push-logs-to-ec2"
path = "/"
description = "cw-policy-to-push-logs-to-ec2"
policy = jsonencode({
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"logs:DescribeLogStreams"
],
"Resource": [
"arn:aws:logs:*:*:*"
]
}
]
})
}
resource "aws_iam_role" "ec2-cw-role" {
name = "cw-ec2-logs-role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
resource "aws_iam_role_policy_attachment" "attach-cw-role" {
role = aws_iam_role.ec2-cw-role.id
policy_arn = aws_iam_policy.logs-push-policy.id
}
resource "aws_iam_instance_profile" "profile" {
name = "ec2-cw-profile"
role = aws_iam_role.ec2-cw-role.id
}
variable "region" {
default = "us-east-1"
}
variable "environment" {
default = "dev"
}
variable "vpc_cidr" {
default = "18.0.0.0/16"
}
variable "subnet_cidr" {
default = "18.0.0.0/24"
}
variable "security_group_open_port" {
default = [22, 22]
}
variable "security_group_allow_ip" {
default = ["180.0.0.0/32"]
}
variable "instance_count" {
default = 1
}
variable "instance_type" {
default = "t2.micro"
}
variable "instance_ami" {
default = "ami-026b57f3c383c2eec" ## amazon linux
}
output "local_workstation_ip" {
value = local.workstation_external_ip
}
output "ec2_public_ip" {
# value = aws_instance.ec2[0].public_ip
value = aws_instance.ec2[*].public_ip
}
Run terraform commands to create resourcs
$ terraform init
$ terraform plan
-> Plan: 15 to add, 0 to change, 0 to destroy.
$ terraform apply --auto-approve
->
Apply complete! Resources: 15 added, 0 changed, 0 destroyed.
Outputs:
ec2_public_ip = [
"52.87.50.72",
]
local_workstation_ip = "***.49.55.31/32"
Once resources are created, check In-bound Rule in Security Groups
go to AWS Dashboard > VPC management > Security Groups
Now, try ssh log-in with private key generated in tls folder. Get public IP from outputs.
$ ssh -i ./tls/private.pem ec2-user@52.87.50.72
Check Cloudwatch logs go to AWS Dashboard > CloudWatch > Log groups > /var/log/messages
Destroy the resources once done
$ terraform destroy
-> Destroy complete! Resources: 15 destroyed.
Terraform code will be available at Github.
Thanks for reading.... :)