Managing Cloud Infrastructure as Code with Terraform
Image credit: https://www.scalefactory.com/blog/2020/06/25/what-we-are-looking-forward-to-in-terraform-0.13/

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:

  • a security group, allowing inbound traffic on port 22; and
  • an SSH key-pair

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.

  1. A resource 'tls_private_key' is used to generate an SSH key-pair. This is logical resource, which means that no cloud resources are provisioned, but Terraform does generate an SSH key-pair, which it stores in the state file. We give AWS the public key using the 'aws_key_pair' resource. This is achieved by referencing the public key generated by the 'tls_private_key' resource ('public_key = tls_private_key.pk.public_key_openssh'). Finally, in order to place the public key onto the EC2 instance, we reference it in the 'key_name' parameter inside the 'aws_instance' resource block that defines the EC2 instance.
  2. A resource 'aws_security_group' is used to generate an AWS security group. This security group has rules that allow all outbound traffic and all inbound traffic on port 22 (default SSH port). We also have to reference this security group in the 'security_groups' parameter inside the 'aws_instance' resource block.
  3. There are also two "output" blocks in the code above. Outputs make it possible to access values that are created when Terraform creates or changes infrastructure. In this case, we want to know the value of the SSH private key and the public IP address of the instance so that we can access it via SSH.

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.


要查看或添加评论,请登录

Fathom Data的更多文章

社区洞察

其他会员也浏览了