Running aws instance with connection using terraform - amazon-web-services

resource "aws_instance" "appserver1" {
ami = var.imageid
instance_type = var.instancetype
key_name = var.key
security_groups = [aws_security_group.allow_all.name]
connection {
user = "ubuntu"
private_key = file(var.privatekeypath)
}
provisioner "remote-exec" {
inline = [
"sudo apt-get update",
"sudo apt-get install tomcat7 -y"
]
}
}
"terraform validate" gives me the error:
Error: Missing required argument
on main.tf line 52, in resource "aws_instance" "appserver1":
52: connection {
The argument "host" is required, but no definition was found.

You have to specify connection details in the provisioner block. For example:
resource "aws_instance" "appserver1" {
ami = var.imageid
instance_type = var.instancetype
key_name = var.key
security_groups = [aws_security_group.allow_all.name]
provisioner "remote-exec" {
connection {
type = "ssh"
user = "ubuntu"
private_key = file(var.privatekeypath)
host = self.public_ip
}
inline = [
"sudo apt-get update",
"sudo apt-get install tomcat7 -y"
]
}
}
But in your case, using user_data would be more suited.

Instead of using a connection you can make use of userdataEC2 userdata options to install tomcat while launching the deploy instance.
I don't think giving a connection block inside the instance configuration will work

Related

terraform v0.12.21 throws "Failed to read ssh private key: no key found"

Not able to connect to ec2 instance from terraform. The same key pair works if I create the ec2 instance manually (not via terraform). That confirms my key-pair is correct. Here is the code that I'm trying to do. The error I get: `aws_instance.ec2_test_instance: Provisioning with 'remote-exec'...
Error: Failed to read ssh private key: no key found
Error: Error import KeyPair: MissingParameter: The request must contain the parameter PublicKeyMaterial
status code: 400, request id: `
resource "aws_instance" "ec2_test_instance" {
ami = var.instance_test_ami
instance_type = var.instance_type
subnet_id = var.aws_subnet_id
key_name = aws_key_pair.deployer.key_name
tags = {
Name = var.environment_tag
}
connection {
type = "ssh"
host = self.public_ip
user = "centos"
private_key = "file(path.root/my-key)"
}
provisioner "remote-exec" {
inline = [
"sudo yum -y install wget, unzip",
"sudo yum -y install java-1.8.0-openjdk",
]
}
You will need to use ${} for the interpolation syntax in your path:
private_key = file("${path.module}/my-key")
In the documentation, the example shows ${} around the actual file path within the argument field:
https://www.terraform.io/docs/configuration/functions/file.html

terraform V12: Error import KeyPair: MissingParameter: The request must contain the parameter PublicKeyMaterial

getting error "import KeyPair: MissingParameter: The request must contain the parameter PublicKeyMaterial " when I run "terraform apply". what does this error mean.
resource "aws_instance" "ec2_test_instance" {
ami = var.instance_test_ami
instance_type = var.instance_type
subnet_id = var.aws_subnet_id
key_name = aws_key_pair.deployer.key_name
tags = {
Name = var.environment_tag
}
provisioner "local-exec" {
command = "echo ${self.public_ip} > public-ip.txt"
}
provisioner "remote-exec" {
connection {
type = "ssh"
host = self.public_ip
user = "centos"
private_key = file("${path.module}/my-key")
}
inline = [
"sudo yum -y install wget, unzip",
"sudo yum -y install java-1.8.0-openjdk"
]
}
}
Assuming that everything else is correct, connection block should be inside provisioner, not outside of it:
resource "aws_instance" "ec2_test_instance" {
ami = var.instance_test_ami
instance_type = var.instance_type
subnet_id = var.aws_subnet_id
key_name = aws_key_pair.deployer.key_name
provisioner "remote-exec" {
connection {
type = "ssh"
host = self.public_ip
user = "centos"
private_key = file("${path.module}/my-key")
}
inline = [
"sudo yum -y install wget, unzip",
"sudo yum -y install java-1.8.0-openjdk",
]
}
}

Terraform Resource: Connection Error while executing apply?

I am trying to login to ec2 instance that terraform will create with the following code:
resource "aws_instance" "sess1" {
ami = "ami-c58c1dd3"
instance_type = "t2.micro"
key_name = "logon"
connection {
host= self.public_ip
user = "ec2-user"
private_key = file("/logon.pem")
}
provisioner "remote-exec" {
inline = [
"sudo yum install nginx -y",
"sudo service nginx start"
]
}
}
But this gives me an error:
PS C:\Users\Amritvir Singh\Documents\GitHub\AWS-Scribble\Terraform> terraform apply
provider.aws.region
The region where AWS operations will take place. Examples
are us-east-1, us-west-2, etc.
Enter a value: us-east-1
Error: Invalid function argument
on Session1.tf line 13, in resource "aws_instance" "sess1":
13: private_key = file("/logon.pem")
Invalid value for "path" parameter: no file exists at logon.pem; this function
works only with files that are distributed as part of the configuration source
code, so if this file will be created by a resource in this configuration you
must instead obtain this result from an attribute of that resource.
How do I save pass the key from resource to provisioner at runtime without logging into the console?
Have you tried using the full path? Especially beneficial if you are using modules.
I.E:
private_key = file("${path.module}/logon.pem")
Or I think even this will work
private_key = file("./logon.pem")
I believe your existing code is looking for the file at the root of your filesystem.
connection should be in the provisioner block:
resource "aws_instance" "sess1" {
ami = "ami-c58c1dd3"
instance_type = "t2.micro"
key_name = "logon"
provisioner "remote-exec" {
connection {
host= self.public_ip
user = "ec2-user"
private_key = file("/logon.pem")
}
inline = [
"sudo yum install nginx -y",
"sudo service nginx start"
]
}
}
The above assumes that everything else is correct, e.g. the key file exist or security groups allow for ssh connection.

Terraform - Get a value from parameter store and pass to resource

We store our latest approved AMIs in AWS parameter store. When creating new instances with Terraform I would like to programatically get this AMI ID. I have a command to pull the AMI ID but I'm not sure how to use it with Terraform.
Here is the command I use to pull the AMI ID:
$(aws ssm get-parameter --name /path/to/ami --query 'Parameter.Value' --output text)
And here is my Terraform script:
resource "aws_instance" "nginx" {
ami = "ami-c58c1dd3" # pull value from parameter store
instance_type = "t2.micro"
#key_name = "${var.key_name}"
provisioner "remote-exec" {
inline = [
"sudo yum install nginx -y",
"sudo service nginx start"
]
}
}
How can I use the command to pull the AMI ID in the Terraform script?
You can use the aws_ssm_parameter data source to fetch the value of a parameter at runtime:
data "aws_ssm_parameter" "ami" {
name = "/path/to/ami"
}
resource "aws_instance" "nginx" {
ami = data.aws_ssm_parameter.ami.value # pull value from parameter store
instance_type = "t2.micro"
provisioner "remote-exec" {
inline = [
"sudo yum install nginx -y",
"sudo service nginx start"
]
}
}
However, a better approach might be to use the aws_ami data source to filter for the AMI you want more directly instead of pushing the AMI ID to SSM parameter store and then looking it up later. You can filter on a number of criteria including name, account owner and tags. Here's the example from the aws_instance resource documentation that is looking for the latest Ubuntu 20.04 AMI:
data "aws_ami" "ubuntu" {
most_recent = true
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
owners = ["099720109477"] # Canonical
}
resource "aws_instance" "web" {
ami = data.aws_ami.ubuntu.id
instance_type = "t2.micro"
tags = {
Name = "HelloWorld"
}
}
I recommend you use this approach since you already have the AMI ID stored at AWS SSM:
resource "aws_instance" "nginx" {
ami = data.aws_ssm_parameter.ami.value
instance_type = "t2.micro"
provisioner "remote-exec" {
inline = [
"sudo yum install nginx -y",
"sudo service nginx start"
]
}
}
data "aws_ssm_parameter" "ami" {
name = "/production/ami"
}

Terraform: provisioner couldn't be found

I have resource "aws_instance" "webserver" in my .tf file which contains provisioner "install-apache":
provider "aws" {
access_key = "ACCESS_KEY"
secret_key = "SECRET-KEY"
region = "us-east-1"
}
resource "aws_instance" "webserver" {
ami = "ami-b374d5a5"
instance_type = "t2.micro"
provisioner "install-apache" {
command = "apt-get install nginx"
}
}
After running terraform plan I've got an error:
* aws_instance.webserver: provisioner install-apache couldn't be found
According to the terraform documentation everything looks fine.
The provisioner value must be one of the following:
chef
file
local-exec
remote-exec
I believe in your case you want the remote-exec value
provider "aws" {
access_key = "ACCESS_KEY"
secret_key = "SECRET-KEY"
region = "us-east-1"
}
resource "aws_instance" "webserver" {
ami = "ami-b374d5a5"
instance_type = "t2.micro"
provisioner "remote-exec" {
inline = [
"apt-get install nginx"
]
}
}