2. AWS账户与基础设施即代码起步

微服务架构的第一块地基不是代码,而是账户与网络边界。如果所有服务、数据库、CI/CD 流水线都挤在一个 AWS 账户里,一次误删、一次密钥泄露或一次权限越界,影响面就是整个系统。因此生产级微服务通常从“多账户 + 基础设施即代码(IaC)”开始:账户负责隔离爆炸半径,IaC 负责让环境可重复、可审计、可回滚。

多账户策略:先划边界,再谈服务

AWS Organizations 是组织多账户的入口。常见做法是按职责拆分 OU(组织单元):安全 OU 放日志归档与安全审计账户,基础设施 OU 放网络与共享服务账户,工作负载 OU 放开发、测试、预发、生产账户。生产账户与开发账户之间默认不互通,跨账户访问通过 IAM Role 显式授权,而不是共享 Access Key。

一个可落地的起步划分如下:管理账户只用于账单与 Organizations 管理,不部署业务;日志归档账户集中接收 CloudTrail 与 Config 日志,并开启 S3 Object Lock 防篡改;网络账户持有 Transit Gateway 或共享 VPC;工作负载账户按环境拆分,每个账户独立 VPC、独立 IAM 边界。这样即使生产账户被误操作,也不会波及日志与网络控制面。

起步阶段不必一次拆到十几个账户。建议先落地“管理 + 日志 + 网络 + 开发 + 生产”五个账户,后续按团队或业务域继续细分。

IAM 权限模型:最小权限与角色传递

IAM 的核心不是“给谁什么权限”,而是“谁在什么条件下能扮演什么角色”。微服务场景下,人、CI/CD、运行时服务应使用三类不同身份:人员通过 SSO 联合登录并扮演只读或运维角色;CI/CD 通过 OIDC 联合到 AWS,避免长期密钥;服务运行时使用 IAM Role(如 EKS IRSA 或 ECS Task Role),按需授予 S3、SQS、DynamoDB 等最小权限。

权限策略建议遵循三层结构:权限边界(Permissions Boundary)限制身份最大权限,防止越权提权;身份策略定义具体允许的操作;资源策略在 S3、KMS、SQS 等资源侧做二次约束。例如,一个订单服务角色可以只允许读写 orders-* 前缀的 S3 对象,并强制通过 aws:SourceVpce 条件限制只能从指定 VPC 终端节点访问。

CDK 与 Terraform 选型

两者都能实现可重复部署,但定位不同。Terraform 使用 HCL,多云与生态成熟,状态文件(state)是核心,适合已有 Terraform 团队或需要跨云统一管理的场景。AWS CDK 使用 TypeScript、Python 等通用语言,把基础设施编译为 CloudFormation 模板,天然贴近 AWS 新服务,适合以 AWS 为主、希望用编程抽象复用组件的团队。

维度TerraformAWS CDK
语言HCL 声明式TypeScript/Python 等
状态管理需自管 state(S3+DynamoDB 锁)由 CloudFormation 托管
多云强仅 AWS
抽象复用ModuleConstruct / L2/L3
适合场景多云、已有 IaC 体系AWS 原生、快速迭代

选型没有绝对优劣。若团队已用 Terraform 管理云资源,继续沿用可降低认知成本;若从零起步且以 AWS 为主,CDK 的 Construct 能显著减少样板代码。关键是选定一种后,把网络、IAM、日志等基础组件封装为可复用模块,避免每个环境手写一遍。

搭建第一个 VPC 与安全组

下面以 CDK(TypeScript)为例,创建一个跨两个可用区的 VPC,并定义安全组。示例参数为教学假设:VPC CIDR 为 10.20.0.0/16,公有子网 10.20.0.0/24、10.20.1.0/24,私有子网 10.20.10.0/24、10.20.11.0/24,NAT 网关仅一个以控制成本。

import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';

export class NetworkStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const vpc = new ec2.Vpc(this, 'MicroVpc', {
      ipAddresses: ec2.IpAddresses.cidr('10.20.0.0/16'),
      maxAzs: 2,
      natGateways: 1,
      subnetConfiguration: [
        { name: 'public', subnetType: ec2.SubnetType.PUBLIC, cidrMask: 24 },
        { name: 'private', subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, cidrMask: 24 },
      ],
    });

    const albSg = new ec2.SecurityGroup(this, 'AlbSg', {
      vpc,
      description: 'ALB ingress from internet',
      allowAllOutbound: true,
    });
    albSg.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(443), 'HTTPS from internet');

    const appSg = new ec2.SecurityGroup(this, 'AppSg', {
      vpc,
      description: 'App tier accepts traffic from ALB only',
      allowAllOutbound: true,
    });
    appSg.addIngressRule(albSg, ec2.Port.tcp(8080), 'App port from ALB');
  }
}

部署后应验证三件事:VPC 与子网 CIDR 是否符合规划;私有子网路由是否指向 NAT 网关;安全组入站规则是否只放行预期来源。可用 aws ec2 describe-vpcs 与 aws ec2 describe-security-groups 核对,或在控制台查看资源映射。若私有子网无法访问外网,优先检查 NAT 网关所在公有子网的路由表是否指向 Internet Gateway。

多账户边界与首个 VPC 网络拓扑 管理账户 Organizations / 账单 不部署业务 SCP 统一约束 日志归档账户 CloudTrail / Config S3 Object Lock 防篡改审计 网络账户 Transit Gateway 共享 VPC / 路由 集中出口 工作负载账户 dev / test / prod 独立 VPC 独立 IAM 边界 工作负载账户内的首个 VPC:10.20.0.0/16 公有子网 A / B 10.20.0.0/24 · 10.20.1.0/24 ALB · NAT Gateway 私有子网 A / B 10.20.10.0/24 · 10.20.11.0/24 ECS / EKS 任务 安全组 AlbSg 入站:0.0.0.0/0 → 443 出站:全部允许 安全组 AppSg 入站:AlbSg → 8080 出站:全部允许 流量

这张图把账户边界与 VPC 内部结构放在同一视野:上层是账户隔离,下层是首个 VPC 的子网与安全组关系。实际部署时,建议把网络栈与业务栈分开,网络栈变更频率低、影响面大,应单独评审;业务栈通过参数引用网络栈输出的 VPC ID 与子网 ID,避免硬编码。

安全组规则不要使用 0.0.0.0/0 放行管理端口(22/3389)。生产环境应通过 SSM Session Manager 或堡垒机访问,安全组只允许来自堡垒机安全组的流量。

完成这一步后,你得到的是一个可重复部署的基础环境:账户边界清晰、IAM 角色可传递、网络与安全组由代码定义。后续微服务的 ECS/EKS、RDS、消息队列都在这张网络上生长,而不是每次手工点控制台。下一阶段再引入 CI/CD 时,只需把同一套 IaC 模块接入流水线,即可实现开发、预发、生产环境的一致性交付。