- Neueste
- Die meisten Stimmen
- Die meisten Kommentare
A few things:
- It must include both a public and private subnet – where the private subnet is used for compute and the public is used for the load balancers.
The EC2 instance is provisioned in a public subnet.
resource "aws_instance" "web_app" {
.
.
subnet_id = aws_subnet.public_subnet.0.id
Is it intentional that the load-balancer and the EC2 have the same security group associate with them? Usually the LB would have a much looser rule (e.g. allow traffic from all addresses on the internet, and pass it to the EC2) and the EC2 sitting behind it would have a much tighter rule (only accept traffic from the LB).
resource "aws_lb" "web_app_lb" {
.
.
security_groups = [aws_security_group.client_alb.id]
resource "aws_instance" "web_app" {
.
.
vpc_security_group_ids = [aws_security_group.client_alb.id]
The client_alb
security group has no outbound rules. This means that (i) the LB will not be able to pass any traffic onto any instances that sit behind it; and (ii) the EC2 has no outbound access to the internet (whether that's through an Internet Gateway or NAT Gateway, depending on whether the EC2 needs to live in a public or private subnet - see earlier comment).
This is also significant because the EC2 instance's user data script tries to install Apache, but as there is no outbound security group rule in the client_alb
security group, it means the yum
commands have no way of contacting the repo, and will just sit there until they eventually timeout.
vpc_security_group_ids = [aws_security_group.client_alb.id]
user_data = <<EOF
#!/bin/bash
sudo yum update -y
sudo yum install -y httpd
The update to /var/www/html/index.html
should also be made before starting Apache, not while it's running.
sudo systemctl start httpd
sudo systemctl enable httpd
sudo echo '<center><h1>Web App!!!</h1></center>' > /var/www/html/index.html
EOF
Hi Steve, thanks for answering first of all. I have made the changes for EC2 and ALB as suggested. Here are the code snippets:
ec2-instance.tf:
resource "aws_instance" "web_app" {
ami = data.aws_ami.amazon_linux.id
instance_type = var.instance_type
subnet_id = aws_subnet.private_subnet.0.id
vpc_security_group_ids = [aws_security_group.client_alb.id]
user_data = <<EOF
#!/bin/bash
sudo systemctl start httpd
sudo systemctl enable httpd
sudo echo '<center><h1>Web App!!!</h1></center>' > /var/www/html/index.html
EOF
tags = {
Name = "${var.default_tags.project_name}-ec2-instance"
}
key_name = var.generated_key_name
associate_public_ip_address = true
monitoring = true
}
// Create key-pair for EC2 instance
resource "tls_private_key" "web_app_key" {
algorithm = "RSA"
rsa_bits = 4096
}
resource "aws_key_pair" "generated_key" {
key_name = var.generated_key_name
public_key = tls_private_key.web_app_key.public_key_openssh
}
resource "local_sensitive_file" "pem_file" {
filename = pathexpand("~/.ssh/${local.ssh_key_name}.pem")
file_permission = "600"
directory_permission = "700"
content = tls_private_key.web_app_key.private_key_pem
provisioner "local-exec" {
command = <<-EOT
touch ec2-keypair.pem
cp "~/.ssh/${local.ssh_key_name}.pem" ./ec2-keypair.pem
chmod 400 ec2-keypair.pem
EOT
}
}
security-groups.tf:
resource "aws_security_group" "client_alb" {
name = "${var.default_tags.project_name}-alb"
description = "security group for web application load balancer"
vpc_id = aws_vpc.main.id
tags = {
Name = "${var.default_tags.project_name}-sg"
}
}
resource "aws_security_group_rule" "client_alb_allow_80" {
security_group_id = aws_security_group.client_alb.id
type = "ingress"
protocol = "tcp"
from_port = 80
to_port = 80
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
description = "Allow HTTP traffic."
}
resource "aws_security_group_rule" "client_alb_allow_22" {
security_group_id = aws_security_group.client_alb.id
type = "ingress"
protocol = "tcp"
from_port = 22
to_port = 22
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
description = "Allow SSH Login."
}
resource "aws_security_group_rule" "client_alb_allow_443" {
security_group_id = aws_security_group.client_alb.id
type = "ingress"
protocol = "tcp"
from_port = 443
to_port = 443
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
description = "Allow HTTP traffic."
}
resource "aws_security_group_rule" "client_alb_allow_outbound" {
security_group_id = aws_security_group.client_alb.id
type = "egress"
protocol = "-1"
from_port = 0
to_port = 0
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
description = "Allow any outbound traffic."
}
resource "aws_security_group" "ec2_security_group" {
name = "${var.default_tags.project_name}-ec2"
description = "Security group for EC2 instances in the target group"
vpc_id = aws_vpc.main.id
tags = {
Name = "${var.default_tags.project_name}-ec2-sg"
}
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
security_groups = [aws_security_group.client_alb.id]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
But now I am facing this error when accessing the ALB DNS:
Regarding your next ask, I also noticed that the EC2 and ALB are in the same security group. There is nothing intentional as such I just noticed I only created one SG which is utilized by both ALB and EC2, so as a good practice I need to have one SG for each. What do you recommend?
Also one last thing the local ssh key name is not getting copied to my pem file using terraform code, any reason why?
Relevanter Inhalt
- AWS OFFICIALAktualisiert vor 2 Jahren
- AWS OFFICIALAktualisiert vor 5 Monaten
- AWS OFFICIALAktualisiert vor 2 Jahren
(1 of 2) There are two ways of approaching this - the first is to have a firm and fixed idea of what the end state needs to be, and then build it by hand in AWS Console. Know how everything fits together - subnets, route tables, security groups, listeners, target groups, internet & NAT gateways, as well as how the load-balancer and EC2 will talk to each other, and to the outside world.
This might take an hour or two to get fully working, but it will be time well spent, and there are plenty of resources on AWS and the wider internet that explain how to build this far better than I ever could here.
Once you know every element that is required, and how it all fits together, provision it in Terraform. You could even have separate VPCs, one of them populated by resources in AWS Console and the other populated with Terraform, and you can compare these as you go along.
(2 of 2) The other approach, if you just want to solely use Terraform, is to start small and don't try to build the whole stack at once. Have a VPC, one public subnet with an internet gateway attached, and deploy your EC2 in there. Get the User Data script working properly so that Apache displays your updated
index.html
. Once that works, provision a new private subnet with its routing table pointing to a NAT Gateway and amend your code so that the EC2 is provisioned in the private subnet. Okay you won't be able to hit it directly from a browser any more, but you can spin up a temporary bastion host (or just use Instance Connect) to check that Apache is properly installed, and is listeing on the right port(s)sudo netstat -tulpn
Once you're happy with that, move onto the target group, then the load balancer and its listeners, and so on.
Use git to commit your code at each big milestone, and if you make a mistake later you can always
terraform destroy
and then go back to your previous commit.And don't get hung up on things like the SSH key and cert having to be provisioned in Terraform if it's holding you up. Create these normally and just import them into your scripts initially. You can always go back and tweak these settings at the end.