navig8tr
navig8tr

Reputation: 1854

Terraform - SSH Provisioner Failing to Connect

I'm creating an aws_instance resource and run a provisioner but the SSH connection is never successful.

Here is my resource code:

resource "aws_instance" "pos" {
  ami           = "ami-c58c1dd3"
  instance_type = "m4.xlarge"
  subnet_id = "${var.subnet_id_1}"
  key_name        = "${var.key_name}"

  connection {
    type = "ssh"
    user        = "ec2-user"
    private_key = "${file(var.private_key_path)}"
    host = "aws_instance.instance.private_ip"
  } 

  provisioner "remote-exec" {
    inline = [
      "sudo yum install nginx -y",
      "sudo service nginx start"
    ]
  }
}

During creation I get the following output repeated over and over:

aws_instance.pos (remote-exec): Connecting to remote host via SSH...
aws_instance.pos (remote-exec):   Host: aws_instance.insance.private_ip
aws_instance.pos (remote-exec):   User: ec2-user
aws_instance.pos (remote-exec):   Password: false
aws_instance.pos (remote-exec):   Private key: true
aws_instance.pos (remote-exec):   Certificate: false
aws_instance.pos (remote-exec):   SSH Agent: false
aws_instance.pos (remote-exec):   Checking Host Key: false
aws_instance.pos: Still creating... [40s elapsed]

The SSH connection is never successful and eventually I must kill the command. However the EC2 instance is successfully created and I can SSH into from my local machine using the private key (PEM file).

I've also tried using self.public_ip in the host field, but that produced the same result. How can I connect to the EC2 instance and provision it during creation?

Upvotes: 1

Views: 9362

Answers (2)

ydaetskcoR
ydaetskcoR

Reputation: 56997

You aren't correctly interpolating the IP address output so are just using a string literal of "aws_instance.insance.private_ip".

Instead you want to interpolate this by wrapping it in ${}. Unfortunately, if you do that you'll then get an error from Terraform saying that it can't find the resource aws_instance.instance because you haven't defined it. Instead you should use the self keyword to access attributes from the resource directly:

resource "aws_instance" "pos" {
  ami           = "ami-c58c1dd3"
  instance_type = "m4.xlarge"
  subnet_id = "${var.subnet_id_1}"
  key_name        = "${var.key_name}"

  connection {
    type = "ssh"
    user        = "ec2-user"
    private_key = "${file(var.private_key_path)}"
    host = "${self.private_ip}"
  } 

  provisioner "remote-exec" {
    inline = [
      "sudo yum install nginx -y",
      "sudo service nginx start"
    ]
  }
}

Upvotes: 3

Pacifist
Pacifist

Reputation: 3201

You can try using the below code. It's working for me. Terraform was able to connect to the instance after creating it and ran the commands.

resource "aws_instance" "pos" {
  ami           = "ami-c58c1dd3"
  instance_type = "m4.xlarge"
  subnet_id = "${var.subnet_id_1}"
  key_name = "XYZ"

  provisioner "remote-exec" {
  connection {
    type = "ssh"
    user = "ec2-user"
    host = "${aws_instance.pos.public_ip}"
    private_key = "${file("<Absolute-Path-to-file>/XYZ.pem")}"
    agent = false
    timeout = "2m"
  }

    inline = [
      "sudo yum install nginx -y",
      "sudo service nginx start"
    ]
  }
}

Make sure key_name should be matching with the private_key file. This is to make sure that you are using the same key while connecting the instance which you used while creating the instance.

One more thing, allow port 22 in your security group which is being used by your instance.

Upvotes: 1

Related Questions