In the previous example, we created an EC2 instance, which we wouldn’t be able to access, that is because we neither provisioned a new key pair nor used existing one, which we could see from the state report:
➜ terraform_demo grep key_name terraform.tfstate "key_name": "", ➜ terraform_demo
As you can see key_name is empty.
Now, if you already have a key pair which you are using to connect to your instance, which you will find
in EC2 Dashboard, NETWORK & SECURITY – Key Pairs:
then we can specify it in aws_instance section so EC2 can be accessed with that key:
resource "aws_instance" "ubuntu_zesty" { ami = "ami-6b7f610f" instance_type = "t2.micro" key_name = "myec2key" }
Let’s create an instance:
➜ terraform_demo vault read -field=value secret/aws | terraform apply --auto-approve var.secret_key Enter a value: aws_instance.ubuntu_zesty: Creating... ami: "" => "ami-6b7f610f" associate_public_ip_address: "" => "<computed>" availability_zone: "" => "<computed>" ebs_block_device.#: "" => "<computed>" ephemeral_block_device.#: "" => "<computed>" instance_state: "" => "<computed>" instance_type: "" => "t2.micro" ipv6_address_count: "" => "<computed>" ipv6_addresses.#: "" => "<computed>" key_name: "" => "myec2key" network_interface.#: "" => "<computed>" network_interface_id: "" => "<computed>" placement_group: "" => "<computed>" primary_network_interface_id: "" => "<computed>" private_dns: "" => "<computed>" private_ip: "" => "<computed>" public_dns: "" => "<computed>" public_ip: "" => "<computed>" root_block_device.#: "" => "<computed>" security_groups.#: "" => "<computed>" source_dest_check: "" => "true" subnet_id: "" => "<computed>" tenancy: "" => "<computed>" volume_tags.%: "" => "<computed>" vpc_security_group_ids.#: "" => "<computed>" aws_instance.ubuntu_zesty: Still creating... (10s elapsed) aws_instance.ubuntu_zesty: Creation complete after 17s (ID: i-00ebe9b4c1c18b286) Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
As you can see key_name is populated now, so we associated our instance with the existing key, meaning we can now use it to connect.
Let’ check the public_ip first:
➜ terraform_demo grep public_ip terraform.tfstate "associate_public_ip_address": "true", "public_ip": "35.177.75.181",
We are ready to connect now, I will run ssh with the command to get release info:
terraform_demo ssh ubuntu@35.177.75.181 -i myec2key.pem lsb_release -a Distributor ID: Ubuntu Description: Ubuntu 17.04 Release: 17.04 Codename: zesty No LSB modules are available. ➜ terraform_demo
If you can’t connect and getting ‘Operation timed out’:
➜ terraform_demo ssh ubuntu@35.177.75.181 -i myec2key.pem lsb_release -c ssh: connect to host 35.177.75.181 port 22: Operation timed out ➜ terraform_demo
make sure you can access port 22 on the other side, quick tcpdump will show something like below:
➜ ~ tcpdump -i en0 'port 22' tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on en0, link-type EN10MB (Ethernet), capture size 262144 bytes 23:06:50.187731 IP 192.168.1.3.58547 > ec2-35-177-75-181.eu-west-2.compute.amazonaws.com.ssh: Flags [S], seq 3506345055, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 421858571 ecr 0,sackOK,eol], length 0 23:06:50.502969 IP 192.168.1.3.58547 > ec2-35-177-75-181.eu-west-2.compute.amazonaws.com.ssh: Flags [S], seq 3506345055, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 421858885 ecr 0,sackOK,eol], length 0 23:06:50.621113 IP 192.168.1.3.58547 > ec2-35-177-75-181.eu-west-2.compute.amazonaws.com.ssh: Flags [S], seq 3506345055, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 421859003 ecr 0,sackOK,eol], length 0 23:06:50.739172 IP 192.168.1.3.58547 > ec2-35-177-75-181.eu-west-2.compute.amazonaws.com.ssh: Flags [S], seq 3506345055, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 4218591
As you can see your ssh client sends series of synchronisation requests([S]) and doesn’t get anything back. Normal sequence would be something like:
➜ ~ tcpdump -i en0 'port 22' tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on en0, link-type EN10MB (Ethernet), capture size 262144 bytes 23:05:02.319613 IP 192.168.1.3.58530 > ec2-35-177-75-181.eu-west-2.compute.amazonaws.com.ssh: Flags [S], seq 111698112, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 421750979 ecr 0,sackOK,eol], length 0 23:05:02.345666 IP ec2-35-177-75-181.eu-west-2.compute.amazonaws.com.ssh > 192.168.1.3.58530: Flags [S.], seq 2183189031, ack 111698113, win 26847, options [mss 1392,sackOK,TS val 812966100 ecr 421750979,nop,wscale 7], length 0 23:05:02.345736 IP 192.168.1.3.58530 > ec2-35-177-75-181.eu-west-2.compute.amazonaws.com.ssh: Flags [.], ack 1, win 4096, options [nop,nop,TS val 421751005 ecr 812966100], length 0 23
with a series of SYNC/SYNC ACK/ACK – if you want to know more about TCP handshake read this article which explains this in detail
So as you can see:
➜ terraform_demo grep security_groups terraform.tfstate "security_groups.#": "1", "security_groups.3814588639": "default", ➜ terraform_demo
it is using ‘default’ security group, now go to VPC dashboard, security group:
and make sure ssh/22 port is added to your ip address or all(0.0.0.0/0).
Provisioning a new key pair.
Now, let’s say you don’t have any keys, or you just want to provision a new key just for this EC2 instance.
Let’s destroy our instance first:
➜ terraform_demo vault read -field=value secret/aws | terraform destroy -force var.secret_key Enter a value: aws_instance.ubuntu_zesty: Refreshing state... (ID: i-00ebe9b4c1c18b286) aws_instance.ubuntu_zesty: Destroying... (ID: i-00ebe9b4c1c18b286) aws_instance.ubuntu_zesty: Still destroying... (ID: i-00ebe9b4c1c18b286, 10s elapsed) aws_instance.ubuntu_zesty: Still destroying... (ID: i-00ebe9b4c1c18b286, 20s elapsed) aws_instance.ubuntu_zesty: Still destroying... (ID: i-00ebe9b4c1c18b286, 30s elapsed) aws_instance.ubuntu_zesty: Still destroying... (ID: i-00ebe9b4c1c18b286, 40s elapsed) aws_instance.ubuntu_zesty: Still destroying... (ID: i-00ebe9b4c1c18b286, 50s elapsed) aws_instance.ubuntu_zesty: Destruction complete after 51s Destroy complete! Resources: 1 destroyed.
and then reprovision again with a new key, for this, you will need to generate a key first:
➜ terraform_demo ssh-keygen -f terraform_ec2_key Generating public/private rsa key pair. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in terraform_ec2_key. Your public key has been saved in terraform_ec2_key.pub. The key fingerprint is: SHA256:4O2exkz/gH8IgB3dXxrsJir8iyIT/R1WsPz5r1u69Iw kayanazimov@kayanazimov.local The key's randomart image is: +---[RSA 2048]----+ | . . . | | . o . o . | | o.o o o + | | ..ooo o = | | . ...S+ + | | . . o.*.o | | . . Oo+.o. . | | o . .o*oooo* | | o ...+..oE=+ | +----[SHA256]-----+ ➜ terraform_demo
We now have two files:
➜ terraform_demo ls terraform_ec2* terraform_ec2_key terraform_ec2_key.pub
We will need to provision public key, and keep private key safe and hidden:
provider "aws" { access_key = "AKIAIVBOWPGYHYWPZ2NQ" secret_key = "${var.secret_key}" region = "eu-west-2" } resource "aws_instance" "ubuntu_zesty" { ami = "ami-6b7f610f" instance_type = "t2.micro" key_name = "terraform_ec2_key" } resource "aws_key_pair" "terraform_ec2_key" { key_name = "terraform_ec2_key" public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDfMCqXraSPxvhL2LIGluGC7Y8UsV1PuMcH1L3u7zdHnMQl0CzAt+1yjqdcbu/OVDBMtoPfimTp5BxawuodDdEEewNSOonL517oSQqwdaunkoy6bioITMvj6iiG4ab3thy0BaT0MWb7Thbf8KDHPIxLm0fdgJHSOhXRb6TEToNCi+zm9BVYcKiYK6HBfnh4wp9CI2pyhZ1OEhly/8K+SjQzg4j8TR/5EH7JEiCl64Y5gXwNxLDyjHHiGMqk2sv6EfxRncroAYVhonG/N63Fkd1BTOIWLNovgId/ehw/+ejh2LHi5Y7+whgPzVqaFfzmhXW/RSRMaAmxeAoLZWDUpeGx kayanazimov@kayanazimov.local" // public_key = "${file("terraform_ec2_key.pub")}" }
As you can see we added key_name to aws_instance resource and defined public_key inside aws_key_pair resource,
alternatively you could refer to file as well instead putting contents, it is actually more preferable as less chances to make copy-paste mistake.
Let’s connect and show the key is added:
➜ terraform_demo ssh ubuntu@35.177.147.19 -i terraform_ec2_key cat .ssh/authorized_keys ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDyx+ksR4sayAn5Bg0esnqqqp5qvhUqEseV43J/ck8tdtUZe7qaof3Upm0mE6GCjMygGqxRNOVGWn5FGws7ILd5desdooNC0tIxa9OF/TmupGEEJ5NBxTZIeUl31+tBjM5wwO7+Cc1FfZBGy/9VQU6sv7zNsqz1a66Zeq4Jif9+31hpVzTmsdXC8cmdXzSrKiEGDRo6/eKqhzELHnNfPQ0xsvD0yjCx4nOcZnIPV4rl2k7goMblRL+p40kIbjOeDj9xb7GWtGvHncgRHrCCqpoDove8OtTikHO7wHCxISsCpkdNVDhkbDfCY1e0dMnFr4L24EVu5Zx4RPqNVhiarGx1 terraform_ec2_key ➜ terraform_demo