I'm following this terraform tutorial found at gruntwork.io. I can use $ terraform apply to spin up a virtual machine, which shows in the aws console with a public facing ip address and everything. Unfortunately the instance seems to be attached to a previously defined security group and doesn't seems to be responding to ssh or curl as l might expect.
I've modified the security group so that the proper ports are open, and modified the tutorials main.tf file in an attempt to add a user account that l can use to at least see what's running on the vm with.
The results of terraform apply can be seen here
When l try to ssh into the instance with the test user and the associated private key l get a response of permission denied (this also happens if l try logging in as the default user, ubuntu). What am l misunderstanding that the security groups aren't being defined properly and that the user isn't being added to the instance properly. The tutorial was written for terraform 0.7, and l'm running with 0.11.10, but l can't imagine that something so basic would change.
The modified main.tf file is as follows
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# DEPLOY A SINGLE EC2 INSTANCE
# This template uses runs a simple "Hello, World" web server on a single EC2 Instance
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ------------------------------------------------------------------------------
# CONFIGURE OUR AWS CONNECTION
# ------------------------------------------------------------------------------
provider "aws" {
region = "us-east-1"
}
# ---------------------------------------------------------------------------------------------------------------------
# DEPLOY A SINGLE EC2 INSTANCE
# ---------------------------------------------------------------------------------------------------------------------
resource "aws_instance" "example" {
# Ubuntu Server 14.04 LTS (HVM), SSD Volume Type in us-east-1
ami = "ami-2d39803a"
instance_type = "t2.micro"
vpc_security_group_ids = ["${aws_security_group.instance.id}"]
user_data = <<-EOF
#!/bin/bash
echo "Hello, World" > index.html
nohup busybox httpd -f -p "${var.server_port}" &
EOF
tags {
Name = "terraform-example"
}
}
# ---------------------------------------------------------------------------------------------------------------------
# CREATE THE SECURITY GROUP THAT'S APPLIED TO THE EC2 INSTANCE
# ---------------------------------------------------------------------------------------------------------------------
resource "aws_security_group" "instance" {
name = "terraform-example-instance"
# Inbound HTTP from anywhere
ingress {
from_port = "${var.server_port}"
to_port = "${var.server_port}"
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
# Inbound SSH from anywhere
ingress {
from_port = "22"
to_port = "22"
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
variable "server_port" {
description = "The port the server will user for the HTTP requests"
default = 8080
}
# ---------------------------------------------------------------------------------------------------------------------
# Try to add a user to the spun up machine that we can ssh into the account of
# ---------------------------------------------------------------------------------------------------------------------
resource "aws_iam_user" "user" {
name = "test-user"
path = "/"
}
resource "aws_iam_user_ssh_key" "user" {
username = "${aws_iam_user.user.name}"
encoding = "SSH"
public_key = <public_key>
}
You did not specify any keypair name while creating ec2 instance.
For using ubuntu user for ssh you should specify keypair name
Related
I have an ec2 instance defined in terraform along with some security rules.
These are the security rules:
resource "aws_security_group" "ec2_web" {
name = "${var.project_name}_${var.env}_ec2_web"
description = "ec2 instances that serve to the load balancer"
vpc_id = aws_vpc.main.id
}
resource "aws_security_group_rule" "ec2_web_http" {
type = "egress"
from_port = 80
to_port = 80
protocol = "tcp"
# cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.ec2_web.id
source_security_group_id = aws_security_group.elb.id
}
resource "aws_security_group_rule" "ec2_web_ssh" {
type = "ingress"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["${var.ip_address}/32"]
security_group_id = aws_security_group.ec2_web.id
}
I'm trying to simply add another security rule:
resource "aws_security_group_rule" "ec2_web_ssh_test" {
type = "ingress"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["${var.ip_address}/32"]
security_group_id = aws_security_group.ec2_web.id
}
And terraform wants to completely replace the security group, and that cascades into completely replacing the ec2 instance.
I'm modifying the .tf file and then running:
terraform apply
EDIT:
The security group itself seems completely unrelated. When I do "plan", I get the output:
# aws_instance.ec2 must be replaced
-/+ resource "aws_instance" "ec2" {
...
~ security_groups = [ # forces replacement
+ "sg-0befd5d21eee052ad",
]
The ec2 instance is created with:
resource "aws_instance" "ec2" {
ami = "ami-0b5eea76982371e91"
instance_type = "t3.small"
key_name = "${var.project_name}"
depends_on = [aws_internet_gateway.main]
user_data = <<EOF
#!/bin/bash
sudo amazon-linux-extras install -y php8.1 mariadb10.5
sudo yum install -y httpd mariadb php8.1 php8.1-cli
sudo systemctl start httpd
sudo systemctl enable httpd
echo 'yup' | sudo tee /var/www/html/index.html
echo '<?php echo phpinfo();' | sudo tee /var/www/html/phpinfo.php
EOF
tags = {
Name = "${var.project_name}_${var.env}_ec2"
}
root_block_device {
volume_size = 8 # GB
volume_type = "gp3"
}
security_groups = [aws_security_group.ec2_web.id]
# vpc_security_group_ids = [aws_security_group.main.id]
subnet_id = aws_subnet.main1.id
}
If I comment out
# security_groups = [aws_security_group.bake.name]
I do not get any errors.
This happens because security_groups can only be used EC2-Classic (legacy instances) and a default VPC. For everything else you must use vpc_security_group_ids.
In your cause you are using custom VPC called main, thus you must be using vpc_security_group_ids, not security_groups.
Before apply please run terraform apply -refresh-only then your main problem is you can not define same rule with different terraform id.
When you apply new changes for ec2_web_ssh_test AWS will complain about
│Error: [WARN] A duplicate Security Group rule was found on (sg-xxxxxx). This may be
│ a side effect of a now-fixed Terraform issue causing two security groups with
│ identical attributes but different source_security_group_ids to overwrite each
│ other in the state
Then you will get this error from AWS api
Error: InvalidPermission.Duplicate: the specified rule "peer: xxx.xxx.xxx.xxx/32, TCP, from port: 22, to port: 22, ALLOW" already exists
With Terraform it compares the current state of your configuration with the new state which will contain the new rule you are adding. Here current state is not same as the desired state with new rule you are adding.
Hence with two different states, Terraform is trying to destroy the EC2 instances and trying to build new instances with newly added rules state.
This can be avoided with using terraform import command that will import the existing resources to your terraform state and then make changes to it.
I really can't figure out why I'm unable to SSH into my newly created EC2 instance and can't figure out why for the life of me.
Here is some of my code in Terraform where I created the EC2 and security groups for it.
This is my EC2 code
resource "aws_key_pair" "AzureDevOps" {
key_name = var.infra_env
public_key = var.public_ssh_key
}
# Create network inferface for EC2 instance and assign secruity groups
resource "aws_network_interface" "vm_nic_1" {
subnet_id = var.subnet_id
private_ips = ["10.0.0.100"]
tags = {
Name = "${var.infra_env}-nic-1"
}
security_groups = [
var.ssh_id
]
}
# Add elastic IP addresss for public connectivity
resource "aws_eip" "vm_eip_1" {
vpc = true
instance = aws_instance.virtualmachine_1.id
associate_with_private_ip = "10.0.0.100"
depends_on = [var.gw_1]
tags = {
Name = "${var.infra_env}-eip-1"
}
}
# Deploy virtual machine using Ubuntu ami
resource "aws_instance" "virtualmachine_1" {
ami = var.ami
instance_type = var.instance_type
key_name = aws_key_pair.AzureDevOps.id
#retrieve the Administrator password
get_password_data = true
connection {
type = "ssh"
port = 22
password = rsadecrypt(self.password_data, file("id_rsa"))
https = true
insecure = true
timeout = "10m"
}
network_interface {
network_interface_id = aws_network_interface.vm_nic_1.id
device_index = 0
}
user_data = file("./scripts/install-cwagent.ps1")
tags = {
Name = "${var.infra_env}-vm-1"
}
}
Here is the code for my security group
resource "aws_security_group" "ssh" {
name = "allow_ssh"
description = "Allow access to the instance via ssh"
vpc_id = var.vpc_id
ingress {
description = "Access the instance via ssh"
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 = "${var.infra_env}-allow-ssh"
}
}
If I need to provide any more code or information I can, it's my first time trying to do this and it's frustrating trying to figure it out. I'm trying to use Putty as well and not sure if I just don't know how to use it correctly or if it's something wrong with my EC2 configuration.
I used my public ssh key from my computer for the variable in my aws_key_pair resource. I saved my public ssh key pair as a .ppk file for putty and on my aws console when I go to "connect" it says to use ubuntu#10.0.0.100 for my host name in Putty which I did and when I click okay and it tries to connect it gets a network error connection timed out
I used my public ssh key
You need to use your private key, not public.
use ubuntu#10.0.0.100
10.0.0.100 is private IP address. To be able to connect to your instance over the internet you need to use public IP address.
I am trying to run one of the first basic examples from the book Terraform Up and Running. My main.tf is almost identical to the one in the link apart from the version:
provider "aws" {
region = "us-east-2"
}
resource "aws_instance" "example" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
vpc_security_group_ids = [aws_security_group.instance.id]
user_data = <<-EOF
#!/bin/bash
echo "Hello, World" > index.html
nohup busybox httpd -f -p 8080 &
EOF
tags = {
Name = "terraform-example"
}
}
resource "aws_security_group" "instance" {
name = var.security_group_name
ingress {
from_port = 8080
to_port = 8080
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
variable "security_group_name" {
description = "The name of the security group"
type = string
default = "terraform-example-instance"
}
output "public_ip" {
value = aws_instance.example.public_ip
description = "The public IP of the Instance"
}
I ran terraform apply and everything seems to be created successfully. However, when I try to run curl http://<EC2_INSTANCE_PUBLIC_IP>:8080, the command hangs.
I created my AWS account right before I ran the example, so it uses the default network configuration.
The routing table has an entry pointing to the Internet Gateway of the VPC:
Destination | Target | Status | Propagated
0.0.0.0/0 | igw-<igwId> | active | No
The Network ACLs has the default settings:
Rule number | Type | Protocol | Port range | Source | Allow/Deny
100 | All traffic| All | All | 0.0.0.0/0 | Allow
* | All traffic| All | All | 0.0.0.0/0 | Deny
My Terraform version is v0.14.10.
Any ideas on how to access the instance's server through the EC2's public IP?
There is nothing wrong the TF program. I verified it using my sandbox account and it works as expected. It takes 1-2 minutes for script to start working, so maybe you are testing it too soon.
So whatever difficulties you have are not due to the script itself. So either what you posted on SO is not your actual code, or you have somehow modified your VPC configurations which make the instance not-accessible.
I am trying to provision an ECS cluster using Terraform along with an ALB. The targets come up as Unhealthy. The error code is 502 in the console Health checks failed with these codes: [502]
I checked through the AWS Troubleshooting guide and nothing helped there.
EDIT: I have no services/tasks running on the EC2 containers. Its a vanilla ECS cluster.
Here is my relevant code for the ALB:
# Target Group declaration
resource "aws_alb_target_group" "lb_target_group_somm" {
name = "${var.alb_name}-default"
port = 80
protocol = "HTTP"
vpc_id = "${var.vpc_id}"
deregistration_delay = "${var.deregistration_delay}"
health_check {
path = "/"
port = 80
protocol = "HTTP"
}
lifecycle {
create_before_destroy = true
}
tags = {
Environment = "${var.environment}"
}
depends_on = ["aws_alb.alb"]
}
# ALB Listener with default forward rule
resource "aws_alb_listener" "https_listener" {
load_balancer_arn = "${aws_alb.alb.id}"
port = "80"
protocol = "HTTP"
default_action {
target_group_arn = "${aws_alb_target_group.lb_target_group_somm.arn}"
type = "forward"
}
}
# The ALB has a security group with ingress rules on TCP port 80 and egress rules to anywhere.
# There is a security group rule for the EC2 instances that allows ingress traffic to the ECS cluster from the ALB:
resource "aws_security_group_rule" "alb_to_ecs" {
type = "ingress"
/*from_port = 32768 */
from_port = 80
to_port = 65535
protocol = "TCP"
source_security_group_id = "${module.alb.alb_security_group_id}"
security_group_id = "${module.ecs_cluster.ecs_instance_security_group_id}"
}
Has anyone hit this error and know how to debug/fix this ?
It looks like you're trying to be register the ECS cluster instances with the ALB target group. This isn't how you're meant to send traffic to an ECS service via an ALB.
Instead you should have your service join the tasks to the target group. This will mean that if you are using host networking then only the instances with the task deployed will be registered. If you are using bridge networking then it will add the ephemeral ports used by your task to your target group (including allowing for there to be multiple targets on a single instance). And if you are using awsvpc networking then it will register the ENIs of every task that the service spins up.
To do this you should use the load_balancer block in the aws_ecs_service resource. An example might look something like this:
resource "aws_ecs_service" "mongo" {
name = "mongodb"
cluster = "${aws_ecs_cluster.foo.id}"
task_definition = "${aws_ecs_task_definition.mongo.arn}"
desired_count = 3
iam_role = "${aws_iam_role.foo.arn}"
load_balancer {
target_group_arn = "${aws_lb_target_group.lb_target_group_somm.arn}"
container_name = "mongo"
container_port = 8080
}
}
If you were using bridge networking this would mean that the tasks are accessible on the ephemeral port range on the instances so your security group rule would need to look like this:
resource "aws_security_group_rule" "alb_to_ecs" {
type = "ingress"
from_port = 32768 # ephemeral port range for bridge networking tasks
to_port = 60999 # cat /proc/sys/net/ipv4/ip_local_port_range
protocol = "TCP"
source_security_group_id = "${module.alb.alb_security_group_id}"
security_group_id = "${module.ecs_cluster.ecs_instance_security_group_id}"
}
it looks like the http://ecsInstanceIp:80 is not returning HTTP 200 OK. I would check that first. It would be easy to check if the instance is public. It wont be the case most of the times. Otherwise I would create an EC2 instance and make a curl request to confirm that.
You may also check the container logs to see if its logging the health check response.
Hope this helps. good luck.
I am trying to use terraform to spin up a VPC and single instance and then connect via ssh but I'm unable to. I'm aware I don't have any keys here but I'm trying to simply connect via the web terminal and it still says
There was a problem setting up the instance connection The connection
has been closed because the server is taking too long to respond. This
is usually caused by network problems, such as a spotty wireless
signal, or slow network speeds. Please check your network connection
and try again or contact your system administrator.
Is anyone able to look at my code and see what I'm doing wrong?
provider "aws" {
region = "us-east-2"
}
resource "aws_vpc" "vpc" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "test"
}
}
resource "aws_internet_gateway" "gateway" {
vpc_id = "${aws_vpc.vpc.id}"
tags = {
Name = "test"
}
}
resource "aws_subnet" "subnet" {
vpc_id = "${aws_vpc.vpc.id}"
cidr_block = "${aws_vpc.vpc.cidr_block}"
availability_zone = "us-east-2a"
map_public_ip_on_launch = true
tags = {
Name = "test"
}
}
resource "aws_route_table" "table" {
vpc_id = "${aws_vpc.vpc.id}"
route {
cidr_block = "0.0.0.0/0"
gateway_id = "${aws_internet_gateway.gateway.id}"
}
tags = {
Name = "test"
}
}
resource "aws_route_table_association" "public" {
subnet_id = "${aws_subnet.subnet.id}"
route_table_id = "${aws_route_table.table.id}"
}
resource "aws_instance" "node" {
#ami = "ami-0d5d9d301c853a04a" # Ubuntu 18.04
ami = "ami-0d03add87774b12c5" # Ubuntu 16.04
instance_type = "t2.micro"
subnet_id = "${aws_subnet.subnet.id}"
}
UPDATE1: I've added key_name = "mykey" which I have previously created. I am unable to ping the public ip and upon trying to ssh with the key I get the following:
$ ssh -v -i ~/.ssh/mykey ubuntu#1.2.3.4
OpenSSH_7.9p1, LibreSSL 2.7.3
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 48: Applying options for *
debug1: Connecting to 1.2.3.4 [1.2.3.4] port 22.
where mykey and 1.2.3.4 have been changed for posting.
UPDATE2: Looking at the security group I don't see anything which stands out. The ACL for this has the following:
Rule # Type Protocol Port Range Source Allow / Deny
100 ALL Traffic ALL ALL 0.0.0.0/0 ALLOW
* ALL Traffic ALL ALL 0.0.0.0/0 DENY
Is this a problem? It seems that no one sees an issue with the terraform code so if anyone can confirm this is not a problem with the code then I think this can be closed out and moved to a different board since it would not be a code issue, correct?
The web console uses SSH to connect, so you still need to setup an SSH key. The only way to connect without an SSH key configured, and port 22 open in the Security Group, is to use AWS Systems Manager Session Manager, but that requires the SSM agent running on the EC2 instance and appropriate IAM roles assigned to the instance.
You have not supplied a key_name to indicate which SSH keypair to use.
If you don't have an existing aws_key_pair then you will also need to create one.