Managing Cloud Infrastructure as Code with Terraform
(Part 2)
In the previous post on Terraform, we introduced Terraform and showed how it could be used to provision an EC2 instance on AWS in the free tier. In this post, we're going to take things a step further, and demonstrate how you can use Terraform to set up a security group and an SSH key-pair to facilitate SSH access to that instance. If you're new to Terraform, you'll probably want to read part 1 first.
Setting up SSH access to an EC2 instance
Let's dive right into it and create a file called 'main.tf' in a new directory.
mkdir terraform-test
cd terraform-test
touch main.tf
In the previous post, we used the following code to configure an EC2 instance. Insert this code into your new 'main.tf' file.
terraform {
??required_providers {
????aws = {
??????source? = "hashicorp/aws"
????}
??}
??required_version = ">= 1.2.0"
}
provider "aws" {
??region? = "us-east-1"
}
resource "aws_instance" "my_server" {
??ami ? ? ? ? ? = "ami-0c7217cdde317cfec"
??instance_type = "t2.micro"
}
After that, you'll need to initialise Terraform in the new directory you created by running:
terraform init
Let's go ahead and view the execution plan, and, assuming that all looks OK, create the EC2 instance:
terraform plan
terraform apply
As noted in the previous post, we can't access this instance because it uses the default security group, which denies all inbound access.
In order to access the EC2 via SSH, we'll now need to add:
Replace the contents of your 'main.tf' file with the code below, which caters for these requirements.
terraform {
??required_providers {
????aws = {
??????source? = "hashicorp/aws"
????}
??}
??required_version = ">= 1.2.0"
}
provider "aws" {
??region? = "us-east-1"
}
resource "tls_private_key" "pk" {
??algorithm = "RSA"
??rsa_bits? = 4096
}
resource "aws_key_pair" "my_key_pair" {
??key_name ? = "my_server_key"
??public_key = tls_private_key.pk.public_key_openssh
}
resource "aws_security_group" "my_security_group" {
??name? ? ? ? = "my_server_sg"
??description = "Allow SSH inbound and all outbound traffic"
??ingress {
????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"]
??}
}
resource "aws_instance" "my_server" {
??ami ? ? ? ? ? ? ? = "ami-0c7217cdde317cfec"
??instance_type ? ? = "t2.micro"
??key_name? ? ? ? ? = aws_key_pair.my_key_pair.key_name
??security_groups ? = [aws_security_group.my_security_group.name]
}
output "instance_public_ip" {
??value = aws_instance.my_server.public_ip
}
output "ssh_private_key" {
??value = tls_private_key.pk.private_key_openssh
??sensitive = true
}
Let's walk through the modifications made above.
领英推荐
You'll notice that there is an argument 'sensitive = true' in the declaration of the 'ssh_private_key' output. This argument prevents Terraform from printing the SSH private key to the command line unless explicitly asked for. It's important to appreciate, however, that the SSH keys are still stored unencrypted in the Terraform state file. For this reason, it's generally a better practice to generate the keys separately and then add only the public key to the required resources once they have been provisioned. This means that the private key is not stored in the state file. The 'tls_private_key' resource is only intended to be used to create key-pairs for short-lived test or development environments like this one.
Applying the updates
Go ahead and view the execution plan using the following command:
terraform plan
You'll notice that Terraform is going to destroy the EC2 instance and create a new one in its place. This is because Terraform treats cloud resources as immutable entities, meaning that they cannot be modified in place. In this case, we want to add an SSH public key to the EC2 instance and also attach a security group, both of which require modifications to the EC2 instance, hence the need to replace it.
Once you're satisfied with the execution plan, go ahead and apply the changes.
terraform apply
Once Terraform has finished making the changes, the public IP address of the EC2 instance is printed to the terminal, but the SSH private key is not. We have to explicitly ask for it. In this case, we want the private key to be written to a file, so in the command below, the standard output is redirected to the 'my-private-key' file.
terraform output -raw ssh_private_key >my-private-key
Now you need to set the file permissions so that they meet the security standards of the SSH protocol:
chmod 400 my-private-key
Finally, you can connect to the EC2 instance! Run the following command, replacing '<public-ip-address>' with the IP address of the EC2 instance that was returned after you ran 'terraform apply'.
ssh -i my-private-key ubuntu@<public-ip-address>
When you're ready to tear down all of the infrastructure, simply run 'terraform destroy'.
Summary
In the previous post, we introduced Terraform and demonstrated how it can be used to provision an EC2 instance on AWS. In this post, we extended the configuration in order to make it possible to access the EC2 instance via SSH. We hope that you enjoyed this brief introduction to Terraform. If you are interested in learning more, or require assistance with using Terraform to manage your own cloud infrastructure, please feel free to leave a comment or get in touch with us directly.