Ngân hàng đề — AWS Certified Solutions Architect Professional
Tìm thấy 1221 câu.
A company manages a healthcare diagnostics application that writes thousands of lab images to a mounted NFS file system each night from 10 PM - 5 AM. The company wants to migrate this application from its on-premises data center to AWS Cloud over a private network. The company has already established an AWS Direct Connect connection to AWS to facilitate this migration. This application is slated to be moved to Amazon EC2 instances with the Elastic File System (Amazon EFS) file system as the storage service.
Which of the following represents the MOST optimal way of replicating all images to the cloud before the application is fully migrated to the cloud?
-
A
Deploy an AWS DataSync agent to an on-premises server that has access to the NFS file system. Send data over the Direct Connect connection to an AWS PrivateLink interface VPC endpoint for Amazon EFS by using a private VIF. Configure a DataSync scheduled task to send the images to the EFS file system every night
-
B
Define a cron job on the on-premises system to run the AWS s3 sync command from the on-premises file system to Amazon S3. Use the Amazon S3 Event Notifications to call a Lambda function that will copy the images from the S3 bucket to the EFS file system
-
C
Create an NFS file share using AWS Storage Gateway file gateway. Mount your NFS file share on a drive on your client and map it to your Amazon S3 bucket. Configure an AWS Lambda function to process event notifications from Amazon S3 and copy the images from Amazon S3 to the EFS file system
-
D
Deploy an AWS DataSync agent to an on-premises server that has access to the NFS file system. Connect to AWS VPC endpoint for EFS over a public VIF of the Direct Connect connection. Configure a DataSync scheduled task to send the images to the EFS file system every night
Xem giải thích
Đáp án
**A — Triển khai DataSync agent trên một máy chủ tại chỗ có quyền truy cập hệ thống tệp NFS; gửi dữ liệu qua Direct Connect tới một interface VPC endpoint (PrivateLink) của Amazon EFS thông qua private VIF; đặt lịch tác vụ DataSync gửi ảnh sang EFS mỗi đêm.
Vì sao đúng
Đề có hai ràng buộc mạnh, và đáp án khớp cả hai: | Ràng buộc | Cách đáp ứng | |---|---| | Qua mạng RIÊNG | private VIF + interface endpoint | | Đích là EFS | DataSync ghi thẳng vào EFS |
⚠ Điểm mấu chốt: private VIF hay public VIF quyết định mức riêng tư: | VIF | Đi tới | Riêng tư | |---|---|---| | Private VIF | VPC qua VGW hoặc DX gateway | hoàn toàn riêng | | Public VIF | endpoint công khai của AWS | địa chỉ công khai, không qua Internet | | Transit VIF | Transit Gateway | hoàn toàn riêng |
Public VIF vẫn đi trên đường Direct
Connect
↓
Không đi qua Internet công cộng
↓
Nhưng đích là ĐỊA CHỈ CÔNG KHAI
→ đề nói "qua mạng riêng"
→ private VIF đúng hơn
⚠ Và đây là điểm phân biệt duy nhất giữa phương án A và D:
A: private VIF + interface endpoint
D: public VIF
↓
Cùng dùng DataSync, cùng đích EFS
↓
→ chỉ khác đường đi
⚠ Và EFS không có endpoint công khai để đi qua public VIF:
EFS chỉ truy cập được qua mount
target trong VPC
↓
Mount target là ENI có IP riêng tư
↓
Không có địa chỉ công khai nào
→ public VIF không tới được EFS
→ phương án D không hoạt động
Dựng DataSync tới EFS:
aws datasync create-location-nfs \
--server-hostname nas.benh-vien.local \
--subdirectory /anh-xet-nghiem \
--on-prem-config AgentArns=<arn-agent>
aws datasync create-location-efs \
--efs-filesystem-arn arn:aws:elasticfilesystem:ap-southeast-1:111122223333:file-system/fs-abc \
--ec2-config SubnetArn=<arn-subnet>,SecurityGroupArns=<arn-sg> \
--subdirectory /anh
aws datasync create-task \
--source-location-arn <arn-nfs> \
--destination-location-arn <arn-efs> \
--schedule ScheduleExpression="cron(0 6 * * ? *)" \
--options TransferMode=CHANGED,VerifyMode=ONLY_FILES_TRANSFERRED
⚠ Và lịch chạy phải đặt sau khi ứng dụng ghi xong:
Ứng dụng ghi ảnh từ 22h tới 5h sáng
↓
Chạy DataSync lúc 6h
↓
Chạy trong lúc đang ghi → tệp
chưa hoàn chỉnh bị chép
→ và DataSync không biết tệp nào
đang mở
⚠ Và vì sao phương án B đi đường vòng:
B chạy `aws s3 sync` bằng cron
↓
Rồi S3 event gọi Lambda
↓
Lambda chép từ S3 sang EFS
↓
Ba chặng thay vì một
→ và mỗi chặng là một chỗ hỏng
⚠ Và Lambda chép ảnh sang EFS có giới hạn thật:
Lambda tối đa 15 phút
↓
Hàng nghìn ảnh mỗi đêm
↓
Mỗi lời gọi chép một tệp → hàng
nghìn lời gọi
↓
Tệp lớn → có thể vượt thời gian
→ và phải quản lý lỗi từng tệp
⚠ Và aws s3 sync không có xác minh như DataSync:
`s3 sync` so kích thước và thời gian
sửa
↓
DataSync tính checksum từng tệp
↓
Ảnh y tế
→ tính toàn vẹn là bắt buộc
⚠ Và vì sao phương án C phức tạp không cần thiết:
C dựng file gateway, mount vào client,
ánh xạ tới S3
↓
Rồi Lambda chép từ S3 sang EFS
↓
Thêm một thiết bị phải vận hành
↓
Và vẫn đi qua S3 làm trung gian
→ đích cuối là EFS thì chép thẳng
Tạo interface endpoint cho EFS:
aws ec2 create-vpc-endpoint \
--vpc-id vpc-abc \
--vpc-endpoint-type Interface \
--service-name com.amazonaws.ap-southeast-1.elasticfilesystem \
--subnet-ids subnet-a subnet-b \
--security-group-ids sg-endpoint \
--private-dns-enabled
⚠ Và phải phân biệt hai thứ hay lẫn:
Interface endpoint cho `elasticfilesystem`
↓
Đó là endpoint API để GỌI LỆNH
quản trị
↓
Mount target
↓
Đó là nơi ĐỌC GHI dữ liệu qua NFS
→ DataSync agent cần tới mount
target
⚠ Và DataSync agent kết nối tới hai nơi:
1. Tới dịch vụ DataSync (endpoint API)
↓
2. Tới mount target của EFS (cổng 2049)
↓
Private VIF phải định tuyến được
tới cả hai
Cấu hình security group cho mount target:
aws ec2 authorize-security-group-ingress \
--group-id sg-efs \
--protocol tcp --port 2049 \
--cidr 10.0.0.0/16
⚠ Và DataSync tạo ENI trong VPC để ghi vào EFS:
`--ec2-config` khai subnet và security
group
↓
DataSync dựng ENI ở đó
↓
ENI này phải tới được mount target
→ cùng VPC hoặc có đường định tuyến
⚠ Và nên bật mã hoá đường truyền tới EFS:
aws datasync create-location-efs \
--efs-filesystem-arn <arn-efs> \
--in-transit-encryption TLS1_2 \
--access-point-arn <arn-access-point> \
--file-system-access-role-arn <arn-role> \
--ec2-config SubnetArn=<arn-subnet>,SecurityGroupArns=<arn-sg>
Ảnh y tế thuộc dữ liệu nhạy cảm
↓
Mã hoá khi lưu bật mặc định
↓
Mã hoá khi truyền phải khai tường
minh
⚠ Và EFS access point giúp cố định quyền:
aws efs create-access-point \
--file-system-id fs-abc \
--posix-user Uid=1001,Gid=1001 \
--root-directory 'Path=/anh,CreationInfo={OwnerUid=1001,OwnerGid=1001,Permissions=0755}'
Mọi truy cập qua access point dùng
đúng uid/gid đó
↓
Không phụ thuộc uid của máy nguồn
→ tránh chuyện quyền lộn xộn sau
khi chép
⚠ Và chế độ throughput của EFS ảnh hưởng tốc độ chép:
Bursting mode: thông lượng tỷ lệ với
dung lượng
↓
Hệ thống tệp nhỏ mà ghi ồ ạt
↓
Hết credit → tụt xuống mức cơ sở
rất thấp
↓
→ dùng Elastic throughput cho tải
không đều
aws efs update-file-system --file-system-id fs-abc \
--throughput-mode elastic
⚠ Và nên bật lifecycle policy cho ảnh cũ:
aws efs put-lifecycle-configuration --file-system-id fs-abc \
--lifecycle-policies \
'[{"TransitionToIA":"AFTER_30_DAYS"},
{"TransitionToArchive":"AFTER_90_DAYS"},
{"TransitionToPrimaryStorageClass":"AFTER_1_ACCESS"}]'
Ba lợi ích: | Lợi ích | Chi tiết | |---|---| | Một chặng duy nhất, ít chỗ hỏng | | | Có xác minh toàn vẹn dữ liệu | | | Hoàn toàn trên mạng riêng | |
⚠ Và DataSync báo cáo chi tiết từng lần chạy:
aws datasync describe-task-execution \
--task-execution-arn <arn-lan-chay> \
--query '{ketQua:Status,soTep:FilesTransferred,
byte:BytesTransferred,loi:Result.ErrorDetail}'
Vì sao các phương án khác sai
- **D. DataSync agent nhưng kết nối qua public VIF — đây là phương án gần nhất và chỉ khác đúng loại VIF, nhưng EFS chỉ truy cập được qua mount target có IP riêng tư trong VPC, không có endpoint công khai nào để public VIF tới được.
- **B. Cron chạy
aws s3 syncrồi Lambda chép từ S3 sang EFS — ba chặng thay vì một, không có xác minh checksum, và Lambda giới hạn 15 phút mỗi lời gọi. - **C. Storage Gateway file gateway ánh xạ tới S3 rồi Lambda chép sang EFS — thêm một thiết bị phải vận hành và vẫn đi vòng qua S3 khi đích cuối là EFS.
Ghi nhớ
⚠ Ba loại VIF của Direct Connect — bảng phải thuộc: | VIF | Tới đâu | Dùng khi | |---|---|---| | Private | VPC | EFS, RDS, EC2 — tài nguyên trong VPC | | Public | endpoint công khai | S3, DynamoDB, và để dựng VPN trên DX | | Transit | Transit Gateway | nhiều VPC |
Từ khoá nhận diện:
"private network to EFS" → private VIF "access S3 over Direct Connect" → public VIF hoặc interface endpoint "copy NFS to EFS" → DataSync, một chặng "verify data integrity" → DataSync VerifyMode
Ba lưu ý về DataSync: | Lưu ý | Chi tiết | |---|---| | Agent tại chỗ cho nguồn NFS/SMB | | | Tạo ENI trong VPC để ghi vào EFS | | | Có xác minh checksum | |
Ba lưu ý về EFS: | Lưu ý | Chi tiết | |---|---| | Truy cập qua mount target, IP riêng tư | | | Mã hoá khi truyền phải bật tường minh | | | Elastic throughput cho tải không đều | |
Ba lưu ý về access point: | Lưu ý | Chi tiết | |---|---| | Cố định uid/gid cho mọi truy cập | | | Giới hạn ở một thư mục gốc | | | Tránh lộn xộn quyền khi chép từ nguồn khác | |
Ba lưu ý về lịch chạy: | Lưu ý | Chi tiết | |---|---| | Chạy sau khi nguồn ghi xong | | | TransferMode=CHANGED cho lần sau | | | Xem báo cáo mỗi lần chạy | |
Ba lưu ý về throughput của EFS: | Chế độ | Đặc điểm | |---|---| | Bursting | tỷ lệ với dung lượng, có credit | | Provisioned | cố định, trả tiền theo mức | | Elastic | tự co giãn, trả theo dùng thật |
Ba lưu ý về chi phí: | Lưu ý | Chi tiết | |---|---| | DataSync tính theo GB chuyển | | | EFS IA rẻ hơn Standard nhiều lần | | | Truyền qua DX rẻ hơn qua Internet | |
Ba việc kiểm chứng: | Việc | Cách | |---|---| | Xem báo cáo describe-task-execution | | | So số tệp và checksum hai bên | | | Kiểm lưu lượng đi qua private VIF | |
Và một lời khuyên: hãy đặt lịch DataSync chạy sau khi ứng dụng đã ghi xong hoàn toàn. DataSync không biết tệp nào đang được mở ghi dở — nó sẽ chép nguyên trạng thái tại thời điểm đọc, và với ảnh y tế thì một tệp cắt cụt trông y hệt tệp bình thường cho tới lúc có người mở ra xem.
A team has recently created a secret using AWS Secrets Manager to access their private Amazon Relational Database Service (Amazon RDS) instance. When the team tried to rotate the AWS Secrets Manager secret in an Amazon Virtual Private Cloud (Amazon VPC), the operation failed. On analyzing the Amazon CloudWatch Logs, the team realized that the AWS Lambda task timed out.
Which of the following solutions needs to be implemented for rotating the secret successfully?
-
A
Configure an Amazon VPC interface endpoint for the Lambda service to enable access for your Secrets Manager Lambda rotation function and private Amazon Relational Database Service (Amazon RDS) instance
-
B
Your Lambda rotation function might be based on an older template that doesn't support SSL/TLS. To support connections that use SSL/TLS, you must recreate your Lambda rotation function
-
C
Configure an Amazon VPC interface endpoint for the Secrets Manager service to enable access for your Secrets Manager Lambda rotation function and private Amazon Relational Database Service (Amazon RDS) instance
-
D
Interface VPC endpoints support traffic only over HTTP. If this is incorrectly configured, the AWS Lambda function can timeout
Xem giải thích
Đáp án
**C — Dựng một interface VPC endpoint cho dịch vụ Secrets Manager để hàm Lambda xoay vòng và instance RDS riêng tư truy cập được.
Vì sao đúng
Triệu chứng "Lambda hết thời gian chờ" khi xoay vòng bí mật gần như luôn có một nguyên nhân: hàm nằm trong VPC nhưng không có đường tới Secrets Manager.
⚠ Điểm mấu chốt: Lambda xoay vòng phải gọi được HAI nơi:
1. Cơ sở dữ liệu RDS
↓
Để đổi mật khẩu
↓
2. API của Secrets Manager
↓
Để đọc và ghi phiên bản bí mật
Đặt Lambda trong VPC để tới được RDS
↓
Lambda mất đường ra Internet
↓
Secrets Manager là dịch vụ có
endpoint CÔNG KHAI
↓
→ gọi không tới, chờ tới khi hết
giờ
⚠ Và đây là lý do triệu chứng là "timeout" chứ không phải "access denied":
Thiếu quyền → trả lỗi ngay
↓
Không có đường mạng → gói tin đi
vào hư vô
↓
Chờ tới khi Lambda hết thời gian
→ dấu hiệu đặc trưng của vấn đề
mạng
Tạo endpoint:
aws ec2 create-vpc-endpoint \
--vpc-id vpc-abc \
--vpc-endpoint-type Interface \
--service-name com.amazonaws.ap-southeast-1.secretsmanager \
--subnet-ids subnet-rieng-tu-a subnet-rieng-tu-b \
--security-group-ids sg-endpoint \
--private-dns-enabled
⚠ Và --private-dns-enabled là phần quan trọng nhất:
Bật lên
↓
Tên `secretsmanager.ap-southeast-1.amazonaws.com`
phân giải thành IP RIÊNG TƯ của
endpoint
↓
Mã không phải sửa gì cả
↓
Tắt → phải gọi bằng tên DNS riêng
của endpoint
⚠ Và private DNS cần hai thuộc tính VPC:
aws ec2 modify-vpc-attribute --vpc-id vpc-abc --enable-dns-support
aws ec2 modify-vpc-attribute --vpc-id vpc-abc --enable-dns-hostnames
Thiếu → tạo endpoint thành công
↓
Nhưng tên vẫn phân giải ra IP công
khai
→ và triệu chứng y hệt như chưa
tạo endpoint
⚠ Và security group của endpoint phải cho phép cổng 443:
aws ec2 authorize-security-group-ingress \
--group-id sg-endpoint \
--protocol tcp --port 443 \
--source-group sg-lambda
Endpoint có ENI, và ENI có security
group
↓
Mặc định của security group mới:
inbound rỗng
↓
→ Lambda gọi tới bị chặn im lặng
→ lại là timeout
⚠ Và có lựa chọn thay thế: NAT gateway:
Đặt Lambda trong subnet riêng tư
↓
Subnet có route tới NAT gateway
↓
Lambda gọi ra được endpoint công
khai
↓
Nhưng: tốn phí NAT theo giờ và
theo GB
→ và lưu lượng đi ra Internet
Bảng so sánh: | | Interface endpoint | NAT gateway | |---|---|---| | Lưu lượng | trong mạng AWS | ra Internet công cộng | | Phí | ~7,3 USD/tháng mỗi AZ + GB | ~32 USD/tháng + GB | | Phạm vi | một dịch vụ | mọi đích | | Kiểm soát | security group + endpoint policy | chỉ route |
⚠ Và vì sao phương án A sai — endpoint cho Lambda không giúp gì:
A tạo interface endpoint cho DỊCH VỤ
LAMBDA
↓
Endpoint đó để GỌI API của Lambda
từ trong VPC
↓
Ví dụ: `Invoke`, `ListFunctions`
↓
Không liên quan tới việc hàm Lambda
gọi RA
→ hiểu ngược chiều
⚠ Và đây là nhầm lẫn rất phổ biến về VPC endpoint:
Endpoint cho dịch vụ X nghĩa là:
↓
"Từ VPC gọi ĐƯỢC tới API của X"
↓
Không phải:
"X gọi được ra ngoài"
⚠ Và vì sao phương án B sai:
B nói hàm xoay vòng dựa trên mẫu cũ
không hỗ trợ SSL/TLS
↓
Vấn đề TLS sẽ báo lỗi bắt tay
↓
Không phải hết thời gian chờ
↓
Và mẫu của AWS luôn hỗ trợ TLS
→ chẩn đoán sai triệu chứng
⚠ Và vì sao phương án D sai về sự thật:
D nói interface endpoint chỉ hỗ trợ
HTTP
↓
Interface endpoint dùng HTTPS
↓
Mọi API của AWS đều là HTTPS
→ mệnh đề sai hoàn toàn
Cấu hình xoay vòng:
aws secretsmanager rotate-secret \
--secret-id csdl-san-xuat \
--rotation-lambda-arn <arn-lambda-xoay-vong> \
--rotation-rules AutomaticallyAfterDays=30
⚠ Và Secrets Manager có sẵn hàm xoay vòng dựng sẵn:
aws secretsmanager rotate-secret \
--secret-id csdl-san-xuat \
--rotation-rules '{"ScheduleExpression": "rate(30 days)"}' \
--rotate-immediately
Với RDS, Aurora, Redshift, DocumentDB
↓
AWS cung cấp mẫu Lambda sẵn
↓
Console tự dựng, tự gắn VPC
→ nhưng vẫn phải tự lo endpoint
Bốn bước của quy trình xoay vòng:
createSecret → tạo mật khẩu mới, lưu
với nhãn AWSPENDING
↓
setSecret → đặt mật khẩu mới vào
CSDL
↓
testSecret → thử đăng nhập bằng mật
khẩu mới
↓
finishSecret → chuyển nhãn AWSCURRENT
sang phiên bản mới
⚠ Và ba nhãn phiên bản phải nắm: | Nhãn | Nghĩa | |---|---| | AWSCURRENT | phiên bản đang dùng | | AWSPENDING | phiên bản mới, chưa kích hoạt | | AWSPREVIOUS | phiên bản trước |
Ứng dụng không khai nhãn → nhận
`AWSCURRENT`
↓
Trong lúc xoay vòng, `AWSCURRENT`
vẫn là mật khẩu cũ
→ ứng dụng không bị gián đoạn
⚠ Và chiến lược hai người dùng an toàn hơn:
Chiến lược một người dùng:
↓
Đổi mật khẩu của chính tài khoản
ứng dụng
↓
Có khoảnh khắc kết nối cũ dùng mật
khẩu đã đổi
Chiến lược thay phiên (alternating):
↓
Hai tài khoản CSDL, đổi luân phiên
↓
Luôn có một tài khoản hợp lệ
→ không có khoảng trống nào
⚠ Và cần endpoint policy để giới hạn phạm vi:
{"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": "*",
"Action": ["secretsmanager:GetSecretValue",
"secretsmanager:PutSecretValue",
"secretsmanager:DescribeSecret",
"secretsmanager:UpdateSecretVersionStage"],
"Resource": "arn:aws:secretsmanager:ap-southeast-1:111122223333:secret:csdl-*"}]}
⚠ Và nên bật cảnh báo khi xoay vòng thất bại:
aws events put-rule --name canh-bao-xoay-vong \
--event-pattern '{
"source": ["aws.secretsmanager"],
"detail-type": ["AWS API Call via CloudTrail"],
"detail": {"eventName": ["RotationFailed"]}}'
Xoay vòng thất bại im lặng
↓
Bí mật cũ vẫn dùng được
↓
Nhưng nó không còn được xoay nữa
→ và không ai biết cho tới lần
kiểm toán
Ba lợi ích của interface endpoint: | Lợi ích | Chi tiết | |---|---| | Lưu lượng không rời mạng AWS | | | Không cần NAT gateway | | | Giới hạn được bằng endpoint policy | |
Vì sao các phương án khác sai
- **A. Tạo interface endpoint cho dịch vụ Lambda — đây là phương án gần nhất và cùng cơ chế, cùng loại endpoint, nhưng endpoint của Lambda dùng để gọi API Lambda TỪ trong VPC, không giúp hàm Lambda gọi RA tới Secrets Manager.
- **B. Hàm xoay vòng dựa trên mẫu cũ không hỗ trợ SSL/TLS — vấn đề TLS gây lỗi bắt tay chứ không gây hết thời gian chờ.
- **D. Interface endpoint chỉ hỗ trợ HTTP — sai; interface endpoint dùng HTTPS như mọi API của AWS.
Ghi nhớ
⚠ Bốn thứ Lambda trong VPC mất đi — bảng phải thuộc: | Mất | Cách lấy lại | |---|---| | Đường ra Internet | NAT gateway | | Gọi API dịch vụ AWS | interface endpoint | | Gọi S3, DynamoDB | gateway endpoint (miễn phí) | | Phân giải DNS công khai | vẫn có, qua Route 53 Resolver |
Từ khoá nhận diện:
"Lambda in VPC times out calling AWS service" → thiếu endpoint hoặc NAT "access denied" → vấn đề IAM, không phải mạng "rotate secret in VPC" → endpoint Secrets Manager "call Lambda API from VPC" → endpoint Lambda
Ba lưu ý về interface endpoint: | Lưu ý | Chi tiết | |---|---| | Bật --private-dns-enabled | | | Cần enableDnsSupport và enableDnsHostnames | | | Security group phải mở cổng 443 | |
Ba lưu ý về xoay vòng: | Lưu ý | Chi tiết | |---|---| | Bốn bước: create, set, test, finish | | | Chiến lược thay phiên an toàn hơn | | | Cảnh báo khi xoay vòng thất bại | |
Ba nhãn phiên bản: | Nhãn | Nghĩa | |---|---| | AWSCURRENT | đang dùng | | AWSPENDING | mới, chưa kích hoạt | | AWSPREVIOUS | trước đó |
Ba lưu ý về Lambda trong VPC: | Lưu ý | Chi tiết | |---|---| | Cần AWSLambdaVPCAccessExecutionRole | | | Dùng ENI dùng chung, cold start không còn chậm | | | Đặt ở nhiều subnet cho sẵn sàng cao | |
Ba lưu ý về chi phí: | Lưu ý | Chi tiết | |---|---| | Endpoint tính theo giờ mỗi AZ | | | NAT gateway đắt hơn nếu chỉ gọi vài dịch vụ | | | Gateway endpoint cho S3 và DynamoDB miễn phí | |
Ba lưu ý về chẩn đoán: | Triệu chứng | Nguyên nhân thường gặp | |---|---| | Timeout | thiếu đường mạng | | AccessDenied | thiếu quyền IAM | | Không phân giải được tên | thiếu private DNS |
Ba việc kiểm chứng: | Việc | Cách | |---|---| | dig tên endpoint từ trong VPC — phải ra IP riêng tư | | | Chạy rotate-secret --rotate-immediately thử | | | Xem log Lambda có tới bước nào | |
Và một lời khuyên: hãy phân biệt ngay từ đầu giữa timeout và access denied khi chẩn đoán Lambda trong VPC. Hai triệu chứng đó dẫn tới hai hướng hoàn toàn khác nhau — một là mạng, một là quyền — và nhầm hướng ở bước đầu thường khiến người ta sửa chính sách IAM suốt buổi trong khi vấn đề nằm ở một endpoint chưa tạo.
An e-commerce company manages its flagship application on a load-balanced EC2 instance fleet for web hosting, database API services, and business logic. This tightly coupled architecture makes it inflexible for new feature additions while also making the architecture less scalable.
Which of the following options can be used to decouple the architecture, improve scalability and provide the ability to track the failed orders?
-
A
Use Amazon Lightsail for web hosting with AWS AppSync for database API services. Use Simple Queue Service (Amazon SQS) for order queuing. Use Amazon Elastic Container Service (Amazon ECS) for business logic and use the
visibility timeoutparameter of Amazon SQS to retain the failed orders -
B
Configure Amazon CloudFront for hosting the website and Amazon API Gateway for database API services. Use Amazon Simple Queue Service (Amazon SQS) for order queuing and AWS Lambda for business logic. Use Amazon SQS long polling for retaining failed orders
-
C
Configure Amazon S3 for hosting the web application while using AWS AppSync for database access services. Use Amazon Simple Queue Service (Amazon SQS) for queuing orders and AWS Lambda for business logic. Use Amazon SQS dead-letter queue for tracking and re-processing failed orders
-
D
Use AWS Elastic Beanstalk for hosting the web application and Amazon API Gateway for database API services. Use Kinesis Data Streams for queuing orders and AWS Lambda to build business logic. Configure an Amazon S3 bucket for retaining failed orders on an hourly basis
Xem giải thích
Đáp án
**C — Dùng Amazon S3 host ứng dụng web, AWS AppSync cho dịch vụ truy cập cơ sở dữ liệu, Amazon SQS xếp hàng đơn hàng, AWS Lambda cho logic nghiệp vụ, và dead-letter queue của SQS để theo dõi và xử lý lại đơn hàng thất bại.
Vì sao đúng
Đề đòi ba thứ, và chỉ đáp án này đủ cả ba: | Yêu cầu | Thành phần | |---|---| | Tách rời kiến trúc | SQS giữa tầng web và xử lý | | Cải thiện khả năng co giãn | S3 + Lambda co giãn tự động | | Theo dõi đơn hàng thất bại | dead-letter queue |
⚠ Điểm mấu chốt: dead-letter queue là cơ chế DUY NHẤT trong bốn phương án thật sự giữ lại thông điệp hỏng:
Thông điệp được nhận
↓
Xử lý thất bại
↓
Quay lại hàng đợi sau visibility
timeout
↓
Lặp lại tới `maxReceiveCount`
↓
→ chuyển sang DLQ
Cấu hình DLQ:
aws sqs create-queue --queue-name don-hang-that-bai
aws sqs set-queue-attributes \
--queue-url <url-hang-doi-chinh> \
--attributes '{
"RedrivePolicy": "{\"deadLetterTargetArn\":\"<arn-dlq>\",\"maxReceiveCount\":\"3\"}",
"VisibilityTimeout": "300"}'
⚠ Và maxReceiveCount là con số phải chọn có suy nghĩ:
Đặt quá thấp (1-2)
↓
Lỗi tạm thời (CSDL bận) đẩy thông
điệp vào DLQ
↓
Đặt quá cao (20+)
↓
Thông điệp hỏng vĩnh viễn chiếm
chỗ rất lâu
→ 3-5 là khoảng hợp lý
⚠ Và visibility timeout phải LỚN HƠN thời gian xử lý:
Lambda xử lý mất 60 giây
↓
Visibility timeout 30 giây
↓
Thông điệp hiện lại khi đang xử lý
↓
Lambda thứ hai nhận cùng thông điệp
→ đơn hàng bị xử lý hai lần
Quy tắc: visibility timeout ≥ 6 lần
thời gian chạy của hàm
↓
Đó là khuyến nghị của AWS cho
Lambda + SQS
⚠ Và đây là lý do phương án B sai — long polling KHÔNG giữ thông điệp hỏng:
B nói dùng "SQS long polling để giữ
đơn hàng thất bại"
↓
Long polling là cách người tiêu thụ
CHỜ khi hàng đợi rỗng
↓
Nó tiết kiệm lời gọi API rỗng
↓
Không liên quan gì tới việc xử lý
thất bại
aws sqs receive-message \
--queue-url <url> --wait-time-seconds 20
Chờ tối đa 20 giây mới trả về
↓
Thay vì trả rỗng ngay lập tức
→ giảm chi phí và giảm độ trễ
→ chỉ vậy thôi
⚠ Và vì sao phương án A sai — visibility timeout cũng không giữ được gì:
A nói dùng "visibility timeout để giữ
đơn hàng thất bại"
↓
Visibility timeout là thời gian
thông điệp bị ẨN sau khi được
nhận
↓
Hết thời gian → thông điệp hiện
lại
↓
Sau `maxReceiveCount` lần → bị XOÁ
nếu không có DLQ
→ mất hẳn đơn hàng
Bảng ba tham số SQS hay bị lẫn: | Tham số | Việc | |---|---| | Visibility timeout | ẩn thông điệp trong lúc xử lý | | Long polling | chờ khi hàng đợi rỗng | | Redrive policy (DLQ) | chuyển thông điệp hỏng đi nơi khác | | Message retention | giữ tối đa 14 ngày |
⚠ Và vì sao phương án D sai — Kinesis không phải hàng đợi công việc:
D dùng Kinesis Data Streams xếp hàng
đơn hàng
↓
Kinesis là luồng dữ liệu, giữ theo
thứ tự trong shard
↓
Không có visibility timeout, không
có DLQ tự nhiên
↓
Một bản ghi hỏng chặn cả shard
→ "poison pill" làm dừng toàn bộ
luồng
Bảng SQS và Kinesis: | | SQS | Kinesis Data Streams | |---|---|---| | Mô hình | hàng đợi công việc | luồng sự kiện | | Xoá sau khi đọc | có | không (giữ tới 365 ngày) | | Nhiều người tiêu thụ độc lập | không (trừ SNS fanout) | có | | DLQ | có sẵn | phải tự dựng | | Bản ghi hỏng | vào DLQ, luồng tiếp tục | chặn shard |
⚠ Và Lambda giờ có bộ lọc lỗi cho Kinesis:
{"FunctionResponseTypes": ["ReportBatchItemFailures"],
"MaximumRetryAttempts": 2,
"BisectBatchOnFunctionError": true,
"DestinationConfig": {"OnFailure": {"Destination": "<arn-sqs>"}}}
Giảm được vấn đề poison pill
↓
Nhưng vẫn phức tạp hơn SQS + DLQ
→ cho bài toán xếp hàng đơn hàng
thì SQS đúng hơn
⚠ Và D còn ghi đơn hàng thất bại vào S3 mỗi giờ:
Ghi theo lô mỗi giờ
↓
Đơn hàng thất bại nằm chờ tới một
giờ
↓
Và không có cơ chế xử lý lại tự
động
→ phải viết tay toàn bộ
Xử lý lại từ DLQ:
aws sqs start-message-move-task \
--source-arn <arn-dlq> \
--destination-arn <arn-hang-doi-chinh> \
--max-number-of-messages-per-second 10
⚠ Và tính năng redrive này rất đáng biết:
Trước đây phải tự viết script đọc DLQ
rồi gửi lại
↓
Giờ có lệnh sẵn
↓
Giới hạn tốc độ để không làm ngập
hệ thống vừa mới hồi phục
⚠ Và phải đặt cảnh báo cho DLQ:
aws cloudwatch put-metric-alarm \
--alarm-name dlq-co-thong-diep \
--namespace AWS/SQS \
--metric-name ApproximateNumberOfMessagesVisible \
--dimensions Name=QueueName,Value=don-hang-that-bai \
--statistic Maximum --period 300 \
--threshold 0 --comparison-operator GreaterThanThreshold \
--evaluation-periods 1 --alarm-actions <arn-sns>
DLQ không có cảnh báo
↓
Đơn hàng rơi vào đó im lặng
↓
Phát hiện khi khách hàng gọi điện
→ DLQ chỉ có giá trị khi có ai đọc
⚠ Và AppSync là lựa chọn hợp lý cho tầng API:
AppSync là GraphQL được quản lý
↓
Nối thẳng tới DynamoDB, Aurora,
Lambda, OpenSearch
↓
Client hỏi đúng trường cần
↓
Có subscription thời gian thực
→ hợp với ứng dụng thương mại điện
tử nhiều màn hình khác nhau
⚠ Và S3 host web tĩnh là phần rẻ nhất:
Không có máy chủ nào
↓
Co giãn không giới hạn
↓
Đặt CloudFront trước để có HTTPS,
cache và tên miền riêng
Kiến trúc hoàn chỉnh:
Trình duyệt
↓
CloudFront → S3 (giao diện)
↓
AppSync (GraphQL)
↓
SQS (đơn hàng)
↓
Lambda (logic nghiệp vụ)
↓ (thất bại 3 lần)
Dead-letter queue → cảnh báo
⚠ Và SQS FIFO nếu thứ tự quan trọng:
Hàng đợi chuẩn: thứ tự best-effort,
có thể trùng
↓
FIFO: đúng thứ tự, xử lý đúng một
lần
↓
Đơn hàng thường cần FIFO theo từng
khách
→ dùng `MessageGroupId` là mã khách
hàng
aws sqs send-message \
--queue-url <url-fifo> \
--message-body '{"maDon":"DH123"}' \
--message-group-id "khach-456" \
--message-deduplication-id "DH123"
Ba lợi ích: | Lợi ích | Chi tiết | |---|---| | Đỉnh tải được hàng đợi hấp thụ | | | Không đơn hàng nào biến mất im lặng | | | Mỗi tầng co giãn độc lập | |
⚠ Và hàng đợi giúp hệ thống sống sót khi hạ nguồn chết:
CSDL bảo trì
↓
Lambda thất bại
↓
Thông điệp quay lại hàng đợi
↓
CSDL trở lại → xử lý tiếp
→ khách hàng không thấy gì cả
Vì sao các phương án khác sai
- **B. CloudFront + API Gateway + SQS + Lambda, dùng long polling để giữ đơn hàng thất bại — đây là phương án gần nhất và kiến trúc gần như tương đương, nhưng long polling chỉ là cách người tiêu thụ chờ khi hàng đợi rỗng, không có chức năng giữ lại thông điệp xử lý thất bại.
- **A. Lightsail + AppSync + SQS + ECS, dùng visibility timeout để giữ đơn hàng thất bại — visibility timeout chỉ ẩn thông điệp trong lúc xử lý; hết số lần nhận mà không có DLQ thì thông điệp bị xoá hẳn.
- **D. Elastic Beanstalk + API Gateway + Kinesis Data Streams + Lambda, ghi đơn hàng thất bại vào S3 mỗi giờ — Kinesis không phải hàng đợi công việc, một bản ghi hỏng chặn cả shard, và ghi theo lô mỗi giờ không phải cơ chế theo dõi thất bại.
Ghi nhớ
⚠ Bốn tham số SQS phải phân biệt — bảng phải thuộc: | Tham số | Việc | |---|---| | Visibility timeout | ẩn thông điệp đang xử lý | | Long polling | chờ khi hàng đợi rỗng | | Redrive policy | chuyển thông điệp hỏng vào DLQ | | Message retention | tối đa 14 ngày |
Từ khoá nhận diện:
"track failed orders" → dead-letter queue "reduce empty API calls" → long polling "message processed twice" → visibility timeout quá ngắn "multiple independent consumers" → Kinesis hoặc SNS fanout
Ba lưu ý về DLQ: | Lưu ý | Chi tiết | |---|---| | maxReceiveCount 3-5 là hợp lý | | | Phải có cảnh báo, nếu không thì vô dụng | | | start-message-move-task để đẩy lại | |
Ba lưu ý về visibility timeout: | Lưu ý | Chi tiết | |---|---| | Phải lớn hơn thời gian xử lý | | | Khuyến nghị: 6 lần thời gian chạy Lambda | | | Kéo dài được bằng ChangeMessageVisibility | |
Ba lưu ý về FIFO: | Lưu ý | Chi tiết | |---|---| | MessageGroupId quyết định thứ tự trong nhóm | | | Mặc định 300 thao tác/giây | | | High-throughput mode lên tới hàng chục nghìn | |
Ba lưu ý về Lambda + SQS: | Lưu ý | Chi tiết | |---|---| | Lambda tự thăm dò hàng đợi | | | ReportBatchItemFailures để chỉ thử lại phần hỏng | | | Đặt reserved concurrency tránh làm ngập hạ nguồn | |
Ba lưu ý về tách rời: | Lưu ý | Chi tiết | |---|---| | Hàng đợi hấp thụ đỉnh tải | | | Hạ nguồn chết không làm mất dữ liệu | | | Mỗi tầng co giãn độc lập | |
Ba lưu ý về AppSync: | Lưu ý | Chi tiết | |---|---| | GraphQL được quản lý | | | Nối thẳng tới DynamoDB, Aurora, Lambda | | | Có subscription thời gian thực | |
Ba việc kiểm chứng: | Việc | Cách | |---|---| | Gửi thông điệp hỏng, xem có vào DLQ không | | | Kiểm cảnh báo DLQ có gửi thư không | | | Đo ApproximateAgeOfOldestMessage | |
Và một lời khuyên: hãy đặt cảnh báo cho dead-letter queue ngay khi tạo nó. Một DLQ không ai theo dõi chỉ là một nơi để đơn hàng biến mất chậm hơn — nó vẫn giữ dữ liệu, nhưng đến khi có người mở ra xem thì thời hạn 14 ngày thường đã trôi qua.
A company uses Elastic Load Balancing to distribute traffic across multiple Amazon EC2 instances. Auto Scaling groups start and stop Amazon EC2 machines based on the number of incoming requests. The company has recently started operations in a new AWS Region and is setting up an Application Load Balancer for its fleet of EC2 instances spread across two Availability Zones, with one instance as a target in Availability Zone X and four instances as targets in Availability Zone Y. The company is doing benchmarking for server performance in the new Region for the case when cross-zone load balancing is enabled compared to the case when cross-zone load balancing is disabled.
As a Solutions Architect Professional, which of the following traffic distribution outcomes would you identify as correct?
-
A
With cross-zone load balancing enabled, one instance in Availability Zone X receives no traffic and four instances in Availability Zone Y receive 25% traffic each. With cross-zone load balancing disabled, one instance in Availability Zone X receives 50% traffic and four instances in Availability Zone Y receive 12.5% traffic each
-
B
With cross-zone load balancing enabled, one instance in Availability Zone X receives 20% traffic and four instances in Availability Zone Y receive 20% traffic each. With cross-zone load balancing disabled, one instance in Availability Zone X receives no traffic and four instances in Availability Zone Y receive 25% traffic each
-
C
With cross-zone load balancing enabled, one instance in Availability Zone X receives 50% traffic and four instances in Availability Zone Y receive 12.5% traffic each. With cross-zone load balancing disabled, one instance in Availability Zone X receives 20% traffic and four instances in Availability Zone Y receive 20% traffic each
-
D
With cross-zone load balancing enabled, one instance in Availability Zone X receives 20% traffic and four instances in Availability Zone Y receive 20% traffic each. With cross-zone load balancing disabled, one instance in Availability Zone X receives 50% traffic and four instances in Availability Zone Y receive 12.5% traffic each
Xem giải thích
Đáp án
**D — Bật cross-zone load balancing: instance ở AZ X nhận 20% lưu lượng và bốn instance ở AZ Y mỗi cái nhận 20%. Tắt cross-zone load balancing: instance ở AZ X nhận 50% và bốn instance ở AZ Y mỗi cái nhận 12,5%.
Vì sao đúng
Đây là bài toán số học thuần tuý, và chỉ cần nhớ một quy tắc.
⚠ Điểm mấu chốt: cross-zone quyết định lưu lượng chia theo AZ hay theo INSTANCE:
TẮT cross-zone:
↓
Mỗi node LB chỉ gửi tới đích trong
CÙNG AZ
↓
Lưu lượng chia đều giữa các AZ
trước
↓
Rồi mới chia trong AZ
BẬT cross-zone:
↓
Mọi node LB gửi tới MỌI đích
↓
Lưu lượng chia đều giữa TẤT CẢ
instance
Tính toán khi TẮT:
Hai AZ → mỗi AZ 50%
↓
AZ X: 50% ÷ 1 instance = 50%
AZ Y: 50% ÷ 4 instance = 12,5% mỗi cái
↓
Kiểm tra: 50 + 4×12,5 = 100% ✓
Tính toán khi BẬT:
Tổng 5 instance
↓
100% ÷ 5 = 20% mỗi instance
↓
Kiểm tra: 5×20 = 100% ✓
⚠ Và đây là hệ quả thực tế rất nghiêm trọng:
Tắt cross-zone với phân bố lệch
↓
Instance ở AZ X gánh gấp 4 lần
instance ở AZ Y
↓
Nó quá tải trong khi bốn máy kia
nhàn rỗi
→ và metric CPU trung bình trông
hoàn toàn bình thường
⚠ Và mặc định KHÁC NHAU giữa ALB và NLB — điểm hay ra thi: | Loại | Mặc định | |---|---| | ALB | BẬT (không tắt được ở cấp LB) | | NLB | TẮT | | CLB (console) | BẬT | | CLB (API/CLI) | TẮT |
⚠ Và với ALB thì tắt được ở cấp TARGET GROUP:
aws elbv2 modify-target-group-attributes \
--target-group-arn <arn-tg> \
--attributes Key=load_balancing.cross_zone.enabled,Value=false
Tính năng này có từ tháng 11/2022
↓
Trước đó ALB luôn bật, không đổi
được
→ đề cũ có thể nói "ALB không tắt
được"
Bật cho NLB:
aws elbv2 modify-load-balancer-attributes \
--load-balancer-arn <arn-nlb> \
--attributes Key=load_balancing.cross_zone.enabled,Value=true
⚠ Và lý do NLB mặc định tắt: chi phí và độ trễ:
Cross-zone gửi lưu lượng qua AZ
↓
Với NLB, lưu lượng qua AZ TÍNH
TIỀN
↓
Với ALB thì KHÔNG tính
↓
→ đây là khác biệt về giá đáng
nhớ
Bảng chi phí: | Loại | Lưu lượng cross-zone | |---|---| | ALB | miễn phí | | NLB | tính phí truyền dữ liệu giữa AZ | | GWLB | tính phí |
⚠ Và độ trễ cũng khác:
Trong cùng AZ: dưới 1 ms
↓
Qua AZ: thường 1-2 ms
↓
Ứng dụng nhạy cảm độ trễ cực cao
→ tắt cross-zone có lý
⚠ Nhưng cách đúng hơn là làm phân bố instance ĐỀU:
Nguyên nhân gốc không phải cross-zone
↓
Mà là 1 instance ở AZ X và 4 ở AZ Y
↓
Auto Scaling group nên cân bằng
giữa các AZ
→ tiến trình `AZRebalance` làm việc
này
aws autoscaling describe-auto-scaling-groups \
--auto-scaling-group-names asg-ung-dung \
--query 'AutoScalingGroups[0].Instances[*].AvailabilityZone'
⚠ Và phân bố lệch thường do một trong ba nguyên nhân:
1. Tiến trình `AZRebalance` bị tạm
dừng
↓
2. Một AZ hết công suất loại instance
đó
↓
3. Subnet ở AZ đó hết địa chỉ IP
aws ec2 describe-subnets --subnet-ids subnet-x \
--query 'Subnets[0].AvailableIpAddressCount'
⚠ Và có thể dùng nhiều loại instance để tránh hết công suất:
{"MixedInstancesPolicy": {
"LaunchTemplate": {
"Overrides": [
{"InstanceType": "m6i.large"},
{"InstanceType": "m5.large"},
{"InstanceType": "m6a.large"}]},
"InstancesDistribution": {
"OnDemandPercentageAboveBaseCapacity": 50,
"SpotAllocationStrategy": "capacity-optimized"}}}
⚠ Và thuật toán định tuyến trong AZ cũng ảnh hưởng: | Thuật toán | Hành vi | |---|---| | Round robin | lần lượt, mặc định của ALB | | Least outstanding requests | gửi tới đích ít việc nhất | | Weighted random | ngẫu nhiên có trọng số |
aws elbv2 modify-target-group-attributes \
--target-group-arn <arn-tg> \
--attributes Key=load_balancing.algorithm.type,Value=least_outstanding_requests
Yêu cầu có thời gian xử lý rất khác
nhau
↓
Round robin gửi đều nhưng tải
không đều
↓
Least outstanding requests cân
bằng theo việc thật
⚠ Và đây là thuật toán của ALB, KHÔNG phải NLB:
NLB làm việc ở tầng 4
↓
Nó dùng flow hash
↓
Không đếm được "yêu cầu đang chờ"
→ phương án nào gán least
outstanding requests cho NLB đều
sai
⚠ Và target group có trọng số dùng cho triển khai từng phần:
aws elbv2 modify-listener --listener-arn <arn> \
--default-actions '[{
"Type": "forward",
"ForwardConfig": {"TargetGroups": [
{"TargetGroupArn": "<arn-cu>", "Weight": 90},
{"TargetGroupArn": "<arn-moi>", "Weight": 10}]}}]'
Ba lợi ích khi bật cross-zone: | Lợi ích | Chi tiết | |---|---| | Tải đều giữa mọi instance | | | Chịu được phân bố lệch tạm thời | | | Mất một AZ không làm quá tải AZ còn lại | |
⚠ Và tình huống mất AZ là lý do mạnh nhất:
Tắt cross-zone, AZ Y hỏng
↓
Route 53 gỡ IP của node LB ở AZ Y
↓
Nhưng client đã cache DNS vẫn gọi
tới đó
↓
Node đó không có đích nào khoẻ
→ yêu cầu thất bại
Bật cross-zone
↓
Node ở AZ Y vẫn gửi được tới AZ X
→ dịch vụ tiếp tục
Vì sao các phương án khác sai
- **B. Đảo ngược hai vế: bật thì 20% đều, tắt thì AZ X không nhận gì và AZ Y mỗi cái 25% — đây là phương án gần nhất và vế "bật" hoàn toàn đúng, nhưng khi tắt thì AZ X vẫn nhận đủ 50% phần của nó chứ không phải bằng không.
- **C. Đảo ngược hoàn toàn: bật thì 50/12,5, tắt thì 20/20 — hiểu ngược bản chất của cross-zone.
- **A. Bật thì AZ X không nhận gì — sai; bật cross-zone nghĩa là mọi instance đều nhận phần bằng nhau.
Ghi nhớ
⚠ Công thức tính phân bố — bảng phải thuộc: | Trạng thái | Công thức | |---|---| | Tắt cross-zone | (100% ÷ số AZ) ÷ số instance trong AZ đó | | Bật cross-zone | 100% ÷ tổng số instance |
Từ khoá nhận diện:
"cross-zone disabled, uneven instances" → chia theo AZ trước "NLB default" → cross-zone TẮT "ALB default" → cross-zone BẬT "cross-zone data transfer cost" → NLB tính phí, ALB không
Ba lưu ý về mặc định: | Loại | Mặc định | Đổi ở đâu | |---|---|---| | ALB | bật | cấp target group | | NLB | tắt | cấp load balancer | | GWLB | tắt | cấp load balancer |
Ba lưu ý về chi phí: | Lưu ý | Chi tiết | |---|---| | ALB cross-zone miễn phí | | | NLB cross-zone tính phí giữa AZ | | | Cân nhắc khi lưu lượng lớn | |
Ba lưu ý về phân bố lệch: | Nguyên nhân | Cách kiểm | |---|---| | AZRebalance bị tạm dừng | describe-auto-scaling-groups | | Hết công suất loại instance | dùng mixed instances policy | | Subnet hết IP | AvailableIpAddressCount |
Ba thuật toán định tuyến của ALB: | Thuật toán | Dùng khi | |---|---| | Round robin | yêu cầu đồng đều | | Least outstanding requests | thời gian xử lý khác nhau nhiều | | Weighted random | kèm anomaly mitigation |
Ba lưu ý về NLB: | Lưu ý | Chi tiết | |---|---| | Định tuyến bằng flow hash | | | Không có least outstanding requests | | | Có IP tĩnh mỗi AZ | |
Ba lưu ý về sẵn sàng: | Lưu ý | Chi tiết | |---|---| | Bật cross-zone giúp khi mất AZ | | | Ít nhất 2 instance mỗi AZ | | | Bật ít nhất 2 AZ cho mọi LB | |
Ba việc kiểm chứng: | Việc | Cách | |---|---| | Xem RequestCount theo từng đích | | | So phân bố instance giữa các AZ | | | Đo CPU từng máy, không chỉ trung bình | |
Và một lời khuyên: hãy nhìn tải theo từng instance chứ đừng nhìn mức trung bình của Auto Scaling group. Với cross-zone tắt và phân bố lệch, một máy chạy 80% CPU trong khi bốn máy chạy 20% cho ra trung bình 32% — con số đó trông rất khoẻ mạnh cho tới lúc máy đơn độc kia gục.
A data analytics company uses Amazon S3 as the data lake to store the input data that is ingested from the IoT field devices on an hourly basis. The ingested data has attributes such as the device type, ID of the device, the status of the device, the timestamp of the event, the source IP address, etc. The data runs into millions of records per day and the company wants to run complex analytical queries on this data daily for product improvements for each device type.
Which is the most optimal way to save this data to get the best performance from the millions of data points processed daily?
-
A
Store the data in compressed .csv, partitioned by date and sorted by the status of the device
-
B
Store the data in Apache Parquet, partitioned by device type and sorted by date
-
C
Store the data in compressed .csv, partitioned by date and sorted by device type
-
D
Store the data in Apache ORC, partitioned by date and sorted by device type of the device
Xem giải thích
Đáp án
**D — Lưu dữ liệu ở định dạng Apache ORC, phân vùng theo ngày và sắp xếp theo loại thiết bị.
Vì sao đúng
Ba quyết định cần đưa ra, và đáp án đúng ở cả ba: | Quyết định | Chọn | Vì sao | |---|---|---| | Định dạng | cột (ORC) | chỉ đọc cột cần | | Phân vùng | theo ngày | dữ liệu nạp theo giờ, truy vấn theo ngày | | Sắp xếp | theo loại thiết bị | gom dữ liệu cùng loại lại gần nhau |
⚠ Điểm mấu chốt: định dạng cột giảm dữ liệu quét rất nhiều:
CSV: đọc cả dòng để lấy một cột
↓
ORC/Parquet: chỉ đọc cột cần
↓
Bảng có 20 cột, truy vấn dùng 3
→ quét khoảng 15% dữ liệu
Và Athena tính tiền theo lượng QUÉT
↓
→ giảm quét = giảm tiền trực tiếp
⚠ Và điều đó loại ngay phương án A và C:
A và C dùng CSV nén
↓
Nén giảm dung lượng lưu
↓
Nhưng vẫn phải giải nén và đọc CẢ
DÒNG
↓
Và GZIP KHÔNG chia tách được
→ một tệp lớn chỉ một worker xử lý
Bảng ba định dạng: | Định dạng | Kiểu | Chia tách được | |---|---|---| | CSV + GZIP | dòng | KHÔNG | | CSV + BZIP2 | dòng | có | | Parquet, ORC | cột | có |
⚠ Và tính chia tách quan trọng hơn người ta tưởng:
Một tệp GZIP 10 GB
↓
Chỉ MỘT worker giải nén được
↓
Thêm bao nhiêu node cũng vô ích
↓
Parquet/ORC chia thành row group
→ nhiều worker đọc song song
⚠ Và phân vùng theo NGÀY là đúng vì dữ liệu nạp theo giờ:
Dữ liệu về mỗi giờ
↓
Truy vấn chạy HẰNG NGÀY
↓
Phân vùng theo ngày → truy vấn chỉ
đọc phân vùng của ngày đó
→ bỏ qua toàn bộ lịch sử
Cấu trúc thư mục:
s3://kho/du-lieu/
nam=2026/thang=09/ngay=01/tep-001.orc
nam=2026/thang=09/ngay=01/tep-002.orc
nam=2026/thang=09/ngay=02/tep-001.orc
CREATE EXTERNAL TABLE du_lieu_thiet_bi (
ma_thiet_bi string,
loai_thiet_bi string,
trang_thai string,
thoi_gian timestamp,
dia_chi_ip string)
PARTITIONED BY (nam string, thang string, ngay string)
STORED AS ORC
LOCATION 's3://kho/du-lieu/';
⚠ Và phải nạp phân vùng thì Athena mới thấy:
MSCK REPAIR TABLE du_lieu_thiet_bi;
⚠ Hoặc dùng partition projection để khỏi phải nạp:
ALTER TABLE du_lieu_thiet_bi SET TBLPROPERTIES (
'projection.enabled' = 'true',
'projection.nam.type' = 'integer',
'projection.nam.range' = '2024,2030',
'projection.thang.type' = 'integer',
'projection.thang.range' = '1,12',
'projection.thang.digits' = '2',
'projection.ngay.type' = 'integer',
'projection.ngay.range' = '1,31',
'projection.ngay.digits' = '2',
'storage.location.template' =
's3://kho/du-lieu/nam=${nam}/thang=${thang}/ngay=${ngay}');
Athena tự suy ra phân vùng từ mẫu
↓
Không phải chạy `MSCK REPAIR`
↓
Rất quan trọng khi có hàng chục
nghìn phân vùng
→ `MSCK REPAIR` trên bảng lớn mất
hàng giờ
⚠ Và vì sao KHÔNG phân vùng theo loại thiết bị:
Phương án B phân vùng theo loại thiết
bị
↓
Truy vấn chạy HẰNG NGÀY cho MỌI
loại
↓
→ phải đọc mọi phân vùng
→ và đọc toàn bộ lịch sử trong mỗi
phân vùng
Và số loại thiết bị thường ít
↓
Ít phân vùng, mỗi phân vùng khổng
lồ
↓
Trong khi ngày càng tích luỹ mãi
→ phân vùng mất tác dụng lọc
⚠ Và nguyên tắc chọn khoá phân vùng:
Phân vùng theo thứ xuất hiện trong
mệnh đề `WHERE` của HẦU HẾT truy vấn
↓
Thời gian là khoá phân vùng phổ
biến nhất
↓
Vì gần như mọi truy vấn phân tích
đều giới hạn khoảng thời gian
⚠ Và sắp xếp theo loại thiết bị giúp bỏ qua ở tầng dưới:
ORC chia dữ liệu thành stripe
↓
Mỗi stripe có chỉ mục min/max cho
từng cột
↓
Dữ liệu sắp xếp theo loại thiết bị
↓
→ `WHERE loai_thiet_bi = 'cam-bien'`
bỏ qua được cả stripe
Không sắp xếp
↓
Mọi loại nằm rải rác trong mọi
stripe
↓
Min/max của mỗi stripe trải rộng
→ không bỏ qua được gì
⚠ Và ORC còn có bloom filter:
CREATE TABLE du_lieu_orc
STORED AS ORC
TBLPROPERTIES (
'orc.bloom.filter.columns' = 'ma_thiet_bi',
'orc.bloom.filter.fpp' = '0.05',
'orc.stripe.size' = '67108864')
AS SELECT * FROM nguon;
Bloom filter cho cột có nhiều giá trị
riêng biệt
↓
Tra nhanh "stripe này CHẮC CHẮN
không có giá trị đó"
→ bỏ qua thêm được nhiều
Ghi nhớ về chất lượng câu hỏi
⚠ ORC và Parquet gần như tương đương — đó không phải điểm phân biệt thật:
Cả hai đều là định dạng cột
↓
Cả hai đều nén tốt, chia tách được
↓
Cả hai đều có thống kê để bỏ qua
dữ liệu
↓
→ điểm phân biệt THẬT của câu này
là PHÂN VÙNG theo ngày hay theo
loại thiết bị
Khác biệt nhỏ giữa hai định dạng: | | Parquet | ORC | |---|---|---| | Hệ sinh thái | Spark, phổ biến hơn | Hive, Presto | | Nén | tốt | thường nhỉnh hơn chút | | Kiểu lồng nhau | mạnh hơn | hỗ trợ | | ACID trên Hive | không | có |
Trong thực tế: chọn Parquet nếu dùng
Spark hoặc Glue
↓
Chọn ORC nếu hệ sinh thái Hive
→ khác biệt hiệu năng thường dưới
10%
⚠ Và cần biết: Athena đọc được cả hai như nhau:
Không có định dạng nào "đúng" tuyệt
đối ở đây
↓
Đề chọn ORC vì phương án đó cũng
có phân vùng đúng
→ đọc kỹ vế phân vùng chứ đừng
dừng ở tên định dạng
Chuyển từ CSV sang ORC bằng Athena:
CREATE TABLE du_lieu_orc
WITH (format = 'ORC',
partitioned_by = ARRAY['nam','thang','ngay'],
bucketed_by = ARRAY['loai_thiet_bi'],
bucket_count = 20,
external_location = 's3://kho/orc/')
AS SELECT ma_thiet_bi, loai_thiet_bi, trang_thai,
thoi_gian, dia_chi_ip, nam, thang, ngay
FROM du_lieu_csv
ORDER BY loai_thiet_bi;
⚠ Và ORDER BY khi ghi là chỗ tạo ra tính sắp xếp:
Không có `ORDER BY`
↓
Dữ liệu ghi theo thứ tự đọc
↓
Thống kê stripe vô dụng
→ sắp xếp lúc ghi, hưởng lợi mãi
về sau
⚠ Và kích thước tệp cũng quan trọng:
Quá nhiều tệp nhỏ
↓
Mỗi tệp một lời gọi S3
↓
Chi phí liệt kê và mở tệp áp đảo
↓
→ nhắm khoảng 128 MB tới 1 GB mỗi
tệp
Ba lợi ích: | Lợi ích | Chi tiết | |---|---| | Chỉ quét cột cần | | | Chỉ quét phân vùng của ngày cần | | | Bỏ qua stripe không chứa loại thiết bị cần | |
⚠ Và đo được mức cải thiện ngay:
aws athena get-query-execution --query-execution-id <id> \
--query 'QueryExecution.Statistics.DataScannedInBytes'
Chạy cùng truy vấn trên hai bảng
↓
So `DataScannedInBytes`
→ thường giảm 90% trở lên
Vì sao các phương án khác sai
- **B. Apache Parquet, phân vùng theo loại thiết bị, sắp xếp theo ngày — đây là phương án gần nhất và định dạng cột hoàn toàn đúng, nhưng phân vùng theo loại thiết bị buộc truy vấn hằng ngày phải quét mọi phân vùng và toàn bộ lịch sử trong đó.
- **C. CSV nén, phân vùng theo ngày, sắp xếp theo loại thiết bị — phân vùng đúng nhưng định dạng dòng buộc đọc cả dòng, và GZIP không chia tách được.
- **A. CSV nén, phân vùng theo ngày, sắp xếp theo trạng thái — sai cả định dạng lẫn khoá sắp xếp.
Ghi nhớ
⚠ Bốn đòn bẩy giảm chi phí truy vấn — bảng phải thuộc: | Đòn bẩy | Mức giảm điển hình | |---|---| | Định dạng cột | 80-95% | | Phân vùng đúng khoá | tuỳ phạm vi truy vấn | | Nén | 60-80% dung lượng | | Sắp xếp + thống kê | thêm 20-50% |
Từ khoá nhận diện:
"queries run daily on hourly data" → phân vùng theo ngày "analytical queries on millions of rows" → định dạng cột "GZIP CSV" → không chia tách được "thousands of partitions" → partition projection
Ba lưu ý về phân vùng: | Lưu ý | Chi tiết | |---|---| | Chọn cột hay xuất hiện trong WHERE | | | Quá nhiều phân vùng nhỏ cũng hại | | | Partition projection bỏ được MSCK REPAIR | |
Ba lưu ý về định dạng cột: | Lưu ý | Chi tiết | |---|---| | Chỉ đọc cột cần | | | Có thống kê min/max theo khối | | | Chia tách được, đọc song song | |
Ba lưu ý về nén: | Codec | Đặc điểm | |---|---| | Snappy | nhanh, mặc định cho cột | | ZSTD | nén tốt hơn, vẫn nhanh | | GZIP | nén tốt, KHÔNG chia tách |
Ba lưu ý về kích thước tệp: | Lưu ý | Chi tiết | |---|---| | Nhắm 128 MB tới 1 GB | | | Quá nhiều tệp nhỏ tốn chi phí mở | | | Gộp tệp nhỏ định kỳ | |
Ba lưu ý về sắp xếp: | Lưu ý | Chi tiết | |---|---| | ORDER BY lúc ghi mới có tác dụng | | | Sắp theo cột hay lọc | | | Bloom filter cho cột nhiều giá trị riêng | |
Ba lưu ý về chi phí Athena: | Lưu ý | Chi tiết | |---|---| | Tính theo TB quét | | | LIMIT không giảm lượng quét | | | SELECT * quét mọi cột | |
Ba việc kiểm chứng: | Việc | Cách | |---|---| | So DataScannedInBytes trước và sau | | | Kiểm truy vấn có dùng phân vùng không | | | Đếm số tệp và kích thước trung bình | |
Và một lời khuyên: hãy kiểm tra DataScannedInBytes sau mỗi thay đổi bố cục dữ liệu. Đó là con số duy nhất nói thật về hiệu quả — thời gian chạy có thể dao động vì đủ lý do, nhưng lượng dữ liệu quét là thứ bạn trả tiền và là thứ chứng minh phân vùng có thật sự được dùng hay không.
A multi-national company operates hundreds of AWS accounts and the CTO wants to rationalize the operational costs. The CTO has mandated a centralized process for purchasing new Reserved Instances (RIs) or modifying existing RIs. Whereas earlier the business units (BUs) would directly purchase or modify RIs in their own AWS accounts independently, now all BUs must be denied independent purchase and the BUs must submit requests to a dedicated central team for purchasing RIs.
As an AWS Certified Solutions Architect Professional, which of the following solutions would you combine to enforce the new process most efficiently? (Select two)
-
A
Set up a Service Control Policy (SCP) that contains a deny rule to the ec2:PurchaseReservedInstancesOffering and ec2:ModifyReservedInstances actions. Attach the SCP to each organizational unit (OU) of the AWS Organizations structure
-
B
Set up an IAM policy in each AWS account with a deny rule to the ec2:PurchaseReservedInstancesOffering and ec2:ModifyReservedInstances actions
-
C
Leverage AWS Config to notify on the attachment of an IAM policy that allows access to the ec2:PurchaseReservedInstancesOffering and ec2:ModifyReservedInstances actions
-
D
Make sure that all AWS accounts are assigned organizational units (OUs) within an AWS Organizations structure operating in all features mode
-
E
Make sure that all AWS accounts are assigned organizational units (OUs) within an AWS Organizations structure operating in the consolidated billing features mode
Xem giải thích
Đáp án
**A và D — Dựng một SCP có luật deny cho ec2:PurchaseReservedInstancesOffering và ec2:ModifyReservedInstances, gắn vào từng OU của cấu trúc Organizations; và đảm bảo mọi tài khoản đều nằm trong OU của một tổ chức chạy ở chế độ ALL FEATURES.
Vì sao đúng
Hai mệnh đề này là hai phần bắt buộc của cùng một giải pháp: | Phần | Vì sao cần | |---|---| | SCP deny | cấm hành động ở mọi tài khoản | | All features mode | KHÔNG có nó thì SCP không dùng được |
⚠ Điểm mấu chốt: SCP chỉ hoạt động ở chế độ all features:
Organizations có hai chế độ:
↓
`CONSOLIDATED_BILLING`: chỉ gộp
hoá đơn
↓
`ALL`: gộp hoá đơn + SCP + các
tính năng quản trị
↓
→ mệnh đề E chọn consolidated
billing là sai
aws organizations describe-organization \
--query 'Organization.FeatureSet'
Chuyển sang all features:
aws organizations enable-all-features
Lệnh này tạo một yêu cầu chấp thuận
↓
MỌI tài khoản thành viên phải đồng
ý
↓
Không thể quay lại consolidated
billing
→ đây là quyết định một chiều
SCP cần dùng:
{"Version": "2012-10-17",
"Statement": [{
"Sid": "ChanMuaVaSuaReservedInstance",
"Effect": "Deny",
"Action": ["ec2:PurchaseReservedInstancesOffering",
"ec2:ModifyReservedInstances"],
"Resource": "*"}]}
aws organizations create-policy \
--name chan-mua-ri --type SERVICE_CONTROL_POLICY \
--content file://scp-ri.json
aws organizations attach-policy \
--policy-id p-abc123 --target-id ou-workloads-11111111
⚠ Và SCP là cơ chế DUY NHẤT chặn được cả root của tài khoản thành viên:
Chính sách IAM không áp cho root user
↓
Root của tài khoản con vẫn mua
được RI
↓
SCP áp cho MỌI danh tính, kể cả
root
→ đây là lý do quyết định
⚠ Và đó là vì sao mệnh đề B không đủ:
B đặt chính sách IAM deny ở từng tài
khoản
↓
Ba vấn đề:
1. root vẫn làm được
2. quản trị viên tài khoản đó
XOÁ được chính sách
3. phải làm ở hàng trăm tài khoản
Và tài khoản mới thêm vào
↓
Phải nhớ áp chính sách
↓
Quên một tài khoản → lỗ hổng
→ SCP gắn vào OU thì tài khoản mới
tự có
Bảng phân biệt: | | SCP | IAM policy | |---|---|---| | Áp cho root tài khoản con | có | không | | Sửa được từ trong tài khoản | không | có | | Tài khoản mới tự có | có (theo OU) | không | | Cấp quyền | không | có |
⚠ Và vì sao mệnh đề C chỉ là giám sát, không phải thực thi:
C dùng Config để thông báo khi có ai
gắn chính sách cho phép mua RI
↓
Đó là PHÁT HIỆN
↓
Việc mua đã có thể xảy ra rồi
↓
Và RI là cam kết 1-3 năm
→ không huỷ được, chỉ bán lại được
trên marketplace
⚠ Và đó là lý do phải NGĂN chứ không CHỮA:
Mua nhầm một RI 3 năm
↓
Tiền đã cam kết
↓
Bán lại được nhưng chỉ ở một số
Region và mất giá
→ thiệt hại thật, không hoàn tác
được
⚠ Và có một chi tiết rất quan trọng về RI trong Organizations:
Mặc định, RI mua ở BẤT KỲ tài khoản
nào được CHIA SẺ cho cả tổ chức
↓
Một đơn vị mua nhầm loại instance
↓
Chiết khấu áp cho tài khoản khác
dùng đúng loại đó
→ hoặc không ai dùng, tiền lãng
phí toàn tổ chức
Tắt chia sẻ nếu không muốn:
aws ec2 disable-reserved-instances-exchange-quote 2>/dev/null
aws organizations disable-aws-service-access \
--service-principal ram.amazonaws.com 2>/dev/null
Thực tế cấu hình ở console Billing:
↓
Preferences → RI and Savings Plans
discount sharing
↓
Bật/tắt theo từng tài khoản
⚠ Và nên chặn cả Savings Plans, không chỉ RI:
{"Effect": "Deny",
"Action": ["ec2:PurchaseReservedInstancesOffering",
"ec2:ModifyReservedInstances",
"savingsplans:CreateSavingsPlan",
"rds:PurchaseReservedDBInstancesOffering",
"elasticache:PurchaseReservedCacheNodesOffering",
"redshift:PurchaseReservedNodeOffering",
"es:PurchaseReservedInstanceOffering",
"dynamodb:PurchaseReservedCapacityOfferings"],
"Resource": "*"}
Chặn mỗi EC2 RI
↓
Đội vẫn mua được RDS RI, Savings
Plans
→ cùng vấn đề, khác dịch vụ
⚠ Và nên chừa ngoại lệ cho vai trò của đội trung tâm:
{"Effect": "Deny",
"Action": ["ec2:PurchaseReservedInstancesOffering"],
"Resource": "*",
"Condition": {"ArnNotLike": {
"aws:PrincipalArn": "arn:aws:iam::*:role/DoiMuaTapTrung"}}}
Nhưng cẩn thận: điều kiện này cho
phép BẤT KỲ tài khoản nào có vai trò
tên đó
↓
→ cách chắc hơn: gắn SCP vào mọi
OU TRỪ OU của đội trung tâm
⚠ Và cấu trúc OU nên phản ánh chính sách:
Root
├─ OU-MuaSam (không gắn SCP chặn)
├─ OU-SanXuat (gắn SCP chặn)
├─ OU-PhatTrien (gắn SCP chặn)
└─ OU-Sandbox (gắn SCP chặn)
⚠ Và gắn ở gốc thì đơn giản hơn gắn từng OU:
Gắn vào root
↓
Áp cho MỌI tài khoản trừ tài khoản
quản lý
↓
Nhưng cũng áp cho OU-MuaSam
→ đó là lý do đề bài nói gắn vào
"từng OU"
⚠ Và tài khoản quản lý miễn nhiễm SCP — hệ quả ở đây:
SCP gắn ở gốc không chặn tài khoản
quản lý
↓
Nếu đội mua sắm làm việc ở đó
↓
Họ vẫn mua được
→ nhưng chạy nghiệp vụ ở tài khoản
quản lý là thực hành xấu
Kiểm chứng SCP đã áp:
aws organizations describe-effective-policy \
--policy-type SERVICE_CONTROL_POLICY \
--target-id 333344445555
⚠ Và nên theo dõi lời gọi bị từ chối:
aws logs start-query --log-group-name /aws/cloudtrail \
--start-time <bat-dau> --end-time <ket-thuc> \
--query-string 'fields @timestamp, userIdentity.arn, errorCode
| filter eventName like /PurchaseReservedInstances/
and errorCode = "AccessDenied"'
Biết đơn vị nào đang cố mua
↓
Chủ động liên hệ họ
→ tránh việc họ tưởng hệ thống hỏng
Ba lợi ích: | Lợi ích | Chi tiết | |---|---| | Chặn được cả root tài khoản con | | | Tài khoản mới tự có chính sách | | | Không sửa được từ bên trong | |
Vì sao các phương án khác sai
- **B. Đặt chính sách IAM deny ở từng tài khoản — đây là phương án gần nhất và về mặt cú pháp là chính sách giống hệt, nhưng chính sách IAM không áp cho root user, quản trị viên tài khoản đó xoá được nó, và phải triển khai thủ công cho từng tài khoản kể cả tài khoản mới.
- **E. Đảm bảo mọi tài khoản nằm trong OU của tổ chức chạy ở chế độ consolidated billing — chế độ này không dùng được SCP.
- **C. Dùng AWS Config thông báo khi có ai gắn chính sách cho phép mua RI — đó là phát hiện sau khi việc đã xảy ra; RI là cam kết 1-3 năm không huỷ được.
Ghi nhớ
⚠ Bốn điều kiện để dùng SCP — bảng phải thuộc: | Điều kiện | Chi tiết | |---|---| | Chế độ all features | bắt buộc | | Gắn vào root, OU hoặc tài khoản | | | Không áp cho tài khoản quản lý | | | Không áp cho service-linked role | |
Từ khoá nhận diện:
"deny across all accounts including root" → SCP "consolidated billing mode" → KHÔNG dùng được SCP "notify when policy attached" → Config, chỉ phát hiện "prevent the purchase" → SCP deny
Ba lưu ý về chế độ tổ chức: | Lưu ý | Chi tiết | |---|---| | enable-all-features cần mọi thành viên đồng ý | | | Không quay lại được | | | Kiểm bằng describe-organization | |
Ba lưu ý về SCP deny: | Lưu ý | Chi tiết | |---|---| | Deny thắng mọi Allow | | | Áp cho cả root tài khoản con | | | Nên chặn cả dịch vụ tương đương | |
Ba lưu ý về Reserved Instance: | Lưu ý | Chi tiết | |---|---| | Cam kết 1 hoặc 3 năm, không huỷ | | | Mặc định chia sẻ chiết khấu toàn tổ chức | | | Chỉ bán lại được ở một số Region | |
Ba lưu ý về ngoại lệ: | Cách | Chi tiết | |---|---| | Không gắn SCP vào OU của đội mua sắm | chắc chắn nhất | | Điều kiện aws:PrincipalArn | dễ bị lách | | Tài khoản quản lý | luôn miễn nhiễm |
Ba lưu ý về giám sát: | Lưu ý | Chi tiết | |---|---| | CloudTrail ghi lời gọi bị từ chối | | | Cost Explorer xem mức dùng RI | | | Cảnh báo khi RI sắp hết hạn | |
Ba lưu ý về tối ưu chi phí: | Lưu ý | Chi tiết | |---|---| | Savings Plans linh hoạt hơn RI | | | Compute Savings Plans áp cả Lambda và Fargate | | | Mua tập trung dễ tối ưu hơn mua rời | |
Ba việc kiểm chứng: | Việc | Cách | |---|---| | Thử mua RI từ tài khoản con — phải bị từ chối | | | Thử bằng chính root của tài khoản con | | | Đọc describe-effective-policy | |
Và một lời khuyên: hãy chặn cả Savings Plans và RI của các dịch vụ khác trong cùng một SCP. Chặn mỗi ec2:PurchaseReservedInstancesOffering để lại đúng những cánh cửa mà một đội đang muốn tiết kiệm chi phí sẽ tìm thấy đầu tiên — và cam kết ba năm cho RDS cũng khó hoàn tác y như cam kết cho EC2.
The security team at a company has put forth a requirement to track the external IP address when a customer or a third party uploads files to the Amazon Simple Storage Service (Amazon S3) bucket owned by the company.
How will you track the external IP address used for each upload? (Select two)
-
A
CloudWatch Logs centrally maintain the logs from all of your systems, applications, and AWS services that you use. Use these logs to capture the IP address at the object level for the S3 bucket
-
B
Enable AWS Systems Manager Agent (SSM Agent) that writes information about executions, commands, scheduled actions on all AWS resources
-
C
Enable VPC Flow Logs to capture all object-level events occurring on the S3 bucket
-
D
Enable Amazon S3 server access logging to capture all bucket-level and object-level events
-
E
Enable AWS CloudTrail data events to enable object-level logging for S3 bucket
Xem giải thích
Đáp án
**D và E — Bật S3 server access logging để ghi mọi sự kiện cấp bucket và cấp object; và bật CloudTrail data event để ghi log cấp object cho bucket đó.
Vì sao đúng
Chỉ hai cơ chế này ghi lại địa chỉ IP của người gọi khi có object được tải lên S3.
⚠ Điểm mấu chốt: cả hai đều ghi IP nguồn, nhưng khác nhau về nhiều mặt: | | Server access log | CloudTrail data event | |---|---|---| | Đích | bucket S3 khác | S3, CloudWatch Logs, EventBridge | | Độ trễ | vài giờ | vài phút | | Định dạng | văn bản phân tách khoảng trắng | JSON | | Chi phí | chỉ tiền lưu trữ | 0,10 USD mỗi 100.000 sự kiện | | Bảo đảm đầy đủ | best-effort | đầy đủ | | Trường IP | Remote IP | sourceIPAddress |
Bật server access logging:
aws s3api put-bucket-logging --bucket kho-tai-len \
--bucket-logging-status '{
"LoggingEnabled": {
"TargetBucket": "kho-log-truy-cap",
"TargetPrefix": "kho-tai-len/",
"TargetObjectKeyFormat": {
"PartitionedPrefix": {"PartitionDateSource": "EventTime"}}}}'
⚠ Và bucket đích phải khác bucket nguồn:
Ghi log vào chính bucket đang theo dõi
↓
Mỗi lần ghi log sinh ra một sự
kiện mới
↓
Sự kiện đó lại sinh log
→ vòng lặp vô tận, hoá đơn tăng
mãi
Một dòng server access log:
79a5 kho-tai-len [01/Sep/2026:10:15:30 +0000]
203.0.113.45 arn:aws:iam::111122223333:user/khach-a
3E57427F REST.PUT.OBJECT tai-lieu/hop-dong.pdf
"PUT /tai-lieu/hop-dong.pdf HTTP/1.1" 200 - - 5242880
125 40 "-" "aws-cli/2.15.0" - ...
| Trường | Giá trị |
|---|---|
| Remote IP | 203.0.113.45 |
| Requester | ARN của người gọi |
| Operation | REST.PUT.OBJECT |
| HTTP status | 200 |
Bật CloudTrail data event:
aws cloudtrail put-event-selectors \
--trail-name theo-doi-s3 \
--advanced-event-selectors '[{
"Name": "Ghi log ghi object",
"FieldSelectors": [
{"Field": "eventCategory", "Equals": ["Data"]},
{"Field": "resources.type", "Equals": ["AWS::S3::Object"]},
{"Field": "resources.ARN", "StartsWith":
["arn:aws:s3:::kho-tai-len/"]},
{"Field": "readOnly", "Equals": ["false"]}]}]'
⚠ Và readOnly: false lọc bỏ thao tác đọc — giảm chi phí rất nhiều:
Không lọc
↓
Mọi `GetObject` cũng bị ghi
↓
Bucket phục vụ web → hàng triệu
sự kiện mỗi ngày
↓
Chỉ cần theo dõi tải lên
→ lọc `readOnly: false`
Một sự kiện CloudTrail:
{"eventTime": "2026-09-01T10:15:30Z",
"eventName": "PutObject",
"sourceIPAddress": "203.0.113.45",
"userIdentity": {"type": "IAMUser",
"arn": "arn:aws:iam::111122223333:user/khach-a"},
"requestParameters": {
"bucketName": "kho-tai-len",
"key": "tai-lieu/hop-dong.pdf"},
"additionalEventData": {
"bytesTransferredIn": 5242880,
"SSEApplied": "SSE_S3"}}
⚠ Và CloudTrail data event KHÔNG bật mặc định:
Trail thông thường chỉ ghi management
event
↓
`CreateBucket`, `PutBucketPolicy`
↓
Không ghi `PutObject`, `GetObject`
↓
→ phải bật data event tường minh
⚠ Và đây là hiểu lầm rất phổ biến:
"Chúng tôi đã bật CloudTrail"
↓
Nhưng khi cần điều tra ai tải tệp
lên
↓
Không có sự kiện nào
→ vì data event chưa bao giờ được
bật
⚠ Và vì sao phương án C sai — VPC Flow Log không thấy sự kiện object:
C nói bật VPC Flow Logs để ghi sự
kiện cấp object trên S3
↓
Flow Log ghi luồng GÓI TIN trong
VPC
↓
Nó không biết gì về HTTP, về API
S3
↓
Và người tải lên là bên thứ ba,
không đi qua VPC của bạn
⚠ Và vì sao phương án A sai:
A nói dùng CloudWatch Logs bắt IP ở
cấp object
↓
CloudWatch Logs là NƠI CHỨA log
↓
Nó không tự sinh ra log nào
↓
Phải có nguồn ghi vào đó
→ và nguồn đó chính là CloudTrail
⚠ Và vì sao phương án B sai:
B nói bật SSM Agent
↓
SSM Agent chạy trên EC2 hoặc máy
chủ
↓
Nó ghi lệnh chạy trên máy đó
↓
Khách hàng gọi API S3 từ máy của
họ
→ không có agent nào của bạn ở đó
⚠ Và có một chi tiết quan trọng: IP nào được ghi:
Khách gọi thẳng API S3
↓
→ IP thật của họ
Khách gọi qua CloudFront
↓
S3 thấy IP của điểm biên CloudFront
↓
→ phải đọc access log của
CloudFront mới thấy IP thật
Khách gọi từ EC2 trong VPC qua gateway
endpoint
↓
Server access log ghi IP RIÊNG TƯ
↓
Và có thêm trường `vpcendpoint-id`
⚠ Và presigned URL làm việc truy vết phức tạp hơn:
Người tạo URL là A
↓
Người dùng URL là B
↓
CloudTrail ghi `userIdentity` là A
↓
Nhưng `sourceIPAddress` là của B
→ phải đọc cả hai trường mới hiểu
chuyện gì xảy ra
Truy vấn CloudTrail bằng Athena:
SELECT eventtime, sourceipaddress,
useridentity.arn AS nguoi_goi,
json_extract_scalar(requestparameters, '$.key') AS khoa
FROM cloudtrail_logs
WHERE eventname = 'PutObject'
AND json_extract_scalar(requestparameters, '$.bucketName')
= 'kho-tai-len'
AND eventtime >= '2026-09-01'
ORDER BY eventtime DESC;
Truy vấn server access log:
CREATE EXTERNAL TABLE log_truy_cap_s3 (
chu_bucket string, ten_bucket string, thoi_gian string,
mui_gio string, ip_nguoi_goi string, nguoi_goi string,
ma_yeu_cau string, thao_tac string, khoa string)
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.RegexSerDe'
WITH SERDEPROPERTIES ('input.regex' =
'([^ ]*) ([^ ]*) \\[(.*?) (.*?)\\] ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*).*')
LOCATION 's3://kho-log-truy-cap/kho-tai-len/';
⚠ Và nên dùng CẢ HAI, không chọn một:
CloudTrail: nhanh, JSON, đầy đủ,
tích hợp EventBridge
↓
Server access log: rẻ, có thêm
trường HTTP chi tiết
↓
Điều tra bảo mật → CloudTrail
→ phân tích lưu lượng → access log
⚠ Và có thể phản ứng tức thì bằng EventBridge:
aws events put-rule --name canh-bao-tai-len-la \
--event-pattern '{
"source": ["aws.s3"],
"detail-type": ["AWS API Call via CloudTrail"],
"detail": {
"eventSource": ["s3.amazonaws.com"],
"eventName": ["PutObject"],
"requestParameters": {"bucketName": ["kho-tai-len"]}}}'
⚠ Và bucket chứa log phải được bảo vệ:
Kẻ tấn công tải tệp xấu lên
↓
Rồi xoá log để che dấu vết
↓
→ bật Object Lock ở chế độ
compliance
→ và chặn xoá bằng SCP
aws s3api put-object-lock-configuration \
--bucket kho-log-truy-cap \
--object-lock-configuration '{
"ObjectLockEnabled": "Enabled",
"Rule": {"DefaultRetention": {
"Mode": "COMPLIANCE", "Days": 365}}}'
Ba lợi ích khi bật cả hai: | Lợi ích | Chi tiết | |---|---| | Biết IP, danh tính và thời gian mọi lần tải lên | | | Phản ứng tự động qua EventBridge | | | Có bản ghi đối chiếu nếu một nguồn thiếu | |
Vì sao các phương án khác sai
- **A. Dùng CloudWatch Logs để bắt IP ở cấp object — đây là phương án gần nhất và CloudTrail thật sự gửi được vào CloudWatch Logs, nhưng CloudWatch Logs chỉ là nơi chứa; nó không tự sinh ra log truy cập S3 nào.
- **C. Bật VPC Flow Logs để ghi sự kiện cấp object — Flow Log ghi luồng gói tin trong VPC, không biết gì về API S3, và bên thứ ba không đi qua VPC của bạn.
- **B. Bật SSM Agent — agent chạy trên máy chủ của bạn, không có mặt trên máy của khách hàng gọi API.
Ghi nhớ
⚠ Bốn nguồn log cho S3 — bảng phải thuộc: | Nguồn | Ghi gì | |---|---| | CloudTrail management event | thao tác trên bucket | | CloudTrail data event | thao tác trên object | | Server access log | mọi yêu cầu, chi tiết HTTP | | CloudFront access log | IP thật khi đi qua CDN |
Từ khoá nhận diện:
"track IP address of uploads" → CloudTrail data event + server access log "CloudTrail is enabled but no PutObject" → chưa bật data event "IP shows CloudFront edge" → đọc log CloudFront "who called the API" →
userIdentity
Ba lưu ý về CloudTrail data event: | Lưu ý | Chi tiết | |---|---| | KHÔNG bật mặc định | | | Tính phí theo số sự kiện | | | Lọc readOnly: false để giảm chi phí | |
Ba lưu ý về server access log: | Lưu ý | Chi tiết | |---|---| | Bucket đích phải khác bucket nguồn | | | Độ trễ vài giờ, best-effort | | | Có nhiều trường HTTP chi tiết hơn | |
Ba lưu ý về IP nguồn: | Đường đi | IP thấy được | |---|---| | Gọi thẳng | IP thật | | Qua CloudFront | IP điểm biên | | Qua VPC endpoint | IP riêng tư + vpcendpoint-id |
Ba lưu ý về presigned URL: | Lưu ý | Chi tiết | |---|---| | userIdentity là người TẠO URL | | | sourceIPAddress là người DÙNG URL | | | Giới hạn thời hạn URL ngắn nhất có thể | |
Ba lưu ý về bảo vệ log: | Lưu ý | Chi tiết | |---|---| | Object Lock chế độ compliance | | | Bucket log ở tài khoản riêng | | | SCP chặn StopLogging và DeleteTrail | |
Ba lưu ý về phân tích: | Lưu ý | Chi tiết | |---|---| | Athena truy vấn được cả hai loại log | | | Phân vùng theo ngày để giảm chi phí | | | CloudTrail Lake nếu muốn truy vấn sẵn | |
Ba việc kiểm chứng: | Việc | Cách | |---|---| | Tải một tệp lên, tìm sự kiện trong CloudTrail | | | Kiểm bucket log có nhận dữ liệu không | | | Đối chiếu IP giữa hai nguồn log | |
Và một lời khuyên: hãy kiểm tra xem data event đã thật sự được bật chưa thay vì tin rằng "CloudTrail đang chạy". Đây là khoảng cách hay gặp nhất giữa niềm tin và thực tế trong kiểm toán S3 — trail vẫn ghi đầy đủ mọi thao tác quản trị, nên mọi thứ trông đúng cho tới ngày cần biết ai đã tải tệp nào lên.
A social media company manages a multi-AZ VPC environment consisting of public subnets and private subnets. Each public subnet contains a NAT Gateway as well as an Internet Gateway. Most of the company's applications are deployed in the private subnets and these applications read and write data to Kinesis Data Streams. The company has hired you as an AWS Certified Solutions Architect Professional to reduce costs and optimize the applications. Upon analysis in the AWS Cost Explorer, you notice that the cost in the EC2-Other category is consistently high due to the increasing NAT Gateway data transfer charges.
What do you recommend to address this requirement?
-
A
Set up a gateway VPC endpoint for Kinesis Data Streams in the VPC. Ensure that the applications have the required IAM permissions to use the gateway VPC endpoint
-
B
Set up an interface VPC endpoint for Kinesis Data Streams in the VPC. Ensure that the applications have the required IAM permissions to use the interface VPC endpoint
-
C
Set up an interface VPC endpoint for Kinesis Data Streams in the VPC. Ensure that the VPC endpoint policy allows traffic from the applications
-
D
Set up a gateway VPC endpoint for Kinesis Data Streams in the VPC. Ensure that the VPC endpoint policy allows traffic from the applications
Xem giải thích
Đáp án
**C — Dựng một interface VPC endpoint cho Kinesis Data Streams trong VPC; đảm bảo chính sách endpoint (endpoint policy) cho phép lưu lượng từ các ứng dụng.
Vì sao đúng
Đề nêu vấn đề rất rõ: chi phí ở hạng mục EC2-Other tăng cao do phí truyền dữ liệu qua NAT Gateway. Nguyên nhân và cách chữa đều xác định được.
⚠ Điểm mấu chốt: ứng dụng trong subnet riêng tư gọi Kinesis qua NAT Gateway:
Kinesis có endpoint CÔNG KHAI
↓
Ứng dụng ở subnet riêng tư
↓
Đường ra duy nhất là NAT Gateway
↓
Mỗi byte gửi vào stream tính phí
xử lý NAT
Chi phí NAT Gateway: | Khoản | Giá xấp xỉ | |---|---| | Phí theo giờ | 0,045 USD/giờ ≈ 32 USD/tháng | | Phí xử lý dữ liệu | 0,045 USD/GB |
Ứng dụng đẩy 10 TB/tháng vào Kinesis
↓
10.000 GB × 0,045 = 450 USD
↓
Chỉ riêng phí xử lý NAT
→ và đó là hạng mục "EC2-Other"
⚠ Và interface endpoint bỏ hẳn khoản đó:
Endpoint tạo ENI trong subnet riêng
tư
↓
Lưu lượng tới Kinesis đi qua ENI
đó
↓
Không chạm NAT Gateway
→ chỉ còn phí endpoint
Chi phí interface endpoint: | Khoản | Giá xấp xỉ | |---|---| | Phí theo giờ mỗi AZ | 0,01 USD/giờ ≈ 7,3 USD/tháng | | Phí xử lý dữ liệu | 0,01 USD/GB |
Cùng 10 TB: 10.000 × 0,01 = 100 USD
↓
Cộng 2 AZ × 7,3 = 14,6 USD
↓
Tổng ~115 USD thay vì 450 USD
→ tiết kiệm khoảng 75%
⚠ Điểm mấu chốt thứ hai: Kinesis KHÔNG có gateway endpoint:
Chỉ S3 và DynamoDB có gateway endpoint
↓
Kinesis dùng interface endpoint
(PrivateLink)
↓
→ phương án A và D sai ngay ở loại
endpoint
Tạo endpoint:
aws ec2 create-vpc-endpoint \
--vpc-id vpc-abc \
--vpc-endpoint-type Interface \
--service-name com.amazonaws.ap-southeast-1.kinesis-streams \
--subnet-ids subnet-rieng-a subnet-rieng-b \
--security-group-ids sg-endpoint \
--private-dns-enabled \
--policy-document file://chinh-sach-endpoint.json
⚠ Và tên dịch vụ là kinesis-streams, không phải kinesis:
com.amazonaws.<region>.kinesis-streams
↓
Còn có:
kinesis-firehose
kinesis-video-streams
→ khai nhầm thì tạo được nhưng
không đi tới đâu
⚠ Điểm mấu chốt thứ ba: endpoint policy khác chính sách IAM:
Phương án B nói "đảm bảo ứng dụng có
quyền IAM cần thiết"
↓
Đúng nhưng chưa đủ
↓
Interface endpoint có CHÍNH SÁCH
RIÊNG
↓
Mặc định cho phép tất cả
→ nhưng nếu đặt chính sách hạn chế
thì phải cho phép ứng dụng
Chính sách endpoint:
{"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": "*",
"Action": ["kinesis:PutRecord", "kinesis:PutRecords",
"kinesis:GetRecords", "kinesis:GetShardIterator",
"kinesis:DescribeStream", "kinesis:ListShards"],
"Resource": "arn:aws:kinesis:ap-southeast-1:111122223333:stream/luong-du-lieu"}]}
⚠ Và quyền thật là GIAO của ba tầng:
Chính sách IAM của ứng dụng
↓
Chính sách endpoint
↓
Chính sách tài nguyên (nếu có)
↓
→ phải cả ba cùng cho phép
⚠ Và endpoint policy dùng để chặn rò rỉ dữ liệu:
{"Effect": "Deny",
"Principal": "*",
"Action": "kinesis:*",
"Resource": "*",
"Condition": {"StringNotEquals": {
"aws:ResourceAccount": "111122223333"}}}
Chặn ghi vào stream của tài khoản
khác
↓
Kể cả khi ai đó có credential của
tài khoản đó
→ đây là giá trị lớn nhất của
endpoint policy
⚠ Và security group của endpoint phải mở cổng 443:
aws ec2 authorize-security-group-ingress \
--group-id sg-endpoint \
--protocol tcp --port 443 \
--source-group sg-ung-dung
Quên bước này
↓
Ứng dụng gọi Kinesis hết thời gian
chờ
↓
Triệu chứng y hệt như chưa có
endpoint
⚠ Và nên tạo endpoint ở MỌI AZ có ứng dụng:
Chỉ tạo ở một AZ
↓
Ứng dụng ở AZ khác vẫn gọi được
↓
Nhưng lưu lượng đi QUA AZ
↓
→ tính phí truyền dữ liệu giữa AZ
→ và mất sẵn sàng nếu AZ đó hỏng
⚠ Và phải xem lại có còn cần NAT Gateway không:
aws logs start-query --log-group-name /vpc/flowlogs \
--start-time <bat-dau> --end-time <ket-thuc> \
--query-string 'fields dstaddr, bytes
| filter srcaddr like /10.0.1./
| stats sum(bytes) as tong by dstaddr
| sort tong desc | limit 20'
Nếu Kinesis là đích duy nhất
↓
Bỏ được NAT Gateway hoàn toàn
↓
Tiết kiệm thêm 32 USD/tháng mỗi
AZ
⚠ Nhưng thường vẫn còn nhu cầu khác:
Ứng dụng cần gọi:
- Systems Manager
- CloudWatch
- Secrets Manager
- kho gói phần mềm
↓
→ tạo endpoint cho từng dịch vụ
AWS
→ NAT chỉ còn cho lưu lượng ra
Internet thật
⚠ Và có ngưỡng để cân nhắc endpoint hay NAT:
Ít dữ liệu, nhiều dịch vụ
↓
NAT rẻ hơn (một cái cho tất cả)
↓
Nhiều dữ liệu, ít dịch vụ
→ endpoint rẻ hơn nhiều
Điểm hoà vốn xấp xỉ:
endpoint 7,3 USD/tháng mỗi AZ
↓
NAT tiết kiệm 0,035 USD/GB
↓
→ khoảng 210 GB/tháng mỗi AZ
⚠ Và nên dùng Cost Explorer tách hạng mục:
aws ce get-cost-and-usage \
--time-period Start=2026-08-01,End=2026-09-01 \
--granularity MONTHLY --metrics UnblendedCost \
--group-by Type=DIMENSION,Key=USAGE_TYPE \
--filter '{"Dimensions": {"Key": "SERVICE",
"Values": ["EC2 - Other"]}}'
Tìm usage type
`<Region>-NatGateway-Bytes`
↓
Đó chính là khoản phí xử lý dữ
liệu
→ con số này chứng minh vấn đề
Ba lợi ích: | Lợi ích | Chi tiết | |---|---| | Giảm khoảng 75% phí truyền | | | Lưu lượng không rời mạng AWS | | | Kiểm soát thêm bằng endpoint policy | |
⚠ Và Kinesis còn có tối ưu khác đáng làm:
Dùng `PutRecords` thay `PutRecord`
↓
Gộp tối đa 500 bản ghi một lần
↓
Giảm số lời gọi API
↓
Và KPL còn gộp nhiều bản ghi nhỏ
vào một
→ giảm cả phí PUT payload unit
Vì sao các phương án khác sai
- **B. Interface endpoint cho Kinesis, đảm bảo ứng dụng có quyền IAM cần thiết — đây là phương án gần nhất và chọn đúng loại endpoint, nhưng quyền IAM là điều kiện vốn đã phải có từ trước khi có endpoint; thứ mới cần cấu hình là chính sách endpoint.
- **A. Gateway endpoint cho Kinesis + quyền IAM — Kinesis không có gateway endpoint; chỉ S3 và DynamoDB có.
- **D. Gateway endpoint cho Kinesis + endpoint policy — cùng lỗi về loại endpoint.
Ghi nhớ
⚠ Hai loại VPC endpoint — bảng phải thuộc: | Loại | Dịch vụ | Chi phí | |---|---|---| | Gateway | CHỈ S3 và DynamoDB | miễn phí | | Interface | hầu hết dịch vụ khác | theo giờ mỗi AZ + theo GB |
Từ khoá nhận diện:
"EC2-Other cost from NAT Gateway" → VPC endpoint "gateway endpoint for Kinesis" → LUÔN SAI "endpoint policy" → kiểm soát ở tầng endpoint "private access to S3" → gateway endpoint, miễn phí
Ba lưu ý về interface endpoint: | Lưu ý | Chi tiết | |---|---| | Tạo ENI trong mỗi subnet khai báo | | | Bật --private-dns-enabled | | | Security group phải mở cổng 443 | |
Ba lưu ý về endpoint policy: | Lưu ý | Chi tiết | |---|---| | Mặc định cho phép tất cả | | | Giới hạn tài nguyên gọi được qua endpoint | | | Chặn được rò rỉ sang tài khoản khác | |
Ba lưu ý về chi phí NAT: | Khoản | Giá xấp xỉ | |---|---| | Theo giờ | 32 USD/tháng | | Xử lý dữ liệu | 0,045 USD/GB | | Điểm hoà vốn với endpoint | ~210 GB/tháng mỗi AZ |
Ba tên dịch vụ Kinesis:
com.amazonaws.<region>.kinesis-streams
com.amazonaws.<region>.kinesis-firehose
com.amazonaws.<region>.kinesis-video-streams
Ba lưu ý về sẵn sàng: | Lưu ý | Chi tiết | |---|---| | Tạo endpoint ở mọi AZ có ứng dụng | | | Lưu lượng qua AZ tính phí | | | Một AZ hỏng không kéo theo AZ khác | |
Ba lưu ý về phân tích chi phí: | Lưu ý | Chi tiết | |---|---| | Nhóm theo USAGE_TYPE trong Cost Explorer | | | Tìm NatGateway-Bytes | | | Dùng Flow Log tìm đích chiếm nhiều lưu lượng nhất | |
Ba việc kiểm chứng: | Việc | Cách | |---|---| | dig endpoint Kinesis — phải ra IP riêng tư | | | Xem NatGateway-Bytes giảm sau khi bật | | | Kiểm ứng dụng vẫn ghi được vào stream | |
Và một lời khuyên: hãy dùng VPC Flow Log để tìm xem lưu lượng qua NAT đang đi tới đâu trước khi tạo endpoint. Kinesis thường không phải đích duy nhất — và tạo endpoint cho một dịch vụ trong khi bốn dịch vụ khác vẫn đi qua NAT sẽ giải thích vì sao hoá đơn giảm ít hơn nhiều so với tính toán.
An Amazon S3 bucket is shared by three different teams (managing their own separate AWS accounts) for document uploads. Initially, the S3 bucket settings were set to default. Later, the bucket sees the following updates:
After week 1, S3 Object Ownership bucket-level settings were used and all Access Control Lists (ACLs) were disabled. The three teams uploaded their documents to the shared bucket with this new setting.
After week 2, S3 bucket level settings were again set back to default and the ACLs were enabled once more
What is the outcome of these action(s) on the documents uploaded after week 1 and what are the key points of consideration for future S3 bucket configurations? (Select two)
-
A
To simplify permissions management and auditing, use the
Bucket owner preferredS3 bucket setting -
B
You, as the bucket owner, still own any objects that were written to the bucket while the
bucket owner enforcedsetting was applied. These objects are not owned by theobject writer, even if you re-enable ACLs -
C
You, as the bucket owner, will not own the objects that were written to the bucket while the
bucket owner enforced settingwas applied. These objects will again be owned by the object writer when you re-enable the ACLs -
D
If you used object ACLs for permissions management before you applied the
bucket owner enforcedsetting and you didn't migrate these object ACL permissions to your bucket policy after you re-enable ACLs, these permissions are restored -
E
If you used object ACLs for permissions management before you applied the
bucket owner enforcedsetting and you didn't migrate these object ACL permissions to your bucket policy after you re-enable ACLs, these permissions are not restored
Xem giải thích
Đáp án
**B và D — Bạn, với tư cách chủ bucket, vẫn sở hữu mọi object đã ghi trong lúc bật bucket owner enforced, kể cả sau khi bật lại ACL; và nếu trước đó bạn dùng object ACL để quản quyền mà không chuyển chúng sang bucket policy, thì các quyền đó được khôi phục khi bật lại ACL.
Vì sao đúng
Câu này kiểm tra hai hành vi khác nhau của cùng một thao tác bật/tắt ACL.
⚠ Điểm mấu chốt thứ nhất: quyền sở hữu object là VĨNH VIỄN, không đảo ngược được:
Bật `bucket owner enforced`
↓
Mọi object ghi từ lúc đó thuộc về
CHỦ BUCKET
↓
Tắt đi, bật lại ACL
↓
→ object đó VẪN thuộc chủ bucket
→ quyền sở hữu đã ghi vào siêu dữ
liệu, không đổi ngược
Đây là ý nghĩa của "enforced":
↓
Không phải "tạm thời áp dụng"
↓
Mà là "quyết định vĩnh viễn tại
thời điểm ghi"
⚠ Và đó là lý do mệnh đề C sai:
C nói object sẽ quay về thuộc người
ghi khi bật lại ACL
↓
Không có cơ chế nào làm việc đó
↓
Muốn đổi chủ sở hữu → phải chép
lại object
Đổi chủ sở hữu bằng cách chép lại:
aws s3 cp s3://kho-chung/tep.pdf s3://kho-chung/tep.pdf \
--metadata-directive REPLACE \
--acl bucket-owner-full-control
Chép object lên chính nó
↓
Tài khoản thực hiện trở thành chủ
sở hữu mới
→ đây là cách duy nhất
⚠ Điểm mấu chốt thứ hai: ACL cũ KHÔNG bị xoá, chỉ bị BỎ QUA:
Bật `bucket owner enforced`
↓
S3 ngừng ĐÁNH GIÁ mọi ACL
↓
Nhưng dữ liệu ACL vẫn còn trong
siêu dữ liệu
↓
Bật lại ACL
→ chúng có hiệu lực trở lại
→ đó là mệnh đề D
→ và mệnh đề E nói ngược lại nên sai
⚠ Và đây là rủi ro bảo mật thật:
Đội bật `bucket owner enforced` để
siết bảo mật
↓
Quên chuyển quyền sang bucket
policy
↓
Sau này ai đó tắt đi vì một lý do
nào khác
↓
→ mọi quyền cũ sống lại
→ kể cả quyền cấp cho `AllUsers`
Kiểm tra ACL còn tồn tại:
aws s3api get-object-acl \
--bucket kho-chung --key tai-lieu/tep.pdf
⚠ Và AWS khuyến nghị rõ: chuyển ACL sang bucket policy TRƯỚC khi tắt:
aws s3api get-bucket-acl --bucket kho-chung
aws s3api list-objects-v2 --bucket kho-chung \
--query 'Contents[*].Key' --output text | \
while read k; do
aws s3api get-object-acl --bucket kho-chung --key "$k"
done
Ba giá trị của Object Ownership: | Giá trị | Nghĩa | |---|---| | BucketOwnerEnforced | ACL tắt hẳn, chủ bucket sở hữu tất cả | | BucketOwnerPreferred | ACL bật; object ghi kèm bucket-owner-full-control thuộc chủ bucket | | ObjectWriter | ACL bật; người ghi sở hữu object |
⚠ Và vì sao mệnh đề A không phải câu trả lời tốt nhất:
A khuyên dùng `Bucket owner preferred`
↓
Đó là chế độ TRUNG GIAN
↓
Vẫn cần người ghi khai
`--acl bucket-owner-full-control`
↓
Quên khai → object vẫn thuộc họ
→ không đơn giản hoá được gì
AWS khuyến nghị `BucketOwnerEnforced`
↓
Đó mới là cái "đơn giản hoá quản
lý quyền và kiểm toán"
→ A chọn chế độ giữa chừng
Đặt Object Ownership:
aws s3api put-bucket-ownership-controls \
--bucket kho-chung \
--ownership-controls '{"Rules": [{
"ObjectOwnership": "BucketOwnerEnforced"}]}'
⚠ Và tắt ACL thì phải chuyển sang bucket policy:
{"Version": "2012-10-17",
"Statement": [{
"Sid": "ChoPhepBaDoiTaiLen",
"Effect": "Allow",
"Principal": {"AWS": [
"arn:aws:iam::222233334444:root",
"arn:aws:iam::333344445555:root",
"arn:aws:iam::444455556666:root"]},
"Action": ["s3:PutObject", "s3:GetObject"],
"Resource": "arn:aws:s3:::kho-chung/*"},
{"Sid": "MoiDoiChiThayThuMucCuaMinh",
"Effect": "Deny",
"NotPrincipal": {"AWS": "arn:aws:iam::222233334444:root"},
"Action": "s3:*",
"Resource": "arn:aws:s3:::kho-chung/doi-a/*"}]}
⚠ Và bucket policy có ưu điểm rõ rệt so với ACL: | | ACL | Bucket policy | |---|---|---| | Nơi lưu | trên từng object | một chỗ | | Điều kiện | không có | có (IP, VPC, MFA, thẻ...) | | Kiểm toán | phải đọc từng object | đọc một tài liệu | | Số quy tắc | tối đa 100 grant | 20 KB chính sách |
⚠ Và ACL không có điều kiện là hạn chế lớn nhất:
Muốn: chỉ cho phép từ VPC endpoint
↓
ACL không làm được
↓
Bucket policy:
`Condition: {StringEquals:
{aws:SourceVpce: vpce-abc}}`
⚠ Và có cách phát hiện bucket còn dùng ACL:
aws s3control get-storage-lens-configuration \
--account-id 111122223333 --config-id mac-dinh
Storage Lens có chỉ số về Object
Ownership
↓
Thấy bucket nào chưa tắt ACL
aws configservice put-config-rule --config-rule '{
"ConfigRuleName": "s3-phai-tat-acl",
"Source": {"Owner": "AWS",
"SourceIdentifier": "S3_BUCKET_ACL_PROHIBITED"}}'
⚠ Và Block Public Access là lớp bảo vệ độc lập:
Bốn cờ:
BlockPublicAcls → chặn đặt ACL công khai mới
IgnorePublicAcls → bỏ qua ACL công khai đã có
BlockPublicPolicy → chặn bucket policy công khai
RestrictPublicBuckets → chặn truy cập ẩn danh
`IgnorePublicAcls` chính là lá chắn
cho tình huống ACL cũ sống lại
↓
Kể cả khi ACL công khai được khôi
phục
→ nó vẫn bị bỏ qua
aws s3control put-public-access-block \
--account-id 111122223333 \
--public-access-block-configuration \
BlockPublicAcls=true,IgnorePublicAcls=true,\
BlockPublicPolicy=true,RestrictPublicBuckets=true
⚠ Và ACL từng gây ra vấn đề "chủ bucket không đọc được object của mình":
Tài khoản khác ghi vào bucket của bạn
↓
Không khai `bucket-owner-full-control`
↓
Object thuộc về họ
↓
Bạn trả tiền lưu trữ
→ nhưng KHÔNG đọc được
Đây chính là lý do
`BucketOwnerEnforced` ra đời
↓
Và là mặc định cho bucket tạo từ
tháng 4/2023
Ba lợi ích khi tắt ACL: | Lợi ích | Chi tiết | |---|---| | Một nơi duy nhất quản quyền | | | Chủ bucket luôn đọc được mọi object | | | Kiểm toán đơn giản hơn nhiều | |
⚠ Và Access Analyzer giúp rà soát:
aws accessanalyzer list-findings \
--analyzer-arn <arn> \
--filter '{"resourceType": {"eq": ["AWS::S3::Bucket"]}}'
Vì sao các phương án khác sai
- **A. Dùng chế độ
Bucket owner preferredđể đơn giản hoá quản lý quyền và kiểm toán — đây là phương án gần nhất và thật sự cải thiện so vớiObjectWriter, nhưng nó vẫn giữ ACL bật và vẫn phụ thuộc vào việc người ghi khai đúng ACL; AWS khuyến nghịBucketOwnerEnforcedcho mục đích này. - **C. Object sẽ quay về thuộc người ghi khi bật lại ACL — quyền sở hữu đã ghi vào siêu dữ liệu tại thời điểm ghi, không đảo ngược được.
- **E. Quyền ACL cũ không được khôi phục sau khi bật lại ACL — ngược lại; ACL chỉ bị bỏ qua chứ không bị xoá.
Ghi nhớ
⚠ Ba chế độ Object Ownership — bảng phải thuộc: | Chế độ | ACL | Ai sở hữu object | |---|---|---| | BucketOwnerEnforced | tắt | luôn là chủ bucket | | BucketOwnerPreferred | bật | chủ bucket nếu người ghi khai đúng ACL | | ObjectWriter | bật | người ghi |
Từ khoá nhận diện:
"objects written while ACLs disabled" → chủ bucket sở hữu vĩnh viễn "re-enable ACLs" → ACL cũ sống lại "simplify permissions and auditing" →
BucketOwnerEnforced"bucket owner can't read object" → ACL của người ghi
Ba lưu ý về tắt ACL: | Lưu ý | Chi tiết | |---|---| | Chuyển quyền sang bucket policy TRƯỚC | | | ACL cũ chỉ bị bỏ qua, không bị xoá | | | Mặc định cho bucket mới từ 4/2023 | |
Ba lưu ý về quyền sở hữu: | Lưu ý | Chi tiết | |---|---| | Ghi vào siêu dữ liệu lúc tạo object | | | Không đổi ngược được | | | Chép lại object để đổi chủ | |
Bốn cờ Block Public Access: | Cờ | Chặn gì | |---|---| | BlockPublicAcls | đặt ACL công khai mới | | IgnorePublicAcls | ACL công khai đã có | | BlockPublicPolicy | bucket policy công khai | | RestrictPublicBuckets | truy cập ẩn danh |
Ba lưu ý về bucket policy: | Lưu ý | Chi tiết | |---|---| | Có điều kiện, ACL thì không | | | Tối đa 20 KB | | | Một chỗ duy nhất để đọc và kiểm toán | |
Ba lưu ý về nhiều tài khoản ghi chung: | Lưu ý | Chi tiết | |---|---| | Tách tiền tố theo từng đội | | | Dùng Deny + NotPrincipal để cách ly | | | Hoặc dùng Access Point mỗi đội | |
Ba công cụ rà soát: | Công cụ | Việc | |---|---| | Storage Lens | bucket nào còn bật ACL | | Config rule | cảnh báo bucket vi phạm | | Access Analyzer | tìm chia sẻ ra ngoài |
Ba việc kiểm chứng: | Việc | Cách | |---|---| | get-object-acl xem ACL cũ còn không | | | Kiểm chủ sở hữu object bằng head-object | | | Thử đọc object do tài khoản khác ghi | |
Và một lời khuyên: hãy chuyển toàn bộ quyền từ ACL sang bucket policy trước khi bật BucketOwnerEnforced, chứ đừng chỉ bật rồi để đó. ACL cũ nằm im chứ không biến mất — và ngày nào đó có người tắt cờ vì một lý do hoàn toàn khác, mọi quyền bạn tưởng đã bỏ sẽ sống lại cùng lúc.
An Amazon Simple Storage Service (Amazon S3) bucket has been configured to host a static website. While using the S3 static website endpoint, the testing team has complained that they are receiving access denied error for this website.
What are the key points to consider while configuring an S3 bucket as a static website? (Select two)
-
A
The AWS account that owns the bucket must also own the object
-
B
Objects can't be encrypted by AWS Key Management Service (AWS KMS)
-
C
Objects in the bucket must be publicly accessible. S3 bucket policy must allow access to the s3:GetObject and s3:Put Object actions
-
D
Amazon S3 Block Public Access must be disabled at the bucket level even though it is already disabled at the account level
-
E
Amazon S3 static website endpoint needs to support both publicly and privately accessible content
Xem giải thích
Đáp án
**A và B — Tài khoản AWS sở hữu bucket cũng phải sở hữu object; và object không được mã hoá bằng AWS KMS.
Vì sao đúng
Endpoint website tĩnh của S3 có những ràng buộc riêng, khác hẳn endpoint REST.
⚠ Điểm mấu chốt: website endpoint phục vụ yêu cầu ẨN DANH:
Trình duyệt gọi website endpoint
↓
Không có chữ ký SigV4
↓
S3 xử lý như yêu cầu ẩn danh
↓
→ mọi cơ chế cần danh tính đều
không dùng được
⚠ Và đó là lý do KMS không dùng được:
Object mã hoá bằng SSE-KMS
↓
Giải mã cần quyền `kms:Decrypt`
↓
Yêu cầu ẩn danh không có danh tính
nào
↓
→ không có ai để cấp quyền KMS
→ S3 trả lỗi
Bảng ba kiểu mã hoá với website endpoint: | Kiểu | Dùng được | |---|---| | Không mã hoá | có | | SSE-S3 (AES256) | có | | SSE-KMS | KHÔNG | | SSE-C | KHÔNG |
SSE-S3 dùng được vì khoá do S3 quản
↓
Giải mã không cần quyền của người
gọi
↓
SSE-KMS thì cần
→ đây là khác biệt then chốt
Đặt mã hoá đúng cho bucket website:
aws s3api put-bucket-encryption --bucket trang-web \
--server-side-encryption-configuration '{
"Rules": [{"ApplyServerSideEncryptionByDefault":
{"SSEAlgorithm": "AES256"}}]}'
⚠ Điểm mấu chốt thứ hai: chủ bucket phải sở hữu object:
Object do tài khoản khác ghi
↓
Bucket policy của bạn cấp quyền
`s3:GetObject` cho `*`
↓
Nhưng bạn KHÔNG sở hữu object đó
↓
→ bucket policy của bạn không áp
được cho object của người khác
→ Access Denied
⚠ Và đây là lý do rất hay gặp trong thực tế:
Quy trình CI/CD ở tài khoản A đẩy tệp
lên bucket của tài khoản B
↓
Không khai `bucket-owner-full-control`
↓
Website hiện Access Denied cho
đúng những tệp mới đẩy
→ tệp cũ vẫn chạy bình thường
Cách chữa dứt điểm:
aws s3api put-bucket-ownership-controls \
--bucket trang-web \
--ownership-controls '{"Rules": [{
"ObjectOwnership": "BucketOwnerEnforced"}]}'
Tắt ACL
↓
Chủ bucket sở hữu MỌI object bất
kể ai ghi
→ không bao giờ gặp lại vấn đề này
⚠ Và vì sao mệnh đề C sai — không cần s3:PutObject:
C nói bucket policy phải cho phép
`s3:GetObject` VÀ `s3:PutObject`
↓
Người xem website chỉ ĐỌC
↓
Cho phép `PutObject` công khai
→ ai cũng ghi được vào bucket của
bạn
→ đây là lỗi cấu hình nghiêm trọng
Bucket policy đúng cho website công khai:
{"Version": "2012-10-17",
"Statement": [{
"Sid": "ChoPhepDocCongKhai",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::trang-web/*"}]}
⚠ Và vì sao mệnh đề D sai — Block Public Access không có "cấp tài khoản đè lên":
D nói phải tắt Block Public Access ở
cấp bucket dù đã tắt ở cấp tài khoản
↓
Thực tế ngược lại:
↓
Cấp TÀI KHOẢN đè lên cấp bucket
↓
Bật ở tài khoản → mọi bucket đều
bị chặn
→ tắt ở tài khoản thì cấp bucket
mới có tác dụng
Kiểm tra cả hai cấp:
aws s3control get-public-access-block --account-id 111122223333
aws s3api get-public-access-block --bucket trang-web
⚠ Và vì sao mệnh đề E sai:
E nói website endpoint phải phục vụ
cả nội dung công khai lẫn riêng tư
↓
Website endpoint CHỈ phục vụ nội
dung công khai
↓
Không có cơ chế xác thực nào
→ cần nội dung riêng tư thì dùng
CloudFront + signed URL
Bảng REST endpoint và website endpoint: | | REST endpoint | Website endpoint | |---|---|---| | HTTPS | có | KHÔNG | | Tài liệu mặc định (index.html) | không | có | | Trang lỗi tuỳ chỉnh | không | có | | Chuyển hướng | không | có | | Yêu cầu đã ký | có | chỉ ẩn danh | | SSE-KMS | có | không | | Dùng OAC được | có | không |
⚠ Và thiếu HTTPS là hạn chế nghiêm trọng nhất:
Website endpoint chỉ phục vụ HTTP
↓
Trình duyệt cảnh báo "không an
toàn"
↓
Không dùng được cho trang cần đăng
nhập hay thanh toán
→ giải pháp: CloudFront phía trước
Bật website hosting:
aws s3api put-bucket-website --bucket trang-web \
--website-configuration '{
"IndexDocument": {"Suffix": "index.html"},
"ErrorDocument": {"Key": "404.html"}}'
⚠ Và cách hiện đại: bucket riêng tư + CloudFront + OAC:
aws cloudfront create-origin-access-control \
--origin-access-control-config '{
"Name": "oac-trang-web",
"OriginAccessControlOriginType": "s3",
"SigningBehavior": "always",
"SigningProtocol": "sigv4"}'
Bucket hoàn toàn riêng tư
↓
Chỉ CloudFront đọc được
↓
Có HTTPS, có chứng chỉ riêng
↓
Và SSE-KMS dùng được (OAC hỗ trợ)
⚠ Nhưng OAC dùng REST endpoint nên mất tài liệu mặc định:
Người dùng vào `/blog/`
↓
REST endpoint không tự thêm
`index.html`
↓
→ 403 hoặc 404
Chữa bằng CloudFront Function:
function handler(event) {
var yeuCau = event.request;
var uri = yeuCau.uri;
if (uri.endsWith('/')) {
yeuCau.uri += 'index.html';
} else if (!uri.includes('.')) {
yeuCau.uri += '/index.html';
}
return yeuCau;
}
⚠ Và trang lỗi tuỳ chỉnh cấu hình ở CloudFront:
{"CustomErrorResponses": {"Items": [{
"ErrorCode": 403,
"ResponsePagePath": "/404.html",
"ResponseCode": "404",
"ErrorCachingMinTTL": 300}]}}
S3 trả 403 khi object không tồn tại
(vì OAC không cho `ListBucket`)
↓
CloudFront đổi thành 404 + trang
lỗi đẹp
⚠ Và tên bucket phải khớp tên miền nếu dùng website endpoint với Route 53:
Muốn `www.congty.vn` trỏ tới website
endpoint
↓
Bucket phải tên đúng `www.congty.vn`
↓
Vì alias record của Route 53 trỏ
tới website endpoint dựa trên
tên
→ ràng buộc này không có khi dùng
CloudFront
Ba lợi ích khi chuyển sang CloudFront + OAC: | Lợi ích | Chi tiết | |---|---| | Có HTTPS và chứng chỉ riêng | | | Bucket hoàn toàn riêng tư | | | Dùng được SSE-KMS | |
Vì sao các phương án khác sai
- **C. Object phải công khai và bucket policy phải cho phép
s3:GetObjectvàs3:PutObject— đây là phương án gần nhất và vếGetObjecthoàn toàn đúng, nhưng cho phépPutObjectcông khai nghĩa là bất kỳ ai cũng ghi được vào bucket của bạn. - **D. Phải tắt Block Public Access ở cấp bucket dù đã tắt ở cấp tài khoản — quan hệ ngược lại: cấu hình cấp tài khoản đè lên cấp bucket.
- **E. Website endpoint cần phục vụ cả nội dung công khai lẫn riêng tư — website endpoint chỉ phục vụ yêu cầu ẩn danh, không có cơ chế xác thực.
Ghi nhớ
⚠ Bốn ràng buộc của website endpoint — bảng phải thuộc: | Ràng buộc | Chi tiết | |---|---| | Không hỗ trợ HTTPS | cần CloudFront | | Không hỗ trợ SSE-KMS | chỉ SSE-S3 | | Chủ bucket phải sở hữu object | tắt ACL để chắc chắn | | Chỉ phục vụ nội dung công khai | không xác thực được |
Từ khoá nhận diện:
"static website endpoint, access denied" → kiểm quyền sở hữu object và mã hoá "KMS encrypted static site" → không dùng được website endpoint "need HTTPS for static site" → CloudFront + OAC "index.html with OAC" → CloudFront Function viết lại URI
Ba lưu ý về mã hoá: | Kiểu | Website endpoint | |---|---| | SSE-S3 | được | | SSE-KMS | không | | SSE-C | không |
Ba lưu ý về quyền sở hữu: | Lưu ý | Chi tiết | |---|---| | Bucket policy không áp cho object của tài khoản khác | | | BucketOwnerEnforced chữa dứt điểm | | | Object cũ phải chép lại để đổi chủ | |
Ba lưu ý về Block Public Access: | Lưu ý | Chi tiết | |---|---| | Cấp tài khoản đè lên cấp bucket | | | Bật mặc định cho bucket mới | | | Kiểm cả hai cấp khi chẩn đoán | |
Ba lưu ý về CloudFront + OAC: | Lưu ý | Chi tiết | |---|---| | Dùng REST endpoint, không phải website endpoint | | | Mất tài liệu mặc định, cần Function bù | | | Custom error response cho trang 404 | |
Ba lưu ý về tên bucket: | Lưu ý | Chi tiết | |---|---| | Website endpoint + Route 53 đòi tên trùng tên miền | | | CloudFront không có ràng buộc này | | | Tên bucket là toàn cục | |
Ba lưu ý về bảo mật: | Lưu ý | Chi tiết | |---|---| | Không bao giờ cho PutObject công khai | | | Ưu tiên bucket riêng tư + CloudFront | | | Bật versioning chống xoá nhầm | |
Ba việc kiểm chứng: | Việc | Cách | |---|---| | head-object xem chủ sở hữu và kiểu mã hoá | | | Gọi website endpoint bằng curl -I | | | Kiểm Block Public Access ở cả hai cấp | |
Và một lời khuyên: hãy kiểm tra kiểu mã hoá của từng object khi một phần trang web trả Access Denied còn phần khác vẫn chạy. Kiểu lỗi từng phần này gần như luôn có nghĩa là các object được ghi bởi hai quy trình khác nhau — một cái dùng SSE-S3, một cái dùng SSE-KMS, hoặc một cái ghi từ tài khoản khác.