33 KiB
Task 1
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. This granular approach enables the team to execute the migration in gradual phases, ensuring smoother implementation and minimizing disruption to ongoing operations. By breaking down the migration into smaller tasks, the Nautilus DevOps team can systematically progress through each stage, allowing for better control, risk mitigation, and optimization of resources throughout the migration process.
For this task, create a key pair using Terraform with the following requirements:
Name of the key pair should be xfusion-kp-t1q1.
Key pair type must be rsa.
The private key file should be saved under /home/bob. The Terraform working directory is /home/bob/terraform/t1q1. Create the main.tf file (do not create a different .tf file) to accomplish this task.
Note: Right-click under the EXPLORER section in VS Code and select Open in Integrated Terminal to launch the terminal.
'xfusion-kp-t1q1' key pair was created using 'Terraform' and saved under '/home/bob'?
Solution
Key Pair — xfusion-kp-t1q1 (RSA, private key under /home/bob)
Terraform generates an RSA private key locally, imports its public half into AWS as a
key pair, and writes the .pem to /home/bob.
main.tf (in working dir /home/bob/terraform/t1q1)
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 6.0"
}
tls = {
source = "hashicorp/tls"
version = "~> 4.0"
}
local = {
source = "hashicorp/local"
version = "~> 2.5"
}
}
}
provider "aws" {
region = "us-east-1"
}
# Generate an RSA private key locally
resource "tls_private_key" "xfusion_kp" {
algorithm = "RSA"
rsa_bits = 4096
}
# Import the public half into AWS as an RSA key pair
resource "aws_key_pair" "xfusion_kp" {
key_name = "xfusion-kp-t1q1"
public_key = tls_private_key.xfusion_kp.public_key_openssh
}
# Save the private key to /home/bob
resource "local_sensitive_file" "xfusion_kp_pem" {
content = tls_private_key.xfusion_kp.private_key_pem
filename = "/home/bob/xfusion-kp-t1q1.pem"
file_permission = "0400"
}
How to run
cd /home/bob/terraform/t1q1
terraform init
terraform apply -auto-approve
How it works
Creating a downloadable key pair takes three coordinated resources across three providers — AWS doesn't hand back private key material on its own, so the private key is generated locally and only the public half is uploaded.
tls_private_key
algorithm = "RSA"— generates an RSA keypair. This is what makes the resulting AWS key pairtype = rsa(the type is derived from the imported key material, not set as an argument onaws_key_pair).rsa_bits = 4096— key strength. 2048 also works; 4096 is a stronger default.
The private key never leaves the local machine — it's held in Terraform state and written to disk in the last step.
aws_key_pair
key_name = "xfusion-kp-t1q1"— the key pair name, exactly as required.public_key = tls_private_key.xfusion_kp.public_key_openssh— imports the public half in OpenSSH format. AWS stores only the public key; because it's an RSA public key, the key pair registers withtype = rsa. The attribute reference also creates an implicit dependency so the TLS key is generated first.
local_sensitive_file
content = tls_private_key.xfusion_kp.private_key_pem— the PEM-encoded private key, pulled from the TLS resource.filename = "/home/bob/xfusion-kp-t1q1.pem"— the required location. The task says save it under/home/bob, so the file goes directly in that directory named after the key pair.file_permission = "0400"— read-only for the owner. A private key should never be world-readable, and strict graders/SSH clients reject loose permissions.- Using
local_sensitive_file(rather thanlocal_file) keeps the private key out of Terraform's plan/apply console output. If the lab'slocalprovider is very old and rejects it, swap tolocal_filewith the same arguments.
Verify
ls -l /home/bob/xfusion-kp-t1q1.pem
aws ec2 describe-key-pairs --key-names xfusion-kp-t1q1 \
--query 'KeyPairs[0].{Name:KeyName,Type:KeyType}'
Expected — the .pem file present with 0400 (-r--------) permissions, and the key
pair reporting KeyType: rsa.
Task 2
The Nautilus DevOps team has been creating a couple of services on AWS cloud. They have been breaking down the migration into smaller tasks, allowing for better control, risk mitigation, and optimization of resources throughout the migration process. Recently they came up with requirements mentioned below.
There is an instance named xfusion-ec2-t1q3 and an elastic-ip named xfusion-ec2-eip-t1q3 in us-east-1 region. Attach the xfusion-ec2-eip-t1q3 elastic-ip to the xfusion-ec2-t1q3 instance using Terraform only. The Terraform working directory is /home/bob/terraform/t1q3. Update the main.tf file (do not create a separate .tf file) to attach the specified Elastic IP to the instance.
Note: Right-click under the EXPLORER section in VS Code and select Open in Integrated Terminal to launch the terminal.
'xfusion-ec2-eip-t1q3' is attached to the 'xfusion-ec2-t1q3' instance using 'terraform'?
Solution
Attach Elastic IP — xfusion-ec2-eip-t1q3 → xfusion-ec2-t1q3
Both the instance (aws_instance.ec2) and the Elastic IP (aws_eip.ec2_eip) are
already managed in this main.tf. So no data sources are needed — you reference the
existing resources directly and add a single association resource.
main.tf (append the association; leave the existing two resources unchanged)
# Provision EC2 instance
resource "aws_instance" "ec2" {
ami = "ami-0c101f26f147fa7fd"
instance_type = "t2.micro"
subnet_id = "subnet-e79b9411489b0eca0"
vpc_security_group_ids = [
"sg-3ebc829d9883de7da"
]
tags = {
Name = "xfusion-ec2-t1q3"
}
}
# Provision Elastic IP
resource "aws_eip" "ec2_eip" {
tags = {
Name = "xfusion-ec2-eip-t1q3"
}
}
# Associate the Elastic IP with the instance
resource "aws_eip_association" "ec2_eip_assoc" {
allocation_id = aws_eip.ec2_eip.id
instance_id = aws_instance.ec2.id
}
How to run
cd /home/bob/terraform/t1q3
terraform plan # should show only the new aws_eip_association to add
terraform apply -auto-approve
How it works
Referencing managed resources (not data sources)
Because both the instance and the EIP already live in this configuration, you point the association straight at their resource attributes:
allocation_id = aws_eip.ec2_eip.id— a VPC Elastic IP'sidis its allocation ID (eipalloc-...), which is what an association binds. (Data sources would only be needed if these were created outside this config — here they aren't.)instance_id = aws_instance.ec2.id— the instance'si-...ID.
Referencing the resource attributes (rather than hardcoding IDs) creates implicit dependencies: Terraform knows the association depends on both the instance and the EIP, orders creation correctly, and the plan cleanly shows only the new association being added — the two existing resources are untouched.
aws_eip_association
This standalone resource represents the binding between the EIP and the instance. On
apply, Terraform calls AssociateAddress, and the instance's public-facing IP becomes
the Elastic IP. Keeping the association as its own resource (rather than folding an
instance = ... argument into the aws_eip block) is the cleaner, more explicit
pattern and isolates the attach/detach lifecycle — destroying just this resource would
detach the EIP while leaving the instance and EIP intact.
The
planshould report 1 to add, 0 to change, 0 to destroy. If it wants to change or replace the instance or EIP, something in the existing blocks was altered — appending only the association keeps them clean.
Verify
aws ec2 describe-addresses \
--filters Name=tag:Name,Values=xfusion-ec2-eip-t1q3 \
--query 'Addresses[0].{EIP:PublicIp,InstanceId:InstanceId,AssocId:AssociationId}'
aws ec2 describe-instances \
--filters Name=tag:Name,Values=xfusion-ec2-t1q3 \
--query 'Reservations[0].Instances[0].PublicIpAddress'
Expected — the address shows a populated InstanceId (the xfusion-ec2-t1q3 instance)
and an AssociationId, and the instance's PublicIpAddress equals the EIP's
PublicIp.
Task 3
When establishing infrastructure on the AWS cloud, Identity and Access Management (IAM) is among the first and most critical services to configure. IAM facilitates the creation and management of user accounts, groups, roles, policies, and other access controls. The Nautilus DevOps team is currently in the process of configuring these resources and has outlined the following requirements:
For this task, create an IAM user named iamuser_yousuf_t2q1 using terraform. The Terraform working directory is /home/bob/terraform/t2q1. Create the main.tf file (do not create a different .tf file) to accomplish this task.
Note: Right-click under the EXPLORER section in VS Code and select Open in Integrated Terminal to launch the terminal.
Solution
IAM User — iamuser_yousuf_t2q1
Terraform solution to create a single IAM user.
main.tf (in working dir /home/bob/terraform/t2q1)
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 6.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
resource "aws_iam_user" "yousuf" {
name = "iamuser_yousuf_t2q1"
}
How to run
cd /home/bob/terraform/t2q1
terraform init
terraform apply -auto-approve
How it works
aws_iam_user
One resource is all this task needs. The name argument sets the IAM user's
identifier to iamuser_yousuf_t2q1, exactly as required.
-
The
iamuser_prefix is enforced. These locked-down sandboxes require IAM user names to start withiamuser_. The supplied name already satisfies that, so the create stays inside the login user's permission scope and won't be denied. -
IAM is global. The
regionin the provider is needed to initialize and authenticate, but IAM resources aren't regional — the user is visible account-wide regardless of region. -
No policies, keys, or login profile. The task asks only for the user to exist, so nothing is attached. This keeps the config minimal and avoids the custom-policy / attach restrictions these sandboxes enforce (attaching permissions broader than the login user has would fail with
AccessDenied).
Why nothing else is needed
An IAM user with no attached permissions is perfectly valid — it simply can't do
anything yet. Groups, policies, access keys, and login profiles are all separate
resources added later as requirements dictate. For "create a user named X," one
aws_iam_user block is the complete answer.
Verify
aws iam get-user --user-name iamuser_yousuf_t2q1 \
--query 'User.{Name:UserName,Id:UserId,Arn:Arn}'
Expected — the user's name, a unique ID, and an ARN of the form
arn:aws:iam::<account-id>:user/iamuser_yousuf_t2q1.
Task 4
The Nautilus DevOps team has been creating a couple of services on AWS cloud. They have been breaking down the migration into smaller tasks, allowing for better control, risk mitigation, and optimization of resources throughout the migration process. Recently they came up with requirements mentioned below.
An IAM user named iamuser_yousuf_t2q3 and a policy named iampolicy_yousuf_t2q3 already exists. Use Terraform to attach the IAM policy iampolicy_yousuf_t2q3 to the IAM user iamuser_yousuf_t2q3. The Terraform working directory is /home/bob/terraform. Update the main.tf file (do not create a separate .tf file) to attach the specified IAM policy to the IAM user.
Note: Right-click under the EXPLORER section in VS Code and select Open in Integrated Terminal to launch the terminal.
Solution
Attach IAM Policy — iampolicy_yousuf_t2q3 → iamuser_yousuf_t2q3
The user (aws_iam_user.user) and the customer-managed policy (aws_iam_policy.policy)
already exist in this main.tf. The task is to bind them, which is one appended
aws_iam_user_policy_attachment resource referencing both.
main.tf (append the attachment; leave the existing two resources unchanged)
# Create IAM user
resource "aws_iam_user" "user" {
name = "iamuser_yousuf_t2q3"
tags = {
Name = "iamuser_yousuf_t2q3"
}
}
# Create IAM Policy
resource "aws_iam_policy" "policy" {
name = "iampolicy_yousuf_t2q3"
description = "IAM policy allowing EC2 read actions for yousuf"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = ["ec2:Read*"]
Resource = "*"
}
]
})
}
# Attach the policy to the user
resource "aws_iam_user_policy_attachment" "attach" {
user = aws_iam_user.user.name
policy_arn = aws_iam_policy.policy.arn
}
How to run
cd /home/bob/terraform
terraform plan # should show only the new attachment to add
terraform apply -auto-approve
How it works
aws_iam_user_policy_attachment
This resource attaches a managed policy (AWS-managed or customer-managed) to an IAM
user. It's the right resource here because iampolicy_yousuf_t2q3 is a standalone
customer-managed policy with its own ARN — as opposed to an inline policy, which
would use aws_iam_user_policy and embed the JSON directly in the user.
user = aws_iam_user.user.name— the attachment targets the user by name.policy_arn = aws_iam_policy.policy.arn— managed-policy attachments are made by ARN. Theaws_iam_policyresource exposes its generatedarn, so referencing the attribute avoids hardcoding the account ID.
Referencing both resources by attribute creates implicit dependencies: Terraform keeps the user and policy first, then the attachment. The plan shows only the attachment being added — the existing user and policy are untouched.
Managed vs. inline — why this resource
| Resource | Use when |
|---|---|
aws_iam_user_policy_attachment |
Attaching an existing managed policy (this task). |
aws_iam_policy_attachment |
Attaching one policy to many principals at once — avoid; it's exclusive and detaches principals it doesn't manage. |
aws_iam_user_policy |
Defining an inline policy embedded in the user. |
aws_iam_user_policy_attachment is the correct, non-exclusive choice for wiring one
managed policy to one user.
Sandbox note
The policy grants only ec2:Read* — read-only actions well within the login user's
permission scope, so the attach won't trip the anti-privilege-escalation lockdown.
Attaching a policy broader than your login user has is what triggers AccessDenied;
that isn't the case here.
Verify
aws iam list-attached-user-policies --user-name iamuser_yousuf_t2q3 \
--query 'AttachedPolicies[*].{Name:PolicyName,Arn:PolicyArn}'
Expected — a list containing iampolicy_yousuf_t2q3 with its ARN.
Task 5
The Nautilus DevOps team needs to set up an SNS topic for sending notifications. They need to create an SNS topic with the following specifications:
- The topic name should be xfusion-notifications-t3q4.
Use Terraform to create this SNS topic. The Terraform working directory is /home/bob/terraform/t3q4. Create the main.tf file (do not create a different .tf file) to accomplish this task.
Note: Right-click under the EXPLORER section in VS Code and select Open in Integrated Terminal to launch the terminal.
SNS topic 'xfusion-notifications-t3q4' was created using 'Terraform'?
Solution
SNS Topic — xfusion-notifications-t3q4
Terraform solution to create a standard SNS topic.
main.tf (in working dir /home/bob/terraform/t3q4)
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 6.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
resource "aws_sns_topic" "xfusion_notifications" {
name = "xfusion-notifications-t3q4"
}
How to run
cd /home/bob/terraform/t3q4
terraform init
terraform apply -auto-approve
How it works
aws_sns_topic
One resource is all this task needs. The name argument sets the topic name to
xfusion-notifications-t3q4, exactly as required.
-
Standard topic by default. SNS has two classes: Standard (high throughput, best-effort ordering, at-least-once delivery) and FIFO (strict ordering, exactly-once, name must end in
.fifo). With no.fifosuffix andfifo_topicunset, this creates a Standard topic — the right choice for general notifications. -
A topic is just the pub/sub channel. Creating it gives you an endpoint publishers send to. Nothing receives messages until you add subscriptions (email, SMS, SQS, Lambda, HTTP, etc.). The task only asks for the topic, so no
aws_sns_topic_subscriptionresources are included. -
No access policy specified. By default SNS attaches a policy allowing the topic owner (this account) to publish and manage it — sufficient for the task.
Verify
TOPIC_ARN=$(aws sns list-topics \
--query "Topics[?ends_with(TopicArn, ':xfusion-notifications-t3q4')].TopicArn | [0]" \
--output text)
echo "[$TOPIC_ARN]"
aws sns get-topic-attributes --topic-arn "$TOPIC_ARN" \
--query 'Attributes.{Arn:TopicArn,Owner:Owner}'
Expected — a topic ARN of the form
arn:aws:sns:us-east-1:<account-id>:xfusion-notifications-t3q4.
Task 6
The Nautilus DevOps team needs to set up a DynamoDB table for storing user data. They need to create a DynamoDB table with the following specifications:
-
The table name should be xfusion-users-t3q1.
-
The primary key should be xfusion_id_t3q1 (String).
-
The table should use PAY_PER_REQUEST billing mode.
Use Terraform to create this DynamoDB table. The Terraform working directory is /home/bob/terraform/t3q1. Create the main.tf file (do not create a different .tf file) to create the DynamoDB table.
Note: Right-click under the EXPLORER section in VS Code and select Open in Integrated Terminal to launch the terminal.
DynamoDB table 'xfusion-users-t3q1' was created using 'Terraform' with 'PAY_PER_REQUEST' billing mode?
Solution
DynamoDB Table — xfusion-users-t3q1
Terraform solution to create an on-demand DynamoDB table keyed on a string partition key.
main.tf (in working dir /home/bob/terraform/t3q1)
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 6.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
resource "aws_dynamodb_table" "xfusion_users" {
name = "xfusion-users-t3q1"
billing_mode = "PAY_PER_REQUEST"
hash_key = "xfusion_id_t3q1"
attribute {
name = "xfusion_id_t3q1"
type = "S"
}
}
How to run
cd /home/bob/terraform/t3q1
terraform init
terraform apply -auto-approve
How it works
aws_dynamodb_table
A single resource provisions the whole table.
-
name = "xfusion-users-t3q1"— the table name, exactly as required. -
hash_key = "xfusion_id_t3q1"— sets the table's partition key (DynamoDB's API calls it the "hash key"). This is the primary key the task asks for. Norange_keyis defined, soxfusion_id_t3q1alone uniquely identifies each item — a simple primary key rather than a composite one. -
attributeblock — DynamoDB is schemaless for non-key fields, so you only ever declare attributes that participate in a key. Herexfusion_id_t3q1is the partition key, so it must be declared with its type.type = "S"marks it as a String (valid types:Sstring,Nnumber,Bbinary). Referencing ahash_keywithout a matchingattributeblock fails validation with "all attributes must be indexed." -
billing_mode = "PAY_PER_REQUEST"— puts the table in on-demand mode. You pay per read/write request with no capacity to provision, and DynamoDB auto-scales to traffic. Because of this mode,read_capacity/write_capacityare omitted — they're only valid underPROVISIONEDbilling, and setting them here would be a config error.
Why on-demand fits here
Beyond being the task requirement, PAY_PER_REQUEST is the simplest correct choice: no
throughput math, no capacity planning, and it avoids the low provisioned-capacity caps
that constrained sandbox environments impose on PROVISIONED tables. The table comes
up ready to take reads and writes immediately.
Verify
aws dynamodb describe-table --table-name xfusion-users-t3q1 \
--query 'Table.{Name:TableName,Billing:BillingModeSummary.BillingMode,Key:KeySchema,Attrs:AttributeDefinitions,Status:TableStatus}'
Expected — BillingMode: PAY_PER_REQUEST, key schema with xfusion_id_t3q1 as HASH,
an attribute definition of xfusion_id_t3q1 type S, and TableStatus: ACTIVE (a few
seconds after create).
Task 7
As part of the data migration process, the Nautilus DevOps team is actively creating several S3 buckets on AWS. They plan to utilize both private and public S3 buckets to store the relevant data. Given the ongoing migration of other infrastructure to AWS, it is logical to consolidate data storage within the AWS environment as well.
Create a public S3 bucket named xfusion-s3-7078-t4q2 using Terraform.
Ensure the bucket is accessible publicly once created by setting the proper ACL.
The Terraform working directory is /home/bob/terraform/t4q2. Create the main.tf file (do not create a different .tf file) to accomplish this task.
Notes:
Create the resources only in the us-east-1 region. Right-click under the EXPLORER section in VS Code and select Open in Integrated Terminal to launch the terminal. The name of the S3 bucket should be based on xfusion-s3-7078-t4q2. You can use the ACL settings to ensure the bucket is publicly accessible.
'xfusion-s3-7078-t4q2' Public S3 bucket was created using 'Terraform'?
Solution
Public S3 Bucket — xfusion-s3-7078-t4q2
Making a bucket publicly readable via ACL requires undoing two modern AWS defaults
first: ACLs are disabled (BucketOwnerEnforced) and public access is blocked. A bare
acl = "public-read" errors with AccessControlListNotSupported without the enabling
resources, in the right order.
main.tf (in working dir /home/bob/terraform/t4q2)
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 6.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
resource "aws_s3_bucket" "xfusion" {
bucket = "xfusion-s3-7078-t4q2"
}
# Re-enable ACLs (default is BucketOwnerEnforced, which disables them)
resource "aws_s3_bucket_ownership_controls" "xfusion" {
bucket = aws_s3_bucket.xfusion.id
rule {
object_ownership = "BucketOwnerPreferred"
}
}
# Lift the public-access block so a public ACL is allowed
resource "aws_s3_bucket_public_access_block" "xfusion" {
bucket = aws_s3_bucket.xfusion.id
block_public_acls = false
block_public_policy = false
ignore_public_acls = false
restrict_public_buckets = false
}
# Now the public ACL will actually take
resource "aws_s3_bucket_acl" "xfusion" {
bucket = aws_s3_bucket.xfusion.id
acl = "public-read"
depends_on = [
aws_s3_bucket_ownership_controls.xfusion,
aws_s3_bucket_public_access_block.xfusion,
]
}
How to run
cd /home/bob/terraform/t4q2
terraform init
terraform apply -auto-approve
How it works
Order of operations is the whole trick
Since 2023 AWS creates buckets with ACLs disabled and Block Public Access on. To apply a public-read ACL you must, in this order:
aws_s3_bucket_ownership_controls→BucketOwnerPreferred— re-enables ACLs (the defaultBucketOwnerEnforceddisables them entirely).ObjectWriteralso works;BucketOwnerPreferredis the safe pick.aws_s3_bucket_public_access_block→ all four flagsfalse— lifts the block. Any one lefttruewill silently strip or reject the public ACL.aws_s3_bucket_acl→public-read— the actual public grant.
The depends_on on the ACL resource forces steps 1 and 2 to complete before the
ACL is applied. Without it, Terraform may race and hit AccessControlListNotSupported
or AccessDenied.
Why ACL, not a bucket policy
The task explicitly says to make the bucket public via ACL. acl = "public-read"
grants the AllUsers group READ on the bucket — that's the ACL lever the task asks
for, as opposed to an aws_s3_bucket_policy with a public Principal.
Verify
aws s3api get-bucket-acl --bucket xfusion-s3-7078-t4q2 \
--query 'Grants[?Grantee.URI!=`null`].{Grantee:Grantee.URI,Perm:Permission}'
Expected — a grant to the AllUsers group
(http://acs.amazonaws.com/groups/global/AllUsers) with READ. That's the public-read
confirmation.
Task 8
As part of the data migration process, the Nautilus DevOps team is actively creating several S3 buckets on AWS using Terraform. They plan to utilize both private and public S3 buckets to store the relevant data. Given the ongoing migration of other infrastructure to AWS, it is logical to consolidate data storage within the AWS environment as well.
Create an S3 bucket using Terraform with the following details:
-
The name of the S3 bucket must be xfusion-s3-7078-t4q1.
-
The S3 bucket must block all public access, making it a private bucket.
The Terraform working directory is /home/bob/terraform/t4q1. Create the main.tf file (do not create a different .tf file) to accomplish this task.
Notes:
Use Terraform to provision the S3 bucket. Right-click under the EXPLORER section in VS Code and select Open in Integrated Terminal to launch the terminal. Ensure the resources are created in the us-east-1 region. The bucket must have block public access enabled to restrict any public access.
'xfusion-s3-7078-t4q1' private S3 bucket was created using 'terraform'?
Solution
Private S3 Bucket — xfusion-s3-7078-t4q1
Terraform solution for a fully private bucket in us-east-1, with all public access
blocked.
main.tf (in working dir /home/bob/terraform/t4q1)
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 6.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
resource "aws_s3_bucket" "xfusion" {
bucket = "xfusion-s3-7078-t4q1"
}
resource "aws_s3_bucket_public_access_block" "xfusion" {
bucket = aws_s3_bucket.xfusion.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
How to run
cd /home/bob/terraform/t4q1
terraform init
terraform apply -auto-approve
How it works
aws_s3_bucket
Creates the bucket with the required name. Modern buckets are already private by default, but the task explicitly wants Block Public Access enabled, which is a separate resource.
aws_s3_bucket_public_access_block
This is the resource that satisfies the requirement. It manages the four independent
Block Public Access (BPA) switches; all four true guarantees the bucket can never be
exposed publicly, regardless of any ACL or policy attached later.
| Flag | true means |
|---|---|
block_public_acls |
Reject any new request applying a public ACL. |
ignore_public_acls |
Ignore any public ACLs already present. |
block_public_policy |
Reject any new public bucket policy. |
restrict_public_buckets |
If a public policy exists, restrict access to the owner / AWS services only. |
The distinction: block_* flags act at write time (stop you adding public grants),
while ignore_* / restrict_* act at evaluation time (neutralize grants already
there). All four true covers both directions — which is what "block all public
access" means.
Why no ACL / ownership resources here
Unlike a public bucket, a private one needs no aws_s3_bucket_acl or
aws_s3_bucket_ownership_controls. AWS defaults new buckets to BucketOwnerEnforced
(ACLs disabled) and applies BPA — both push toward private. We move with the defaults,
so the config stays minimal.
Verify
aws s3api get-public-access-block --bucket xfusion-s3-7078-t4q1 \
--query 'PublicAccessBlockConfiguration'
Expected — all four true:
{
"BlockPublicAcls": true,
"IgnorePublicAcls": true,
"BlockPublicPolicy": true,
"RestrictPublicBuckets": true
}
Task 9
The Nautilus DevOps team is strategically planning the migration of a portion of their infrastructure to the AWS cloud. Acknowledging the magnitude of this endeavor, they have chosen to tackle the migration incrementally rather than as a single, massive transition. Their approach involves creating Virtual Private Clouds (VPCs) as the initial step, as they will be provisioning various services under different VPCs.
Create a VPC named xfusion-vpc-t5q2 in us-east-1 region with 192.168.0.0/24 IPv4 CIDR using terraform.
The Terraform working directory is /home/bob/terraform/t5q2. Create the main.tf file (do not create a different .tf file) to accomplish this task.
Note: Right-click under the EXPLORER section in VS Code and select Open in Integrated Terminal to launch the terminal.
'xfusion-vpc-t5q2' was created using 'terraform'?
Solution
VPC — xfusion-vpc-t5q2 (CIDR 192.168.0.0/24)
Terraform solution to create a VPC with a specific IPv4 CIDR block.
main.tf (in working dir /home/bob/terraform/t5q2)
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 6.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
resource "aws_vpc" "xfusion_vpc" {
cidr_block = "192.168.0.0/24"
tags = {
Name = "xfusion-vpc-t5q2"
}
}
How to run
cd /home/bob/terraform/t5q2
terraform init
terraform apply -auto-approve
How it works
aws_vpc
One resource creates the VPC.
cidr_block = "192.168.0.0/24"— the required IPv4 range. A/24gives 256 addresses (minus the 5 AWS reserves per subnet when you later carve subnets out).tags = { Name = "xfusion-vpc-t5q2" }— a VPC has no native name field, so theNametag is what the console and graders read as its name. Don't skip it — without the tag the VPC exists but appears unnamed.- Region comes from the provider (
us-east-1).
Verify
aws ec2 describe-vpcs \
--filters Name=tag:Name,Values=xfusion-vpc-t5q2 \
--query 'Vpcs[0].{Id:VpcId,Cidr:CidrBlock,Name:Tags[?Key==`Name`]|[0].Value}'
Expected — the VPC ID, CidrBlock: 192.168.0.0/24, and Name: xfusion-vpc-t5q2.
Task 10
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. This granular approach enables the team to execute the migration in gradual phases, ensuring smoother implementation and minimizing disruption to ongoing operations. By breaking down the migration into smaller tasks, the Nautilus DevOps team can systematically progress through each stage, allowing for better control, risk mitigation, and optimization of resources throughout the migration process.
Create a VPC named xfusion-vpc-t5q1 in region us-east-1 with any IPv4 CIDR block through terraform.
The Terraform working directory is /home/bob/terraform/t5q1. Create the main.tf file (do not create a different .tf file) to accomplish this task.
Note: Right-click under the EXPLORER section in VS Code and select Open in Integrated Terminal to launch the terminal.
'xfusion-vpc-t5q1' was created using 'terraform'?
Solution
VPC — xfusion-vpc-t5q1 (any IPv4 CIDR)
Terraform solution to create a VPC. The task allows any IPv4 CIDR, so a conventional
private /16 is used.
main.tf (in working dir /home/bob/terraform/t5q1)
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 6.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
resource "aws_vpc" "xfusion_vpc" {
cidr_block = "10.0.0.0/16"
tags = {
Name = "xfusion-vpc-t5q1"
}
}
How to run
cd /home/bob/terraform/t5q1
terraform init
terraform apply -auto-approve
How it works
aws_vpc
One resource creates the VPC.
cidr_block = "10.0.0.0/16"— the task allows any IPv4 block, so this uses a standard RFC 1918 private range. A/16provides 65,536 addresses — plenty of room to carve subnets from later. Any valid private CIDR (e.g.172.16.0.0/16,192.168.0.0/24) would satisfy the requirement equally;10.0.0.0/16is the conventional default.tags = { Name = "xfusion-vpc-t5q1" }— a VPC has no native name field, so theNametag is what the console and graders read as its name.- Region comes from the provider (
us-east-1).
Verify
aws ec2 describe-vpcs \
--filters Name=tag:Name,Values=xfusion-vpc-t5q1 \
--query 'Vpcs[0].{Id:VpcId,Cidr:CidrBlock,Name:Tags[?Key==`Name`]|[0].Value}'
Expected — the VPC ID, CidrBlock: 10.0.0.0/16, and Name: xfusion-vpc-t5q1.