Một backend developer cần deploy service lên AWS, mở console EC2 thấy 300 instance type, không biết chọn cái nào. Chọn nhầm, hóa đơn cuối tháng x2. Bài này là những thứ mình học được sau N lần chọn sai instance type.

EC2 là service lâu đời nhất AWS (2006), và cũng là service dễ cấu hình sai nhất. Capital One breach 2019 bắt đầu từ EC2 instance dùng IMDSv1, attacker SSRF vào metadata endpoint, lấy IAM role credential, dùng role đó đọc 100M hồ sơ S3.

Bài này tập trung vào những thứ backend developer thực sự cần, theo thứ tự ưu tiên: chọn instance type (Graviton ARM), SSM Session Manager thay SSH, IMDSv2, và instance profile cho credential an toàn.


  flowchart TB
    AMI["AMI<br/>OS + app base"]
    Type["Instance Type<br/>family · gen · size"]
    UserData["User Data<br/>bootstrap script<br/>chạy 1 lần"]
    SSM["SSM Session Manager<br/>không port 22<br/>không public IP"]
    IMDS["IMDSv2<br/>session token<br/>chống SSRF"]
    Profile["Instance Profile<br/>IAM role → temp credential"]
    AMI --> Type
    Type --> UserData
    UserData --> SSM
    SSM --> IMDS
    IMDS --> Profile
```text

---

## Instance type: đọc tên, hiểu ngay

```text
t4g.medium
│││  └── size: nano · micro · small · medium · large · xlarge · 2xlarge...
││└── generation: 4
│└── attr: g=Graviton(ARM) · i=Intel · a=AMD · d=NVMe · n=network optimized
└── family: t=burstable · m=general · c=compute · r=memory · g=GPU
```text

| Family | Use Case | Ví dụ |
|--------|----------|-------|
| **t** (burstable) | Web server, dev, API nhẹ | `t4g.medium` ~$0.03/h |
| **m** (general) | Application server, backend | `m7g.large` ~$0.08/h |
| **c** (compute) | Batch processing, encoding | `c7g.xlarge` |
| **r** (memory) | In-memory DB, cache | `r7g.large` |
| **g** (GPU) | ML inference, rendering | `g4dn.xlarge` |

Graviton ARM rẻ hơn ~20%, performance tương đương. Node.js/Python/Go chạy native trên ARM. Kiểm tra: nếu app có native C++ addon hoặc Rust binary → test trên Graviton trước khi deploy. AWS khuyến nghị Graviton làm default cho workload mới từ 2025.
--- ## SSM Session Manager: không bao giờ mở port 22 Mình từng thấy team dùng EC2 classic không SSM, mở port 22, rồi một hôm phát hiện SSH brute force từ Trung Quốc. Từ đó mình chuyển hết sang SSM, không bao giờ nhìn lại. ```bash aws iam attach-role-policy --role-name ec2-ssm-role \ --policy-arn arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore # Connect — không SSH key, không public IP, không SG inbound rule aws ssm start-session --target i-1234567890abcdef0 # Port forward: localhost:3000 → EC2:3000 aws ssm start-session --target i-xxx \ --document-name AWS-StartPortForwardingSession \ --parameters '{"portNumber":["3000"],"localPortNumber":["3000"]}' ```text --- ## IMDSv2: chống SSRF credential theft Capital One 2019: attacker SSRF → `curl http://169.254.169.254/latest/meta-data/iam/security-credentials/` → lấy credential. IMDSv1 là plain HTTP GET, không authentication. IMDSv2 yêu cầu **session token**: ```bash TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" \ -H "X-aws-ec2-metadata-token-ttl-seconds: 21600") curl -H "X-aws-ec2-metadata-token: $TOKEN" \ http://169.254.169.254/latest/meta-data/iam/security-credentials/ec2-role ```text ```bash # Launch với IMDSv2 required aws ec2 run-instances \ --image-id ami-xxx --instance-type t4g.medium \ --metadata-options HttpTokens=required,HttpPutResponseHopLimit=2 ```text HopLimit=2 cho phép container trên EC2 cũng lấy được credential từ IMDS, nếu app chạy trong Docker cần hop > 1. --- ## Instance profile: credential không access key ```bash aws iam create-role --role-name ec2-s3-reader --assume-role-policy-document '{ "Version": "2012-10-17", "Statement": [{"Effect":"Allow","Principal":{"Service":"ec2.amazonaws.com"},"Action":"sts:AssumeRole"}] }' aws iam attach-role-policy --role-name ec2-s3-reader --policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess aws iam create-instance-profile --instance-profile-name ec2-s3-reader aws iam add-role-to-instance-profile --instance-profile-name ec2-s3-reader --role-name ec2-s3-reader ```text SDK tự động lấy credential từ IMDS → không cần access key trong code. --- SSM + IMDSv2 + instance profile là bộ ba an toàn tối thiểu cho EC2 production. Graviton ARM là default mặc định từ giờ. - **Graviton ARM rẻ hơn 20%** — default cho workload mới từ 2025 - **SSM Session Manager thay SSH** — không port 22, không public IP, audit log tập trung - **IMDSv2 required** — session token chặn SSRF (Capital One 2019) - **Instance profile** — credential tự động từ IMDS, không access key Bài sau: [Phần 9: Auto Scaling Group & Application Load Balancer](/posts/aws/09-asg-alb-auto-scaling-load-balancer/)