Files
kodekloud-engineer/100 - days of devops/devops-96.md

187 lines
6.4 KiB
Markdown

# 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)
```bash
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
```bash
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:
1. **`tls_private_key`** — generates the key pair **locally**. `algorithm = "RSA"` is what makes the
resulting AWS key pair type `rsa`; `rsa_bits = 4096` sets its strength.
2. **`aws_key_pair`** — uploads only the **public** half
(`tls_private_key.datacenter_kp.public_key_openssh`) under the name `datacenter-kp`. AWS stores
just the public key; because it's RSA, the key pair registers with `KeyType: 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_file` resource is
> included. It lives in Terraform state only. If you later need to SSH in, add a
> `local_sensitive_file` writing `tls_private_key.datacenter_kp.private_key_pem` with `0400`
> permissions.
### The default security group
```hcl
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 the `Name`
**tag**, 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
```hcl
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
```bash
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-instances` returns nothing, check the `Name` tag — the filter matches on that tag, not
> the Terraform resource label.