docs: add AWS certification notes (labs 1-50)
This commit is contained in:
185
aws-45.md
Normal file
185
aws-45.md
Normal file
@@ -0,0 +1,185 @@
|
||||
## Task 45
|
||||
|
||||
The Nautilus DevOps team is tasked with enabling internet access for an EC2 instance running in a private subnet. This instance should be able to upload a test file to a public S3 bucket once it can access the internet. To achieve this, the team must set up a NAT Gateway in a public subnet within the same VPC.
|
||||
|
||||
1) A VPC named xfusion-priv-vpc and a private subnet xfusion-priv-subnet have already been created.
|
||||
2) An EC2 instance named xfusion-priv-ec2 is already running in the private subnet.
|
||||
3) The EC2 instance is configured with a cron job that uploads a test file to a bucket xfusion-nat-285654546 once internet is accessible.
|
||||
|
||||
Your task is to:
|
||||
|
||||
Create a public subnet named xfusion-pub-subnet in the same VPC.
|
||||
Create an Internet Gateway and attach it to the VPC.
|
||||
Create a route table xfusion-pub-rt and associate it with the public subnet.
|
||||
Allocate an Elastic IP and create a NAT Gateway named xfusion-natgw.
|
||||
Update the private route table to route 0.0.0.0/0 traffic via the NAT Gateway.
|
||||
Once complete, verify that the EC2 instance can reach the internet by confirming the presence of the test file in the S3 bucket xfusion-nat-285654546. After completing all the configuration, please wait a few minutes for the test file to appear in the bucket, as it may take 2–3 minutes.
|
||||
|
||||
### Solution
|
||||
|
||||
# NAT Gateway Task (xfusion-priv-vpc)
|
||||
|
||||
The **managed NAT Gateway** version — contrast with the earlier NAT *instance* task, which needed a self-managed EC2 box with source/dest-check disabled, IP forwarding, and iptables MASQUERADE. A NAT **Gateway** is a fully AWS-managed resource: no instance, no OS config, no source/dest check, auto-scaling and HA within its AZ. You just place it in a public subnet, give it an EIP, and route the private subnet's default route at it. Much less to get wrong.
|
||||
|
||||
The architecture: private subnet → its route table `0.0.0.0/0 → NAT GW` → NAT GW (in public subnet) → public subnet's route table `0.0.0.0/0 → IGW` → internet → S3. Two route tables, two different default routes.
|
||||
|
||||
Run on `aws-client`.
|
||||
|
||||
## Phase 1 — Discover VPC + private subnet
|
||||
|
||||
```bash
|
||||
REGION=us-east-1
|
||||
|
||||
VPC_ID=$(aws ec2 describe-vpcs --filters Name=tag:Name,Values=xfusion-priv-vpc \
|
||||
--region $REGION --query 'Vpcs[0].VpcId' --output text)
|
||||
VPC_CIDR=$(aws ec2 describe-vpcs --vpc-ids $VPC_ID --region $REGION \
|
||||
--query 'Vpcs[0].CidrBlock' --output text)
|
||||
|
||||
PRIV_SUBNET=$(aws ec2 describe-subnets --filters "Name=tag:Name,Values=xfusion-priv-subnet" \
|
||||
--region $REGION --query 'Subnets[0].SubnetId' --output text)
|
||||
PRIV_AZ=$(aws ec2 describe-subnets --subnet-ids $PRIV_SUBNET --region $REGION \
|
||||
--query 'Subnets[0].AvailabilityZone' --output text)
|
||||
```
|
||||
|
||||
## Phase 2 — Public subnet + Internet Gateway
|
||||
|
||||
```bash
|
||||
# Pick a free /24 in the VPC for the public subnet
|
||||
BASE=$(echo $VPC_CIDR | cut -d. -f1-2)
|
||||
USED=$(aws ec2 describe-subnets --filters "Name=vpc-id,Values=$VPC_ID" \
|
||||
--region $REGION --query 'Subnets[].CidrBlock' --output text | tr '\t' '\n')
|
||||
for i in $(seq 1 254); do
|
||||
CAND="${BASE}.${i}.0/24"
|
||||
echo "$USED" | grep -Fxq "$CAND" || { PUB_CIDR=$CAND; break; }
|
||||
done
|
||||
|
||||
# Public subnet (same AZ as private keeps NAT traffic in-AZ, avoids cross-AZ charges)
|
||||
PUB_SUBNET=$(aws ec2 create-subnet \
|
||||
--vpc-id $VPC_ID --cidr-block $PUB_CIDR \
|
||||
--availability-zone $PRIV_AZ --region $REGION \
|
||||
--tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=xfusion-pub-subnet}]' \
|
||||
--query 'Subnet.SubnetId' --output text)
|
||||
|
||||
aws ec2 modify-subnet-attribute --subnet-id $PUB_SUBNET \
|
||||
--map-public-ip-on-launch --region $REGION
|
||||
|
||||
# Internet Gateway (reuse if the VPC already has one)
|
||||
IGW_ID=$(aws ec2 describe-internet-gateways \
|
||||
--filters "Name=attachment.vpc-id,Values=$VPC_ID" \
|
||||
--region $REGION --query 'InternetGateways[0].InternetGatewayId' --output text)
|
||||
if [ "$IGW_ID" = "None" ] || [ -z "$IGW_ID" ]; then
|
||||
IGW_ID=$(aws ec2 create-internet-gateway --region $REGION \
|
||||
--tag-specifications 'ResourceType=internet-gateway,Tags=[{Key=Name,Value=xfusion-igw}]' \
|
||||
--query 'InternetGateway.InternetGatewayId' --output text)
|
||||
aws ec2 attach-internet-gateway --internet-gateway-id $IGW_ID --vpc-id $VPC_ID --region $REGION
|
||||
fi
|
||||
```
|
||||
|
||||
## Phase 3 — Public route table (→ IGW), associate with public subnet
|
||||
|
||||
```bash
|
||||
PUB_RT=$(aws ec2 create-route-table --vpc-id $VPC_ID --region $REGION \
|
||||
--tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=xfusion-pub-rt}]' \
|
||||
--query 'RouteTable.RouteTableId' --output text)
|
||||
|
||||
aws ec2 create-route --route-table-id $PUB_RT \
|
||||
--destination-cidr-block 0.0.0.0/0 --gateway-id $IGW_ID --region $REGION
|
||||
|
||||
aws ec2 associate-route-table --route-table-id $PUB_RT --subnet-id $PUB_SUBNET --region $REGION
|
||||
```
|
||||
|
||||
This route table makes `xfusion-pub-subnet` genuinely public — its `0.0.0.0/0` points at the IGW. **The NAT Gateway must live in this subnet** so its own outbound traffic (forwarding on behalf of the private instance) can reach the internet via the IGW.
|
||||
|
||||
## Phase 4 — Elastic IP + NAT Gateway
|
||||
|
||||
```bash
|
||||
# Allocate an EIP for the NAT GW
|
||||
NAT_EIP_ALLOC=$(aws ec2 allocate-address --domain vpc --region $REGION \
|
||||
--tag-specifications 'ResourceType=elastic-ip,Tags=[{Key=Name,Value=xfusion-nat-eip}]' \
|
||||
--query 'AllocationId' --output text)
|
||||
|
||||
# Create the NAT Gateway IN THE PUBLIC SUBNET
|
||||
NATGW_ID=$(aws ec2 create-nat-gateway \
|
||||
--subnet-id $PUB_SUBNET \
|
||||
--allocation-id $NAT_EIP_ALLOC \
|
||||
--region $REGION \
|
||||
--tag-specifications 'ResourceType=natgateway,Tags=[{Key=Name,Value=xfusion-natgw}]' \
|
||||
--query 'NatGateway.NatGatewayId' --output text)
|
||||
|
||||
# NAT GW takes ~1-2 min to become available — wait for it
|
||||
# aws ec2 wait nat-gateway-available --nat-gateway-ids $NATGW_ID --region $REGION
|
||||
STATE=""
|
||||
until [ "$STATE" = "available" ]; do
|
||||
STATE=$(aws ec2 describe-nat-gateways --nat-gateway-ids $NATGW_ID --region $REGION \
|
||||
--query 'NatGateways[0].State' --output text)
|
||||
echo "$NATGW_ID: $STATE"
|
||||
[ "$STATE" = "available" ] || sleep 10
|
||||
done
|
||||
```
|
||||
|
||||
Two must-get-right points:
|
||||
|
||||
- **NAT GW goes in the PUBLIC subnet, not the private one.** This trips people constantly. The NAT GW needs a path to the internet for the traffic it forwards, so it sits in the public subnet (which routes to the IGW). The *private* instance then routes *to* the NAT GW. Putting the NAT GW in the private subnet creates a routing loop with no internet path — nothing works.
|
||||
- **A NAT GW requires an EIP** (public NAT GWs). `allocate-address` → pass its allocation ID to `create-nat-gateway`. The EIP is the NAT GW's public-facing address that S3 sees.
|
||||
|
||||
## Phase 5 — Private route table → NAT Gateway
|
||||
|
||||
```bash
|
||||
# Find the route table serving the private subnet (explicit assoc, else main)
|
||||
PRIV_RT=$(aws ec2 describe-route-tables \
|
||||
--filters "Name=association.subnet-id,Values=$PRIV_SUBNET" \
|
||||
--region $REGION --query 'RouteTables[0].RouteTableId' --output text)
|
||||
if [ "$PRIV_RT" = "None" ] || [ -z "$PRIV_RT" ]; then
|
||||
PRIV_RT=$(aws ec2 describe-route-tables \
|
||||
--filters "Name=vpc-id,Values=$VPC_ID" "Name=association.main,Values=true" \
|
||||
--region $REGION --query 'RouteTables[0].RouteTableId' --output text)
|
||||
fi
|
||||
|
||||
# Point the private default route at the NAT GW (create, or replace if one exists)
|
||||
aws ec2 create-route --route-table-id $PRIV_RT \
|
||||
--destination-cidr-block 0.0.0.0/0 --nat-gateway-id $NATGW_ID --region $REGION 2>/dev/null || \
|
||||
aws ec2 replace-route --route-table-id $PRIV_RT \
|
||||
--destination-cidr-block 0.0.0.0/0 --nat-gateway-id $NATGW_ID --region $REGION
|
||||
```
|
||||
|
||||
This is the step that actually gives the private instance internet access: its subnet's `0.0.0.0/0` now flows to the NAT GW (`--nat-gateway-id`, not `--gateway-id` which is for IGWs). The instance keeps *no* public IP — outbound-only internet via NAT, which is exactly the private-instance pattern.
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
# NAT GW available
|
||||
aws ec2 describe-nat-gateways --nat-gateway-ids $NATGW_ID --region $REGION \
|
||||
--query 'NatGateways[0].{State:State,Subnet:SubnetId,EIP:NatGatewayAddresses[0].PublicIp}'
|
||||
|
||||
# Private route table points at the NAT GW
|
||||
aws ec2 describe-route-tables --route-table-ids $PRIV_RT --region $REGION \
|
||||
--query 'RouteTables[0].Routes[?DestinationCidrBlock==`0.0.0.0/0`]'
|
||||
|
||||
# Poll the bucket for the cron-uploaded test file (2-3 min after config)
|
||||
for n in $(seq 1 8); do
|
||||
FILES=$(aws s3 ls s3://xfusion-nat-285654546/ --region $REGION 2>/dev/null)
|
||||
if [ -n "$FILES" ]; then echo "SUCCESS — bucket contents:"; echo "$FILES"; break; fi
|
||||
echo "waiting for cron upload... ($n)"; sleep 30
|
||||
done
|
||||
```
|
||||
|
||||
Want: NAT GW `State: available` with its EIP; the private route table showing `0.0.0.0/0 → nat-...`; and a file appearing in the bucket within 2–3 minutes. **The file appearing is the end-to-end proof** — the private instance (no public IP) reached S3 entirely through the NAT Gateway.
|
||||
|
||||
## NAT Gateway vs NAT Instance (the contrast)
|
||||
|
||||
| | NAT Gateway (this task) | NAT Instance (earlier task) |
|
||||
|---|---|---|
|
||||
| Management | Fully AWS-managed | You run/patch an EC2 box |
|
||||
| Source/dest check | N/A (managed) | Must disable manually |
|
||||
| iptables / IP forwarding | None | You configure MASQUERADE + `ip_forward` |
|
||||
| HA / scaling | Automatic within AZ | Single instance, you handle HA |
|
||||
| Cost | Higher hourly + data processing | Just the EC2 instance |
|
||||
|
||||
The NAT Gateway is the production-standard choice; the NAT instance exists mostly for cost-sensitive or learning scenarios. This task is the "right way."
|
||||
|
||||
## Debug if the file doesn't appear
|
||||
|
||||
1. **NAT GW stuck in `pending`** → wait longer (up to 2 min), or it `failed` (usually the EIP was already in use — allocate a fresh one).
|
||||
2. **Private route wrong** → confirm `0.0.0.0/0` points at `nat-...` (NAT GW), not `igw-...`. A private subnet routing to an IGW directly doesn't work without a public IP on the instance.
|
||||
3. **Public subnet's route table missing the IGW route** → the NAT GW itself can't reach the internet, so forwarded traffic dies. Confirm `xfusion-pub-rt` has `0.0.0.0/0 → igw-...` and is associated with the public subnet the NAT GW lives in.
|
||||
4. **Give it the full 2–3 min** — the cron runs on an interval; the file won't appear instantly even once networking is correct.
|
||||
Reference in New Issue
Block a user