AWSサービスの配置場所について理解する

# 概要
各AWSサービスは特定の配置場所を持ち，主に以下の3つに分類される．
- グローバル
- リージョン
- アベイラビリティゾーン（AZ）

https://docs.aws.amazon.com/ja_jp/whitepapers/latest/aws-fault-isolation-boundaries/aws-service-types.html

例えばEC2はAZに属するサービスであるのに対し，S3はリージョンに属するサービスであるため，両者間の通信は基本的にインターネットを経由することになる．
この事実を無視した設計では，本来プライベートなネットワーク内で情報をやり取りすべきところを，誤ってインターネットを経由して情報をやり取りしてしまう可能性がある．
このような事態を避けるためにも，AWS環境を設計・構築する上でサービスの配置場所を正しく理解することは極めて重要である．

本記事では各サービスの配置場所についての基礎をまとめ，最後にEC2からS3へセキュアに通信するデモをおこなう．


# グローバル
世界中に展開されている物理的なデータセンター全体のこと．
各データセンター間はAWSの専用ネットワーク回線で接続されており，安定した品質が担保されている．

代表的なサービス
- IAM
- WAF
- CloudFront
- Route53
- Organizations

![global.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/931058/ae6a9c98-b243-17b6-d93d-a0cafd182081.png)


# リージョン
リージョンとは複数のデータセンターから成る物理的なロケーションのこと．
2024年1月時点で33の地理的リージョンが存在する．

各リージョンで利用可能なAWSサービスが異なることや，地理的に離れたリージョンへの通信には時間がかかることを考慮して，適切なリージョンを選定することが重要になる．

代表的なサービス
- VPC
- S3 [^1]
- DynamoDB
- Lambda
- CloudFormation

![region.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/931058/679bd4c0-238b-dbbb-5648-afb84e1cd5f2.png)


# アベイラビリティゾーン(AZ)
AZとは1つのリージョン内で物理的に分離されたデータセンターのこと．
2024年1月時点で105のAZが存在する．

同じリージョン内の各AZは独立した電力やネットワークを備えているため，1つのAZに障害が発生した場合でもシステムやサービスの可用性を確保できることが一番の特徴といえる．

代表的なサービス
- EC2
- EBS
- RDS
- ELB
- Redshift

![az.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/931058/2b6103bb-feab-eb24-7c43-edbf3495f207.png)


# まとめ
- グローバル：世界中に展開されている物理的なデータセンター全体
- リージョン：複数のデータセンターから成る物理的なロケーション
- アベイラビリティゾーン：1つのリージョン内で物理的に分離されたデータセンター

これら場所の特徴と属するサービスを理解し，ベストプラクティスに従った設計・構築を心掛けたい．

![all.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/931058/645b6def-0c4e-8d01-77f6-16cc86d64fa1.png)


# デモ
デモの内容
- プライベートなEC2からS3にアクセスする．
- インターネットを経由しないためにVPCエンドポイントを使用する．
- EC2へのアクセスはSession Managerを使用する．
- リソースの作成はCloudFormationを使用する

![demo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/931058/15e05177-83e6-cf0f-76ec-17debc1b177a.png)

CloudFormationテンプレート
- 今回は配置場所毎にテンプレートを分けた．

```yml:global.yml
AWSTemplateFormatVersion: 2010-09-09
Description: Global service

Resources: 
# ------------------------------------------------------------#
# EC2にアタッチするIAMロールを作成
# ------------------------------------------------------------#
  ec2Role:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument: 
        Version: 2012-10-17
        Statement: 
          - Effect: Allow
            Action: 
              - sts:AssumeRole
            Principal:
              Service:
                - ec2.amazonaws.com
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
      RoleName: ec2Role

  iamInstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: /
      Roles:
        - !Ref ec2Role

Outputs:
  iamInstanceProfile:
    Value: !Ref iamInstanceProfile
    Export:
      Name: iamInstanceProfile
```

```yml:region.yml
AWSTemplateFormatVersion: 2010-09-09
Description: Region service

Parameters:
  s3BucketName:
    Type: String
    Default: qiita20240127

Resources:
# ------------------------------------------------------------#
# VPC, プライベートサブネット, ルートテーブルを作成する
# ------------------------------------------------------------#
  myVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/21
      EnableDnsHostnames: true
      EnableDnsSupport: true
      Tags:
        - Key: Nmae
          Value: myVPC
  privateSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: "ap-northeast-1a"
      VpcId: !Ref myVPC
      CidrBlock: 10.0.1.0/24
      Tags:
        - Key: Name
          Value: privateSubnet
  privateRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref myVPC
      Tags:
        - Key: Name
          Value: privateRouteTable
  PriAssociateRouteTable:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref privateRouteTable
      SubnetId: !Ref privateSubnet
# ------------------------------------------------------------#
# SSM用に3つのVPCエンドポイントを作成する
# ------------------------------------------------------------#  
  endpointSG:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: endpointSG
      GroupDescription: allow https
      VpcId: !Ref myVPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: endpointSG
  endpointSSM:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref endpointSG
      ServiceName: com.amazonaws.ap-northeast-1.ssm
      SubnetIds:
        - !Ref privateSubnet
      VpcEndpointType: Interface
      VpcId: !Ref myVPC
  endpointSSMMessages:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref endpointSG
      ServiceName: com.amazonaws.ap-northeast-1.ssmmessages
      SubnetIds:
        - !Ref privateSubnet
      VpcEndpointType: Interface
      VpcId: !Ref myVPC 
  endpointEC2Messages:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref endpointSG
      ServiceName: com.amazonaws.ap-northeast-1.ec2messages
      SubnetIds:
        - !Ref privateSubnet
      VpcEndpointType: Interface
      VpcId: !Ref myVPC
# ------------------------------------------------------------#
# S3用のVPCエンドポイントとバケットを作成
# ------------------------------------------------------------#
  endpointS3:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      RouteTableIds:
        - !Ref privateRouteTable
      ServiceName: com.amazonaws.ap-northeast-1.s3
      VpcEndpointType: Gateway
      VpcId: !Ref myVPC
  s3Bucket:
    Type: AWS::S3::Bucket
    Properties: 
      AccessControl: Private
      BucketName: !Ref s3BucketName
      Tags:
        - Key: Name
          Value: s3Bucket

Outputs:
  privateSubnet:
    Value: !Ref privateSubnet
    Export: 
      Name: privateSubnet
```

```yml:az.yml
AWSTemplateFormatVersion: 2010-09-09
Description: AZ service

Resources: 
# ------------------------------------------------------------#
# EC2インスタンスを作成
# ------------------------------------------------------------#
  myEC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: ami-0076451230a62ad66
      InstanceType: t2.micro
      IamInstanceProfile: !ImportValue iamInstanceProfile
      SubnetId: !ImportValue privateSubnet
      Tags:
        - Key: Name
          Value: myEC2
```

動作確認
- CloudFormationで3つのスタックを作成
- EC2インスタンスにセッションマネージャーで接続
- `aws s3 ls`コマンドでバケットを取得できれば成功!!

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/931058/0f4d0ba4-4dc0-4c52-26b0-bc7e617a918a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/931058/3f61479d-fde5-dd71-7a03-6633d45b75d9.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/931058/52ea79e3-e5f8-4f5d-b7bb-e2a79b4ffbf6.png)

[^1]: S3はサービスとしてはグローバルサービスだが，リソース（バケット）はリージョンに存在する．ストレージという性質上，データの保存領域という実体を用意する必要があり，それはバケットという形でリージョン内の複数のAZに跨って存在する．