6.4 KiB
Assignment
The Nautilus DevOps team is strategizing the migration of a portion of their infrastructure to the AWS cloud. Recognizing the scale of this undertaking, they have opted to approach the migration in incremental steps rather than as a single massive transition. To achieve this, they have segmented large tasks into smaller, more manageable units.
For this task, create an EC2 instance using Terraform with the following requirements:
The EC2 instance must use the value datacenter-ec2 as its Name tag, which defines the instance name in AWS.
Use the Amazon Linux ami-0c101f26f147fa7fd to launch this instance.
The Instance type must be t2.micro.
Create a new RSA key named datacenter-kp.
Attach the default (available by default) security group.
The Terraform working directory is /home/bob/terraform. Create the main.tf file (do not create a different .tf file) to provision the instance.
Note: Right-click under the EXPLORER section in VS Code and select Open in Integrated Terminal to launch the terminal.
Solution
Terraform EC2 Instance — datacenter-ec2
Launch a t2.micro instance with a newly-created RSA key pair and the default security group.
Create main.tf (heredoc → file)
cd /home/bob/terraform
cat > main.tf <<'EOF'
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 6.0"
}
tls = {
source = "hashicorp/tls"
version = "~> 4.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
# --- New RSA key pair ---
resource "tls_private_key" "datacenter_kp" {
algorithm = "RSA"
rsa_bits = 4096
}
resource "aws_key_pair" "datacenter_kp" {
key_name = "datacenter-kp"
public_key = tls_private_key.datacenter_kp.public_key_openssh
}
# --- Default VPC and its default security group ---
data "aws_vpc" "default" {
default = true
}
data "aws_security_group" "default" {
vpc_id = data.aws_vpc.default.id
name = "default"
}
# --- EC2 instance ---
resource "aws_instance" "datacenter_ec2" {
ami = "ami-0c101f26f147fa7fd"
instance_type = "t2.micro"
key_name = aws_key_pair.datacenter_kp.key_name
vpc_security_group_ids = [data.aws_security_group.default.id]
credit_specification {
cpu_credits = "standard"
}
tags = {
Name = "datacenter-ec2"
}
}
EOF
How to run
cd /home/bob/terraform
terraform init
terraform apply -auto-approve
How it works
The heredoc
cat > main.tf <<'EOF' writes the file in one shot; the quoted 'EOF' stops the shell from
expanding anything in the HCL. Everything goes in main.tf as the task requires — no separate
provider or key files.
The RSA key pair (two resources)
AWS never hands back private key material, so creating a usable key pair takes two resources across two providers:
tls_private_key— generates the key pair locally.algorithm = "RSA"is what makes the resulting AWS key pair typersa;rsa_bits = 4096sets its strength.aws_key_pair— uploads only the public half (tls_private_key.datacenter_kp.public_key_openssh) under the namedatacenter-kp. AWS stores just the public key; because it's RSA, the key pair registers withKeyType: rsa.
Referencing the TLS resource's attribute creates an implicit dependency, so Terraform generates the key before trying to import it.
The task doesn't ask for the private key to be saved to disk, so no
local_fileresource is included. It lives in Terraform state only. If you later need to SSH in, add alocal_sensitive_filewritingtls_private_key.datacenter_kp.private_key_pemwith0400permissions.
The default security group
data "aws_vpc" "default" { default = true }
data "aws_security_group" "default" {
vpc_id = data.aws_vpc.default.id
name = "default"
}
Two data sources read existing infrastructure rather than creating it: the account's default VPC,
then the security group named default within that VPC. Scoping by vpc_id matters — every VPC
has its own group named "default", so the name alone is ambiguous.
The group is then attached via vpc_security_group_ids, which takes a list of security group
IDs. (The older security_groups argument takes names and is for EC2-Classic; on modern VPC
instances vpc_security_group_ids is correct.)
Using data sources keeps Terraform from taking ownership of the default SG — it only references it.
The instance
ami = "ami-0c101f26f147fa7fd"— hardcoded exactly as given, so no AMI lookup data source is needed.instance_type = "t2.micro"— as required.key_name = aws_key_pair.datacenter_kp.key_name— attaches the key pair by reference, producing an implicit dependency so the key exists before the instance launches.tags = { Name = "datacenter-ec2" }— an EC2 instance's displayed name comes from theNametag, not a native field. Omit it and the instance runs but appears unnamed — the usual way to fail this requirement. The Terraform resource label (datacenter_ec2) is unrelated; it's only an internal reference.
Why credit_specification is pinned
credit_specification {
cpu_credits = "standard"
}
Burstable T-family instances run in either standard or unlimited CPU-credit mode. In
unlimited, an instance can burn credits beyond its baseline and incur surcharge billing — which
constrained sandbox environments actively police, sometimes by resetting the instance or suspending
the session. t2.micro defaults to standard, so this is belt-and-braces, but pinning it removes
any chance of the mode drifting to unlimited.
Verify
aws ec2 describe-instances \
--filters Name=tag:Name,Values=datacenter-ec2 Name=instance-state-name,Values=pending,running \
--query 'Reservations[0].Instances[0].{Id:InstanceId,Type:InstanceType,Key:KeyName,SG:SecurityGroups[0].GroupName,State:State.Name}'
aws ec2 describe-key-pairs --key-names datacenter-kp \
--query 'KeyPairs[0].{Name:KeyName,Type:KeyType}'
Expected — the instance showing InstanceType: t2.micro, KeyName: datacenter-kp, security group
default, and state pending then running (it takes a minute or two); and the key pair reporting
KeyType: rsa.
If
describe-instancesreturns nothing, check theNametag — the filter matches on that tag, not the Terraform resource label.