Giới Thiệu
Sau khi hoàn thành dự án ứng dụng web 3 tầng trên AWS, tôi muốn dự án tiếp theo trong danh mục của mình phải khác biệt hơn — serverless, hướng sự kiện và tách biệt. Tôi cũng muốn thử nghiệm kiến trúc SQS fan-out, nơi một sự kiện có thể kích hoạt nhiều hành động downstream. Và điều quan trọng không kém, tôi muốn xây dựng mọi thứ với một tư duy bảo mật hàng đầu.
Vì vậy, tôi đã xây dựng một Pipelines Đặt Hàng Bảo Mật. Dưới đây là cách thức hoạt động và những gì tôi học được trong quá trình thực hiện.
Tổng Quan Kiến Trúc
Ở mức độ cao, hệ thống hoạt động như sau:
-
Một ALB công khai nhận các yêu cầu đến (
POST /orders
) và chuyển tiếp chúng đến LambdaPublisher. -
LambdaPublisher xác thực yêu cầu và xuất bản nó đến một chủ đề SNS.
-
Chủ đề SNS này phân tán đến nhiều hàng đợi SQS: thanh toán và lưu trữ.
-
Các Lambda tiêu thụ đọc từ những hàng đợi này và thực hiện các tác vụ của chúng:
- Thanh toán → ghi vào DynamoDB
- Lưu trữ → lưu một bản sao JSON trong S3
Mọi thứ đều chạy trong một VPC, với subnet công khai cho ALB và subnet riêng tư cho Lambdas. Quan trọng là, các Lambdas không có quyền truy cập internet — chúng chỉ giao tiếp với các dịch vụ AWS thông qua các điểm cuối VPC.
Sơ Đồ
Điều này thể hiện mẫu phân tán: một yêu cầu → SNS → nhiều hàng đợi → người tiêu dùng độc lập.
Bảo Mật Trước Hết
Xác Thực Tại Lambda Publisher
Điểm truy cập đầu tiên vào hệ thống là Publisher Lambda, vì vậy tôi đã thêm một lớp xác thực cơ bản:
- Các yêu cầu đến phải bao gồm tiêu đề
X-Client-Id
vàX-Signature
. - Lambda kiểm tra những cái này so với một bí mật (được lưu trữ như một biến môi trường tạm thời, nhưng có thể được chuyển đến Secrets Manager sau này).
- Nếu kiểm tra thất bại → trả về
401 Unauthorized
ngay lập tức.
Điều này đảm bảo chỉ những khách hàng đáng tin cậy mới có thể xuất bản vào pipeline.
Vai Trò IAM
Mỗi Lambda có vai trò thực thi riêng, với quyền hạn tối thiểu. Ví dụ:
- Publisher: chỉ
sns:Publish
. - Thanh toán:
sqs:ReceiveMessage/DeleteMessage
+dynamodb:PutItem
. - Lưu trữ:
sqs:ReceiveMessage/DeleteMessage
+s3:PutObject
.
Không có “vai trò siêu” chung — mỗi chức năng được xác định chặt chẽ.
Chính Sách Tài Nguyên
- Mỗi hàng đợi SQS được giới hạn để chỉ chấp nhận tin nhắn từ chủ đề SNS.
- Tùy chọn, bạn có thể tiến xa hơn và ràng buộc tài nguyên với một điểm cuối VPC cụ thể bằng cách sử dụng các điều kiện như
aws:SourceVpce
.
Điều này ngăn chặn truy cập trực tiếp từ bên ngoài hệ thống.
VPC và Subnets
Đây là một bài học tốt cho tôi:
Lambdas không cần quy tắc inbound.
ALB không gọi Lambda qua mạng — nó gọi thông qua AWS control plane.
Vì vậy, nhóm bảo mật của Lambda chỉ quan trọng đối với traffic outbound (ví dụ, khi ghi vào DynamoDB, xuất bản đến SNS hoặc gửi nhật ký).
Các Điểm Cuối VPC
Vì các Lambdas của tôi không có quyền truy cập internet, tôi cần các điểm cuối để chúng có thể tiếp cận các dịch vụ AWS:
- Gateway endpoints: S3, DynamoDB
- Interface endpoints: SNS, SQS, CloudWatch Logs
Bằng cách này, traffic vẫn được giữ kín bên trong AWS. Không có NAT gateways, không có internet công cộng.
Giám Sát
Mỗi Lambda ghi vào CloudWatch Logs, và tôi đã thiết lập một số chỉ số/cảnh báo:
- Lỗi Lambda
- Độ sâu hàng đợi (quan trọng nếu các tiêu thụ bị tụt lại phía sau)
- Độ sâu DLQ
- ALB 5XXs
Không cầu kỳ, nhưng đủ để biết nếu có điều gì đó sai.
Những Gì Tôi Học Được
- SGs của Lambda là khác biệt → không cần quy tắc inbound; outbound là điều quan trọng.
- Đóng gói Terraform zip → tôi đã phải làm quen với việc đóng gói các chức năng một cách sạch sẽ trong Terraform.
- Tư duy bảo mật hàng đầu → các vai trò IAM, chính sách hàng đợi, hạn chế điểm cuối, và thậm chí xác thực khách hàng đơn giản tại Lambda Publisher được tích hợp ngay từ đầu.
- Tách biệt thực sự có hiệu quả → mỗi Lambda tiêu thụ là độc lập. Nếu một gặp sự cố, những cái khác vẫn hoạt động tốt.
- Mở rộng theo sự kiện là tuyệt vời → SQS + Lambda xử lý các đợt tăng đột biến tốt hơn nhiều so với cấu hình truyền thống.
Triển Khai Terraform
Tôi cũng đã triển khai toàn bộ trong Terraform, chia mã thành nhiều thư mục để dễ dàng quản lý:
infra/
├─ network/ # VPC, subnets, bảng điều hướng, SGs, endpoints
├─ data/ # Bảng DynamoDB + bucket lưu trữ S3
├─ messaging/ # Chủ đề SNS, hàng đợi SQS, DLQs, chính sách
├─ iam/ # Vai trò thực thi Lambda + chính sách inline
├─ compute/ # Các chức năng Lambda (publisher + consumers) + ánh xạ nguồn sự kiện
├─ frontend/ # ALB, nhóm mục tiêu, quy tắc listener
├─ observability/ # CloudWatch alarms cho SQS/Lambda/ALB
Và đây là thứ tự mà tôi áp dụng chúng:
- network → thiết lập VPC và endpoints
- data → DynamoDB và lưu trữ S3
- messaging → SNS, SQS, và các chính sách của chúng
- iam → vai trò thực thi Lambda
- compute → Lambdas + ánh xạ nguồn sự kiện
- frontend → ALB và quy tắc listener
- observability → giám sát và cảnh báo
Cách tiếp cận dựa trên thư mục này giúp tôi dễ dàng xây dựng từng lớp một và giữ mọi thứ có thể quản lý được.
Bạn có thể xem mã Terraform đầy đủ và chi tiết dự án trên GitHub của tôi: serverless-orders-pipeline
.
Kết Luận
Dự án này cảm giác như một bước tiến tự nhiên sau ứng dụng web 3 tầng. Thay vì máy chủ và RDS, tôi đã làm việc với Lambdas, hàng đợi, và mạng riêng tư. Thêm xác thực tại Lambda Publisher đã cho tôi một lớp kiểm soát bổ sung, và Terraform giúp duy trì cấu hình có thể tái tạo và có tổ chức.