Infrastructure as Code Templates

Tự động hóa Triển khai VPC với Infrastructure as Code

ℹ️ Infrastructure as Code (IaC) là gì?
Infrastructure as Code là thực hành quản lý và cung cấp hạ tầng máy tính thông qua các tệp định nghĩa có thể đọc được bằng máy, thay vì cấu hình phần cứng vật lý hoặc các công cụ cấu hình tương tác.

Lợi ích của IaC cho Triển khai VPC

🚀 Xuất sắc Vận hành:

  • Khả năng Lặp lại: Triển khai môi trường giống hệt nhau một cách nhất quán
  • Kiểm soát Phiên bản: Theo dõi các thay đổi hạ tầng theo thời gian
  • Tự động hóa: Giảm lỗi thủ công và thời gian triển khai
  • Tài liệu: Code phục vụ như tài liệu sống

💰 Tối ưu Chi phí:

  • Vòng đời Tài nguyên: Dễ dàng hủy và tạo lại môi trường
  • Chuẩn hóa: Ngăn chặn sự lan tràn và cung cấp quá mức tài nguyên
  • Kiểm thử: Xác thực cấu hình trước khi triển khai

🔒 Bảo mật & Tuân thủ:

  • Nhất quán: Áp dụng chính sách bảo mật một cách đồng nhất
  • Audit Trail: Theo dõi tất cả các thay đổi hạ tầng
  • Xác thực: Kiểm tra bảo mật và tuân thủ tự động

CloudFormation Template

  1. Template VPC Stack Hoàn chỉnh:
AWSTemplateFormatVersion: '2010-09-09'
Description: 'VPC production-ready với multi-AZ NAT Gateways, Flow Logs, và Security Groups'

Parameters:
  VpcCidr:
    Type: String
    Default: '10.10.0.0/16'
    Description: 'CIDR block cho VPC'
    
  Environment:
    Type: String
    Default: 'prod'
    AllowedValues: ['dev', 'staging', 'prod']
    Description: 'Tên môi trường'

Resources:
  # VPC
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VpcCidr
      EnableDnsHostnames: true
      EnableDnsSupport: true
      Tags:
        - Key: Name
          Value: !Sub '${Environment}-VPC'
        - Key: Environment
          Value: !Ref Environment

  # Internet Gateway
  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: !Sub '${Environment}-IGW'

  InternetGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      InternetGatewayId: !Ref InternetGateway
      VpcId: !Ref VPC

  # Public Subnets
  PublicSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select [0, !GetAZs '']
      CidrBlock: !Select [0, !Cidr [!Ref VpcCidr, 4, 8]]
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Sub '${Environment}-Public-Subnet-AZ1'

  PublicSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select [1, !GetAZs '']
      CidrBlock: !Select [1, !Cidr [!Ref VpcCidr, 4, 8]]
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Sub '${Environment}-Public-Subnet-AZ2'

  # Private Subnets
  PrivateSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select [0, !GetAZs '']
      CidrBlock: !Select [2, !Cidr [!Ref VpcCidr, 4, 8]]
      Tags:
        - Key: Name
          Value: !Sub '${Environment}-Private-Subnet-AZ1'

  PrivateSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select [1, !GetAZs '']
      CidrBlock: !Select [3, !Cidr [!Ref VpcCidr, 4, 8]]
      Tags:
        - Key: Name
          Value: !Sub '${Environment}-Private-Subnet-AZ2'

  # NAT Gateways
  NatGateway1EIP:
    Type: AWS::EC2::EIP
    DependsOn: InternetGatewayAttachment
    Properties:
      Domain: vpc
      Tags:
        - Key: Name
          Value: !Sub '${Environment}-NAT-EIP-AZ1'

  NatGateway2EIP:
    Type: AWS::EC2::EIP
    DependsOn: InternetGatewayAttachment
    Properties:
      Domain: vpc
      Tags:
        - Key: Name
          Value: !Sub '${Environment}-NAT-EIP-AZ2'

  NatGateway1:
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId: !GetAtt NatGateway1EIP.AllocationId
      SubnetId: !Ref PublicSubnet1
      Tags:
        - Key: Name
          Value: !Sub '${Environment}-NAT-Gateway-AZ1'

  NatGateway2:
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId: !GetAtt NatGateway2EIP.AllocationId
      SubnetId: !Ref PublicSubnet2
      Tags:
        - Key: Name
          Value: !Sub '${Environment}-NAT-Gateway-AZ2'

  # Route Tables
  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub '${Environment}-Public-Routes'

  DefaultPublicRoute:
    Type: AWS::EC2::Route
    DependsOn: InternetGatewayAttachment
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway

  PublicSubnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PublicRouteTable
      SubnetId: !Ref PublicSubnet1

  PublicSubnet2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PublicRouteTable
      SubnetId: !Ref PublicSubnet2

  PrivateRouteTable1:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub '${Environment}-Private-Routes-AZ1'

  DefaultPrivateRoute1:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PrivateRouteTable1
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref NatGateway1

  PrivateSubnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PrivateRouteTable1
      SubnetId: !Ref PrivateSubnet1

  PrivateRouteTable2:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub '${Environment}-Private-Routes-AZ2'

  DefaultPrivateRoute2:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PrivateRouteTable2
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref NatGateway2

  PrivateSubnet2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PrivateRouteTable2
      SubnetId: !Ref PrivateSubnet2

  # Security Groups
  PublicSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub '${Environment}-Public-SG'
      GroupDescription: 'Security group cho tài nguyên public subnet'
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0  # Hạn chế trong production
          Description: 'SSH access'
        - IpProtocol: icmp
          FromPort: -1
          ToPort: -1
          CidrIp: !Ref VpcCidr
          Description: 'ICMP trong VPC'
      Tags:
        - Key: Name
          Value: !Sub '${Environment}-Public-SG'

  PrivateSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub '${Environment}-Private-SG'
      GroupDescription: 'Security group cho tài nguyên private subnet'
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          SourceSecurityGroupId: !Ref PublicSecurityGroup
          Description: 'SSH từ public subnet'
        - IpProtocol: icmp
          FromPort: -1
          ToPort: -1
          CidrIp: !Ref VpcCidr
          Description: 'ICMP trong VPC'
      Tags:
        - Key: Name
          Value: !Sub '${Environment}-Private-SG'

  # VPC Flow Logs
  VPCFlowLogRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: vpc-flow-logs.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: flowlogsDeliveryRolePolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                  - logs:DescribeLogGroups
                  - logs:DescribeLogStreams
                Resource: '*'

  VPCFlowLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub '/aws/vpc/flowlogs/${Environment}'
      RetentionInDays: 30

  VPCFlowLog:
    Type: AWS::EC2::FlowLog
    Properties:
      ResourceType: VPC
      ResourceId: !Ref VPC
      TrafficType: ALL
      LogDestinationType: cloud-watch-logs
      LogGroupName: !Ref VPCFlowLogGroup
      DeliverLogsPermissionArn: !GetAtt VPCFlowLogRole.Arn
      Tags:
        - Key: Name
          Value: !Sub '${Environment}-VPC-FlowLogs'

