# 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.