同学反馈 tutor 重点问了:IAM policy、VPC description、ASG policy。下面是这三块的深度问答,重点准备。这三块的回答必须流利。其他问题答错可以补救,这三块结巴会很扣分。
a2-ec2-role has four AWS-managed policies. AmazonS3FullAccess for the web tier to PutObject and the worker to GetObject. AmazonSQSFullAccess for workers to ReceiveMessage and DeleteMessage. AmazonSNSFullAccess — actually only needed if I were to publish from EC2; in the current design the publisher is S3, but I added it for completeness in case I extend the app to publish directly. AmazonSSMManagedInstanceCore lets Systems Manager Session Manager work, which I kept for emergency access if I lost the SSH key."ec2.amazonaws.com to call sts:AssumeRole, which is what lets an EC2 instance assume this role via the instance metadata service. Without that statement, the role couldn't be attached to an instance profile at all."169.254.169.254. The credentials are rotated automatically every few hours. There are no static access keys anywhere on the instance, which is what the IAM role pattern is designed to avoid. If you SSH into the worker right now and run curl http://169.254.169.254/latest/meta-data/iam/security-credentials/a2-ec2-role, you'll see the current temporary credentials."s3:GetObject on arn:aws:s3:::a2-pdf-rag-johnyang-2026/uploads/*; sqs:ReceiveMessage, sqs:DeleteMessage, sqs:GetQueueAttributes on the two queue ARNs; nothing else. No S3 list, no S3 write, no SNS at all, no other queue access. That's exactly what worker_common.py uses, nothing more."a2-vpc is 10.0.0.0/16. It has four subnets across two Availability Zones — 2a and 2b. Each AZ has a public /20 and a private /20: public subnets are 10.0.0.0/20 in 2a and 10.0.16.0/20 in 2b; private subnets are 10.0.128.0/20 in 2a and 10.0.144.0/20 in 2b. The Internet Gateway is attached to the VPC; the public route table sends 0.0.0.0/0 to the IGW. There's one NAT Gateway in the public-1 subnet of 2a, and the private route tables both send 0.0.0.0/0 to that NAT."a2-web-lt, default version. AMI is a2-app-ami, the custom AMI I baked from the worker with Python 3.11 and the application code already installed. Instance type t3.small, key pair a2-key, security group a2-web-sg, IAM instance profile a2-ec2-role. User-data does two things: writes /etc/a2-env with the five required environment variables — region, S3 bucket, two SQS URLs, DATABASE_URL — and creates a systemd unit a2-web.service that runs python3.11 app.py as ec2-user with that environment file. Then it enables the unit. Python is in the AMI so user-data doesn't install anything."GET / every 30 seconds. Without a grace period, the ASG would mark the instance unhealthy and terminate it before user-data even finished writing the systemd unit. 120 seconds is enough for user-data to run, systemd to start the app, and the ALB to register the instance. I tuned this by watching the boot logs the first time I deployed."This is what your tutor expects you to be able to explain in your own words. 这部分 tutor 期待你用自己的话解释。
每一对 SG 之间的关系都有明确目的。不是随便写规则。
| SG | Allow inbound from | Why / 为什么这样设 |
|---|---|---|
a2-alb-sgALB 的 SG |
HTTP:80 from 0.0.0.0/0 |
ALB 是公网入口,必须接受所有人的 80 请求。 没有别的办法 —— 用户能从家里访问就靠这条。SG 范围最宽的就是它。 |
a2-web-sgWeb EC2 的 SG |
TCP:5000 from a2-alb-sg |
关键点:source 是 SG ID 不是 CIDR。意思是"只要请求是从挂着 a2-alb-sg 的实例来的,就放行"。即使有人猜到 Web 的私有 IP,也连不上 —— 他不在 ALB SG 里。 这就是为什么 Web 在私有子网还能正常工作:ALB 在公网,Web 信任 ALB;外人不在 ALB SG 里就连不上 Web。 |
a2-worker-sgWorker 的 SG |
SSH:22 from a2-bastion-sg |
Worker 完全不接受应用流量入站(它是 poll 出去拿 SQS 消息的)。唯一的入站是 SSH,且只能从 bastion 来。 运维渠道唯一。没有 0.0.0.0/0 的 SSH 规则。 |
a2-bastion-sgBastion 的 SG |
SSH:22 from 203.158.41.210/32 |
整个部署里唯一带公网 CIDR 的 SSH 规则,而且锁到我家的单个 IP。换 WiFi 这条规则就要更新。 这是攻击面 —— 但范围被锁到一个 IP,比 0.0.0.0/0 安全 N 倍。 |
a2-rds-sgRDS 的 SG |
5432 from web-sg / worker-sg / bastion-sg | 三个内部 SG 来源,每条规则都说明用途。Web 要写元数据,Worker 要写 chunks,Bastion 要跑 psql 做管理。没有任何 CIDR 规则,没有 0.0.0.0/0。 数据库是最敏感的资源,所以规则最严:只允许三类内部源,且 RDS 本身 Publicly accessible = No。 |
| Security Group | IAM Role | |
|---|---|---|
| 控制什么 | 网络层:谁能连到哪个 port | API 层:哪个身份能调哪个 AWS API |
| 边界 | 实例的网卡 (ENI) | EC2 内 boto3 / CLI 调 AWS |
| 例子 | Worker 能不能 telnet 到 RDS 的 5432 | Worker 能不能 ReceiveMessage from SQS |
| 没有它会怎样 | 实例之间断网 | boto3 调 API 报 AccessDenied |
One-liner / 一句话总结: SG = "能不能连过去"; IAM = "连过去之后能不能调 API"。两个都要对,应用才能工作。
每一跳都有明确的允许策略。这条链里任何一环坏掉应用就停。
s3.amazonaws.com 服务主体 Publish,并用 aws:SourceAccount 条件锁定到本账号。
如果这条 policy 没写,S3 上传后 SNS 收不到事件。
SendMessage,用 aws:SourceArn 条件锁定到那个 topic。
两个队列各自有一份 policy。如果只配一个,另一个 worker 就拿不到消息。
a2-ec2-role 的 SQSFullAccess。不是靠 SG —— SQS 不在 VPC 内,SG 管不到它。
这就是为什么 IAM 比 SG 关键 —— SG 只保护 VPC 内的资源。
EN: "Good afternoon. I'll show you a 3-tier event-driven PDF RAG comparison application I deployed on AWS. Let me start with the user-facing flow, then walk you through the AWS resources."
中文译: 下午好。我会演示一个我部署在 AWS 上的三层事件驱动 PDF RAG 比较应用。先演示用户侧流程,再带你过 AWS 资源。
Choose File → pick a small PDF prepared on Desktop.
点 Choose File,选桌面上准备好的小 PDF。
Upload to S3.
点 Upload to S3。
fixed_size and paragraph_aware marked completed with different chunk counts.
等 3-5 秒,必要时刷新。展示两种策略都 completed,chunk 数不一样。
Compare Retrieval.
滚到 Query Comparison,输入一个查询,点 Compare Retrieval。
EN: "While that processes — the upload is asynchronous. The web tier put the file in S3 and inserted a metadata row. S3 fired an event into SNS, SNS fanned it out to two SQS queues, and both worker processes on the worker EC2 are picking up their respective copies right now."
中文译: 上传是异步的。Web 端把文件放到 S3 然后写了一行元数据。S3 触发了 SNS 事件,SNS 扇出到两个 SQS 队列,worker EC2 上的两个进程正在分别处理。
Open each in console, point at the key field. 每个在控制台打开,指给 tutor 看关键字段。
a2-web-alb
看 Internet-facing、2 个 public subnet、HTTP:80 listener forward 到 a2-web-tg、SG = a2-alb-sg。
a2-web-tg
target port 5000,状态 Healthy。
a2-web-asg
desired=1, max=2, 两个 private subnet, 关联 a2-web-tg, 用 launch template a2-web-lt。
a2-rds-sg
3 条 SG-to-SG 规则在 5432,证明 RDS 不接受公网。
a2-pdf-rag-db
Available, Publicly accessible = No, DB subnet group = a2-db-subnet-group。
pdf-upload-topic → Subscriptions
2 个 confirmed SQS 订阅。
a2-ec2-role
4 个 managed policy 都挂上了。
每个问题都有英文标准回答和中文要点。Demo 时用英文,但中文是你的"我到底想说什么"提示。
/etc/a2-env with the five required environment variables — region, S3 bucket, two SQS URLs, DATABASE_URL. Then it creates a systemd unit a2-web.service that runs python3.11 app.py as ec2-user, and enables the unit. Python and the application code are already in the AMI a2-app-ami."worker_fixed_size.py only polls fixed-size-queue; worker_paragraph_aware.py only polls paragraph-aware-queue. SNS delivers the same S3 event to both queues, so each process gets its own copy and applies its own chunking function."psql on the bastion itself. RDS never gets a public IP and is never reachable from the internet."DeleteMessage after the chunks are written. If it crashes before that, the SQS visibility timeout — 300 seconds — expires and the message becomes visible again. Another worker picks it up. It's not idempotent on the database side though, so duplicate chunks could be inserted; that's acceptable for this assignment but I'd add a unique constraint before going to production."| SG | Inbound rule | 中文 |
|---|---|---|
a2-alb-sg | HTTP:80 from 0.0.0.0/0 | 公网到 ALB |
a2-web-sg | TCP:5000 from a2-alb-sg | 只接受 ALB 来的请求 |
a2-worker-sg | SSH:22 from a2-bastion-sg | 只能从 bastion 登录 |
a2-bastion-sg | SSH:22 from 203.158.41.210/32 | 只允许我家 IP |
a2-rds-sg | 5432 from web-sg / worker-sg / bastion-sg | 3 个内部源能连数据库 |
PutObject 上传 PDFpsql "$DATABASE_URL" with the variable already exported, not the full connection string on the command line.
别在屏幕上显示密码。如果要现场连 RDS,用 psql "$DATABASE_URL" 而不是带密码的完整连接串。
如果你为了省钱 stop 了资源,demo 前要重启。RDS 启动最慢(5-10 分钟),先做。
a2-worker and a2-bastion.
启动 worker 和 bastion(没挂 Elastic IP 的话 IP 会变,记下新 IP)。
a2-pdf-rag-db. Takes 5–10 min.
启动 RDS,最慢,先做。