Outputs:
  VPC:
    Description: 'VPC ID'
    Value: !Ref VPC
    Export:
      Name: !Sub '${Environment}-VPC-ID'

  PublicSubnets:
    Description: 'Public subnet IDs'
    Value: !Join [',', [!Ref PublicSubnet1, !Ref PublicSubnet2]]
    Export:
      Name: !Sub '${Environment}-Public-Subnets'

  PrivateSubnets:
    Description: 'Private subnet IDs'
    Value: !Join [',', [!Ref PrivateSubnet1, !Ref PrivateSubnet2]]
    Export:
      Name: !Sub '${Environment}-Private-Subnets'

  PublicSecurityGroup:
    Description: 'Public security group ID'
    Value: !Ref PublicSecurityGroup
    Export:
      Name: !Sub '${Environment}-Public-SG'

  PrivateSecurityGroup:
    Description: 'Private security group ID'
    Value: !Ref PrivateSecurityGroup
    Export:
      Name: !Sub '${Environment}-Private-SG'

Hướng dẫn Triển khai

  1. Triển khai CloudFormation:
# Triển khai stack
aws cloudformation create-stack \
  --stack-name production-vpc \
  --template-body file://vpc-template.yaml \
  --parameters ParameterKey=Environment,ParameterValue=prod \
  --capabilities CAPABILITY_IAM

# Giám sát triển khai
aws cloudformation describe-stacks \
  --stack-name production-vpc \
  --query 'Stacks[0].StackStatus'
  1. Triển khai CDK:
# Cài đặt dependencies
npm install

# Bootstrap CDK (chỉ lần đầu)
cdk bootstrap

# Triển khai stack
cdk deploy ProductionVpcStack

# Xem outputs
cdk output ProductionVpcStack
  1. Triển khai Terraform:
# Khởi tạo Terraform
terraform init

# Lập kế hoạch triển khai
terraform plan

# Áp dụng cấu hình
terraform apply

# Xem outputs
terraform output

Thực hành Tốt nhất cho IaC

🔒 Bảo mật:

  • Lưu trữ giá trị nhạy cảm trong AWS Secrets Manager hoặc Parameter Store
  • Sử dụng IAM policies với quyền tối thiểu
  • Kích hoạt mã hóa cấp độ tài nguyên khi có thể
  • Triển khai chiến lược tagging phù hợp

💰 Quản lý Chi phí:

  • Sử dụng resource lifecycle policies
  • Triển khai auto-scaling khi phù hợp
  • Giám sát việc sử dụng tài nguyên
  • Thiết lập billing alerts

Xuất sắc Vận hành:

  • Triển khai CI/CD pipelines cho các thay đổi hạ tầng
  • Sử dụng automated testing cho infrastructure code
  • Duy trì các môi trường riêng biệt (dev, staging, prod)
  • Tài liệu hóa quy trình triển khai

🔄 Độ tin cậy:

  • Triển khai multi-AZ deployments
  • Sử dụng health checks và auto-recovery
  • Lập kế hoạch cho các tình huống disaster recovery
  • Kiểm thử quy trình backup và restore

Phương pháp Infrastructure as Code này đảm bảo các triển khai VPC của bạn nhất quán, có thể lặp lại và tuân theo các thực hành tốt nhất của AWS trong khi cho phép mở rộng nhanh chóng và quản lý môi trường.