AWS 基础:Region、IAM 和主要服务
1. 总览
本文帮助你快速掌握刚接触 AWS 时最重要的三个支柱:region(选择基础设施部署在何处)、IAM(谁能做什么)和主要服务(EC2、S3、RDS、Lambda、VPC……)。读完后,你将理解如何安全地组织 AWS 账户、懂得如何为应用创建 IAM role,并且能写出通过 AWS SDK v2 调用 S3 的 Java 代码。
2. Region 和 Availability Zone
AWS 将基础设施分成 region(地理区域,例如 ap-southeast-1 位于新加坡)和各 region 内的多个 Availability Zone(AZ) —— 这些是在电力、网络上都独立的数据中心,彼此靠得很近(延迟低)但在故障上保持隔离(故障隔离)。
aws ec2 describe-availability-zones --region ap-southeast-1
上面的命令列出新加坡 region 内的 AZ。结果通常如下:
ZoneName: ap-southeast-1a
ZoneName: ap-southeast-1b
ZoneName: ap-southeast-1c
在设计系统时,你应该至少部署在 2 个 AZ 中以实现容错(高可用)。例如 Auto Scaling Group 或 RDS 多 AZ 实例都遵循这个原则。
注意: 某些服务是 全局的(不绑定特定 region),如 IAM、Route 53、CloudFront。其他大多数服务(EC2、S3、RDS……)是 区域性的,数据不会自动复制到其他 region,除非你主动配置。
2.1. 如何选择 region
三个主要标准:延迟(靠近用户)、合规性(数据存储位置要求)和成本(不同 region 的服务价格不同)。对于越南用户,ap-southeast-1(新加坡)通常是首选,因为延迟低且服务完整。
3. IAM:User、Group、Role、Policy
IAM(Identity and Access Management)控制谁可以访问什么资源。四个核心概念:
- User:具体的身份(人或服务)拥有自己的凭证。
- Group:用户集合,便于批量管理策略。
- Role:临时权限集合,不绑定固定凭证 —— 用于 EC2、Lambda 或跨账户访问。
- Policy:JSON 文档,描述对操作和资源的权限(允许/拒绝)。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject"],
"Resource": "arn:aws:s3:::order-invoices-bucket/*"
}
]
}
这个 Policy 允许读/写 order-invoices-bucket bucket 中的对象。将 policy 附加到一个 role,然后将这个 role 关联到运行 InvoiceStorageService 服务的 EC2 实例或 Lambda 函数 —— 应用会自动拥有权限,无需硬编码 access key/secret key。
aws iam create-role \
--role-name InvoiceServiceRole \
--assume-role-policy-document file://trust-policy.json
aws iam attach-role-policy \
--role-name InvoiceServiceRole \
--policy-arn arn:aws:iam::123456789012:policy/InvoiceBucketAccess
第一条命令用 trust-policy.json 创建 role,其中定义谁可以 “assume” 这个 role(例如 EC2 service)。第二条命令将具体权限策略附加到 role。
注意: 永远不要在代码中硬编码 access key/secret key 或提交到 Git。对于 AWS 上运行的资源使用 IAM Role,对于用户使用 IAM Identity Center/SSO。
3.1. 最小权限原则
只授予必要的权限,不要给服务账户使用 AdministratorAccess policy。例如一个 Lambda 只需要读某个 bucket,就不应该授予整个账户的 s3:* 权限。
{
"Effect": "Deny",
"Action": "s3:DeleteBucket",
"Resource": "*"
}
Deny Statement 在冲突时总是优先于 Allow —— 这是一种“安全网”,防止误删重要 bucket。
4. 主要服务
4.1. 计算
- EC2:虚拟机按小时/秒收费,你自己管理操作系统。
- Lambda:事件驱动运行代码,无需管理服务器,按调用次数和运行时间计费。
- ECS/EKS:运行带编排的容器(Docker)。
aws lambda invoke \
--function-name CalculateOrderTotal \
--payload '{"orderId":"ORD-1001"}' \
response.json
这条命令调用 CalculateOrderTotal 函数,传入 JSON payload,结果写入 response.json。
4.2. 存储
- S3:对象存储,保存任意文件(图像、日志、备份),耐久性 99.999999999%。
- EBS:块存储,挂载到 EC2。
- EFS:共享文件系统,多个 EC2 可以同时挂载。
4.3. 数据库
- RDS:托管关系数据库(MySQL、PostgreSQL……),自动备份、补丁。
- DynamoDB:NoSQL,自动横向扩展,毫秒级延迟。
4.4. 网络
- VPC:虚拟私有网络,你定义子网、路由表、安全组。
- Security Group:实例级有状态防火墙。
Resources:
OrderServiceSG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: 允许 HTTPS 入站
VpcId: vpc-0123456789abcdef0
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
这段 CloudFormation 创建名为 OrderServiceSG 的安全组,仅对所有 IP 开放 443 端口(HTTPS)—— 其他入站规则默认被拒绝。
5. 从 Java 应用调用 S3
本部分演示如何用 AWS SDK for Java v2 从 Spring Boot 服务上传文件到 S3。
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3</artifactId>
<version>2.25.16</version>
</dependency>
public class InvoiceStorageService {
private final S3Client s3Client;
private final String bucketName;
public InvoiceStorageService(S3Client s3Client, String bucketName) {
this.s3Client = s3Client;
this.bucketName = bucketName;
}
public void uploadInvoice(String orderId, byte[] content) {
PutObjectRequest request = PutObjectRequest.builder()
.bucket(bucketName)
.key("invoices/" + orderId + ".pdf")
.build();
s3Client.putObject(request, RequestBody.fromBytes(content));
}
}
S3Client 通过构造函数注入(如果在 EC2/Lambda 上运行会自动从 IAM Role 获取凭证,无需硬编码)。uploadInvoice 方法用 key 作为 bucket 内的对象路径创建 PutObjectRequest,然后调用 putObject 上传内容到 S3。
S3Client bean 的配置:
@Bean
public S3Client s3Client() {
return S3Client.builder()
.region(Region.AP_SOUTHEAST_1)
.build();
}
无需显式传入 credentialsProvider —— SDK 自动使用 Default Credentials Provider Chain:按顺序查找环境变量、~/.aws/credentials 文件,然后查找 EC2/ECS/Lambda 关联的 IAM Role。
5.1. 用 mock S3Client 测试
@Test
void shouldCallPutObjectWithCorrectKey() {
S3Client mockS3 = mock(S3Client.class);
InvoiceStorageService service = new InvoiceStorageService(mockS3, "order-invoices-bucket");
service.uploadInvoice("ORD-1001", "发票内容".getBytes());
ArgumentCaptor<PutObjectRequest> captor = ArgumentCaptor.forClass(PutObjectRequest.class);
verify(mockS3).putObject(captor.capture(), any(RequestBody.class));
assertThat(captor.getValue().bucket()).isEqualTo("order-invoices-bucket");
assertThat(captor.getValue().key()).isEqualTo("invoices/ORD-1001.pdf");
}
用 Mockito mock S3Client,这样在运行 CI 时不会调用真实的 AWS。ArgumentCaptor 捕获实际发送的 PutObjectRequest,然后用 AssertJ 验证 bucket 和 key 符合预期 —— 确保构建 request 的逻辑正确且不浪费网络成本。
注意: 要进行真实的集成测试,使用 LocalStack 或 Testcontainers 库而非调用生产环境的 S3 bucket —— 避免产生成本和数据风险。
6. 常见错误
- 不小心把 S3 bucket 设为公开:除非真的需要公开 bucket(例如静态网站),否则始终在账户级别启用 “Block Public Access”。
- 给 test role 附加过宽泛的 policy(
"Action": "*", "Resource": "*"),然后忘记在上生产前移除。 - 没有给 root 账户启用 MFA:root 账户拥有完全权限,失去 root 访问权是最严重的风险。
- 在代码中硬编码 access key:应该使用 IAM Role、Secrets Manager 或通过 CI/CD secret 的环境变量。
- 选错 region 导致终端用户延迟高或违反数据本地化存储要求。
7. 总结
Region 帮助你在延迟、成本和合规性之间平衡选择基础设施位置。IAM 是第一道防线,也是最关键的 —— 始终遵循最小权限原则,优先使用 Role 而非静态 access key。掌握核心服务组(EC2、S3、RDS、Lambda、VPC)及通过 AWS SDK 的集成方式,足以让你开始在 AWS 上部署真实系统。