<Terraform学習>AWSにS3エンドポイントを作成してみる

# 前提条件
学習のため細かく分けて作成していきます。  
プライベートサブネット用にS3エンドポイントを作成し、ルートテーブルにルートを追加します。

作成先のVPC、ルートテーブルは下記にて作成した環境を使用いたします。

[AWSにVPCを作成してみる](https://qiita.com/TTG/items/59f0579383c705870ee8)
[AWSにルートテーブルとInternetGatewayを作成してみる](https://qiita.com/TTG/items/4d682fcf51b55f9562e0)

# バージョン情報
- Terraform: `Terraform v1.10.5`
- AWS CLI: `aws-cli/2.24.11 Python/3.12.9 Windows/11 exe/AMD64`

# Terraform ファイルの作成
## `04_S3endpoint.tf`
以下のTerraformファイルを作成しました。

```terraform
provider "aws" {
    region = "us-west-2"
}

#既存のVPCを参照する
data "aws_vpc" "terraform-vpc" {
    filter {
        name = "tag:Name"
        values = ["terraform"]
    }
}
#既存のルートテーブルを参照する
data "aws_route_table" "terraform-private-routetable" {
    filter {
        name = "tag:Name"
        values = ["terraform-private-routetable"]
    }
}

resource "aws_vpc_endpoint" "terraform-s3endpoint" {
    vpc_id           = data.aws_vpc.terraform-vpc.id
    service_name     = "com.amazonaws.us-west-2.s3"
    vpc_endpoint_type = "Gateway"

    # 既存のルートテーブルへルートを追加する
    # route_table_ids はリスト型にする必要がある
    route_table_ids  = [data.aws_route_table.terraform-private-routetable.id]

    tags = {
        Name = "terraform-s3endpoint"
    }
}
```

# Terraform の実行

## `terraform init`
Terraformを初期化します。

```powershell
PS C:\work\Terraform\01_basic\04-S3endopoint> terraform init
```
出力結果（抜粋）:
```log
Terraform has been successfully initialized!
```

## `terraform plan`
Terraformの適用計画を確認します。

```powershell
PS C:\work\Terraform\01_basic\04-S3endopoint> terraform plan
```
<details>
<summary>
出力結果は長いので折りたたみます。見たい方はこちらを展開してください。
</summary>



```log
data.aws_route_table.terraform-private-routetable: Reading...
data.aws_vpc.terraform-vpc: Reading...
data.aws_route_table.terraform-private-routetable: Read complete after 1s [id=rtb-xxxxxxxxxxxxxxx]
data.aws_vpc.terraform-vpc: Read complete after 2s [id=vpc-xxxxxxxxxxxxxxxx]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the
following symbols:
  + create

Terraform will perform the following actions:

  # aws_vpc_endpoint.terraform-s3endpoint will be created
  + resource "aws_vpc_endpoint" "terraform-s3endpoint" {
      + arn                   = (known after apply)
      + cidr_blocks           = (known after apply)
      + dns_entry             = (known after apply)
      + id                    = (known after apply)
      + ip_address_type       = (known after apply)
      + network_interface_ids = (known after apply)
      + owner_id              = (known after apply)
      + policy                = (known after apply)
      + prefix_list_id        = (known after apply)
      + private_dns_enabled   = (known after apply)
      + requester_managed     = (known after apply)
      + route_table_ids       = [
          + "rtb-xxxxxxxxxxxxxxxxx",
        ]
      + security_group_ids    = (known after apply)
      + service_name          = "com.amazonaws.us-west-2.s3"
      + service_region        = (known after apply)
      + state                 = (known after apply)
      + subnet_ids            = (known after apply)
      + tags                  = {
          + "Name" = "terraform-s3endpoint"
        }
      + tags_all              = {
          + "Name" = "terraform-s3endpoint"
        }
      + vpc_endpoint_type     = "Gateway"
      + vpc_id                = "vpc-xxxxxxxxxxxxxxxx"

      + dns_options (known after apply)

      + subnet_configuration (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if
you run "terraform apply" now.
```
</details>

## `terraform apply`
S3エンドポイントを作成します。

```powershell
PS C:\work\Terraform\01_basic\04-S3endopoint> terraform apply
```
<details>
<summary>
出力結果は長いので折りたたみます。見たい方はこちらを展開してください。
</summary>

```log
data.aws_vpc.terraform-vpc: Reading...
data.aws_route_table.terraform-private-routetable: Reading...
data.aws_route_table.terraform-private-routetable: Read complete after 1s [id=rtb-xxxxxxxxxxxxxxx]
data.aws_vpc.terraform-vpc: Read complete after 2s [id=vpc-xxxxxxxxxxxxxxx]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the
following symbols:
  + create

Terraform will perform the following actions:

  # aws_vpc_endpoint.terraform-s3endpoint will be created
  + resource "aws_vpc_endpoint" "terraform-s3endpoint" {
      + arn                   = (known after apply)
      + cidr_blocks           = (known after apply)
      + dns_entry             = (known after apply)
      + id                    = (known after apply)
      + ip_address_type       = (known after apply)
      + network_interface_ids = (known after apply)
      + owner_id              = (known after apply)
      + policy                = (known after apply)
      + prefix_list_id        = (known after apply)
      + private_dns_enabled   = (known after apply)
      + requester_managed     = (known after apply)
      + route_table_ids       = [
          + "rtb-xxxxxxxxxxxxxxx",
        ]
      + security_group_ids    = (known after apply)
      + service_name          = "com.amazonaws.us-west-2.s3"
      + service_region        = (known after apply)
      + state                 = (known after apply)
      + subnet_ids            = (known after apply)
      + tags                  = {
          + "Name" = "terraform-s3endpoint"
        }
      + tags_all              = {
          + "Name" = "terraform-s3endpoint"
        }
      + vpc_endpoint_type     = "Gateway"
      + vpc_id                = "vpc-xxxxxxxxxxxxxxx"

      + dns_options (known after apply)

      + subnet_configuration (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_vpc_endpoint.terraform-s3endpoint: Creating...
aws_vpc_endpoint.terraform-s3endpoint: Creation complete after 6s [id=vpce-xxxxxxxxxxxxxxx]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
```

</details>

# 作成したAWSリソース情報

- S3エンドポイント
- privateサブネット用ルートテーブルへルート追加

これでPrivateサブネットにEC2を作成したときにS3エンドポイントへ接続できるようになります。

# VPC エンドポイントのパラメータ一覧
<details><summary>パラメータ一覧</summary>
参照：https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_endpoint


| パラメータ名 | 説明 |
|-------------|------|
| `vpc_id` | (必須) VPC エンドポイントが使用される VPC の ID。 |
| `auto_accept` | (オプション) VPC エンドポイントを自動承認するかどうか。同じ AWS アカウント内のサービスにのみ適用される。 |
| `policy` | (オプション) エンドポイントにアタッチするポリシー。JSON 形式で指定する。デフォルトはフルアクセス。 |
| `private_dns_enabled` | (オプション) `Interface` タイプのエンドポイントにプライベートホストゾーンを関連付けるかどうか。デフォルトは `false`。 |
| `dns_options` | (オプション) エンドポイントの DNS オプション。 |
| `ip_address_type` | (オプション) エンドポイントの IP アドレスの種類。有効な値は `ipv4`, `dualstack`, `ipv6`。 |
| `resource_configuration_arn` | (オプション) VPC エンドポイントを接続するリソースの ARN。 |
| `route_table_ids` | (オプション) ルートテーブルの ID のリスト。`Gateway` タイプのエンドポイントに適用される。 |
| `service_name` | (オプション) AWS サービスの名前。例: `com.amazonaws.<region>.<service>`。 |
| `service_network_arn` | (オプション) サービスネットワークの ARN。 |
| `service_region` | (オプション) VPC エンドポイントが接続する AWS サービスのリージョン。 |
| `subnet_configuration` | (オプション) エンドポイントのサブネット設定。 |
| `subnet_ids` | (オプション) エンドポイントのネットワークインターフェースを作成するサブネットの ID。`Interface` および `GatewayLoadBalancer` タイプに適用される。 |
| `security_group_ids` | (オプション) `Interface` タイプのエンドポイントに関連付けるセキュリティグループの ID。デフォルトでは VPC のデフォルトセキュリティグループが関連付けられる。 |
| `tags` | (オプション) エンドポイントに割り当てるタグのマップ。 |
| `vpc_endpoint_type` | (オプション) エンドポイントのタイプ。`Gateway`, `GatewayLoadBalancer`, `Interface`, `Resource`, `ServiceNetwork` のいずれか。デフォルトは `Gateway`。 |

## **DNS オプション (`dns_options`)**
| パラメータ名 | 説明 |
|-------------|------|
| `dns_record_ip_type` | (オプション) エンドポイントの DNS レコードの種類。有効な値は `ipv4`, `dualstack`, `service-defined`, `ipv6`。 |
| `private_dns_only_for_inbound_resolver_endpoint` | (オプション) VPC 内からのトラフィックを `Gateway` エンドポイントへ、オンプレミスからのトラフィックを `Interface` エンドポイントへルーティングする。 |

## **サブネット設定 (`subnet_configuration`)**
| パラメータ名 | 説明 |
|-------------|------|
| `ipv4` | (オプション) エンドポイントのネットワークインターフェースに割り当てる IPv4 アドレス。 |
| `ipv6` | (オプション) エンドポイントのネットワークインターフェースに割り当てる IPv6 アドレス。 |
| `subnet` | (オプション) エンドポイントを作成するサブネットの ID。`subnet_ids` と一致する必要がある。 |

## **タイムアウト設定**
| 操作 | デフォルト時間 |
|------|--------------|
| `create` | 10 分 |
| `update` | 10 分 |
| `delete` | 10 分 |

## **エクスポートされる属性**
| 属性名 | 説明 |
|--------|------|
| `id` | VPC エンドポイントの ID。 |
| `arn` | VPC エンドポイントの ARN。 |
| `cidr_blocks` | `Gateway` タイプのエンドポイントで公開される CIDR ブロックのリスト。 |
| `dns_entry` | `Interface` タイプのエンドポイントの DNS エントリ情報。 |
| `network_interface_ids` | `Interface` タイプのエンドポイントに関連付けられたネットワークインターフェースの ID。 |
| `owner_id` | VPC エンドポイントを所有する AWS アカウントの ID。 |
| `prefix_list_id` | `Gateway` タイプのエンドポイントのプレフィックスリスト ID。 |
| `requester_managed` | VPC エンドポイントがサービスによって管理されているかどうか (`true` または `false`)。 |
| `state` | VPC エンドポイントの状態。 |
| `tags_all` | エンドポイントに割り当てられたタグのマップ（プロバイダーのデフォルトタグを含む）。 |

## **DNS エントリ (`dns_entry`)**
| 属性名 | 説明 |
|--------|------|
| `dns_name` | DNS 名。 |
| `hosted_zone_id` | プライベートホストゾーンの ID。 |
</details>



# 気づいたこと・勘違いしていたこと

1. `route_table_ids` はリスト型で記述すること
Terraformの`aws_vpc_endpoint`リソースで`route_table_ids`を指定する際、リスト型にする必要があります。
`data`ブロックはこれまでにVPCを参照するときに使用していたので、同じように記述したところエラーになりました。

**間違った記述例**
```terraform
route_table_ids = data.aws_route_table.terraform-private-routetable.id
```
この記述ではエラーが発生しました。
```log
Error: Incorrect attribute value type
│   Inappropriate value for attribute "route_table_ids": set of string required.
```

## まとめ

- 既存のプライベートサブネット用のルートテーブルにS3エンドポイントを作成しました。
- `route_table_ids` はリスト型で指定する必要があることを学びました。

次回は **ルートテーブルとサブネットを関連付け** を行います。