Techfirm Cloud Architect Blog

テックファーム株式会社クラウドインフラグループのブログ

IaCでREST API(API Gateway)を構成する要素

最近はAPI Gateway+Lambdaによるサーバレス構成を選択することも増えてきています。 その時、インフラ構築はTerraformをよく利用していますが、APIの開発はServerlessFrameworkが使われたりします。

どこまでTerraformで構築し、どこからServerlessFrameworkで構築するか? API Gatewayにどのような設定が必要か? これらの設計をするためには、TerraformやCloudFormationでどのようにAPI Gatewayを設定するか知っている必要があります。 (ServerlessFrameworkのデプロイは、裏でCloudFormationのスタックを作成してAWS環境へ反映しています)

今回は、API Gatewayを構築するためのリソースにどのようなものがあるかご紹介します。

REST APIを設定するリソース一覧

API Gateway全体やREST APIの設定に関わるリソースをTerraformの設定をベースに一覧化しました。横にも長い表なのでご注意ください。

Terraformリソース 必須参照先リソース 任意参照先リソース CloudFormationリソース
aws_api_gateway_account (IAM Role) AWS::ApiGateway::Account
aws_api_gateway_domain_name (ACM証明書) AWS::ApiGateway::DomainName
aws_api_gateway_base_path_mapping domain_name
rest_api
stage AWS::ApiGateway::BasePathMapping
aws_api_gateway_client_certificate AWS::ApiGateway::ClientCertificate
aws_api_gateway_vpc_link (ELB) AWS::ApiGateway::VpcLink
aws_api_gateway_rest_api (VPCEndpoint) AWS::ApiGateway::RestApi
aws_api_gateway_rest_api_policy rest_api -(RestApi内のプロパティ)
aws_api_gateway_resource rest_api
(resource)
AWS::ApiGateway::Resource
aws_api_gateway_method rest_api
(resource)
authorizer
request_validator
AWS::ApiGateway::Method
aws_api_gateway_integration rest_api
(resource)
method
(Lambda)
vpc_link
-(Method内のプロパティ)
aws_api_gateway_method_response rest_api
(resource)
method
-(Method内のプロパティ)
aws_api_gateway_integration_response rest_api
(resource)
method
-(Method内のプロパティ)
aws_api_gateway_deployment rest_api AWS::ApiGateway::Deployment
aws_api_gateway_stage rest_api
deployment
client_certificate
documentation_version
(Logs)
AWS::ApiGateway::Stage
aws_api_gateway_method_settings rest_api
stage
-(Stage内のプロパティ)
aws_api_gateway_model rest_api AWS::ApiGateway::Model
aws_api_gateway_documentation_part rest_api AWS::ApiGateway::DocumentationPart
aws_api_gateway_documentation_version rest_api AWS::ApiGateway::DocumentationVersion
aws_api_gateway_authorizer rest_api (Lambda)
(CognitoUserPool)
AWS::ApiGateway::Authorizer
aws_api_gateway_gateway_response rest_api AWS::ApiGateway::GatewayResponse
aws_api_gateway_request_validator rest_api AWS::ApiGateway::RequestValidator
aws_api_gateway_usage_plan rest_api
stage
AWS::ApiGateway::UsagePlan
aws_api_gateway_api_key AWS::ApiGateway::ApiKey
aws_api_gateway_usage_plan_key usage_plan,api_key AWS::ApiGateway::UsagePlanKey

CloudFormationのリソースはリソースタイプの名前から対応するものを推測したものになります。
ここからはTerraformのリソースを例に説明してますが、CloudFormationも同じような構成になります。詳細は公式ドキュメントをご確認ください。

上記で、必須参照先リソースは他のリソースを参照する必須項目です。先にそのリソースを定義しておく必要があります。
これを見ると、どの設定がREST APIに紐づき、どの設定が単一のREST APIから切り離されているのかが分かります。
たとえば、aws_api_gateway_authorizerはREST APIごとに作成しますが、aws_api_gateway_domain_nameはREST APIとは独立して作成します。

任意参照先リソースは他のリソースを参照する必須でない設定項目です。
たとえば、aws_api_gateway_methodaws_api_gateway_authorizeraws_api_gateway_request_validatorを設定可能なことが分かります。

REST APIの作成とデプロイ

概要

ユーザがAPIを呼び出せるするようにするためには、REST APIを作成してデプロイする必要があります。
AWSコンソールやAWS CLIから構築する場合はAWSの以下ページが参考になるかと思います。


ここでは、以下の作業を行うためにどのリソースを利用するか説明します。

  1. REST APIを作成する(REST API定義)
  2. APIのパスと動作を定義する(リソース定義)
  3. 呼び出し可能な状態にする(ステージへデプロイ)

これらの設定をIaCで行うための主なリソースは以下になります。

APIGatewayデプロイTerraform構成

一覧にすると以下の通りです。

No Terraformリソース 必須参照先リソース 任意参照先リソース
aws_api_gateway_rest_api (VPCEndpoint)
aws_api_gateway_resource rest_api
(resource)
aws_api_gateway_method rest_api
(resource)
authorizer
request_validator
aws_api_gateway_deployment rest_api
aws_api_gateway_stage rest_api
deployment
client_certificate
documentation_version
(Logs)

ここで(resource)と括弧が付いているのは、場合によってaws_api_gateway_resourceではないリソースを参照するためです(後述)。

次から詳しく見ていきます。

① REST APIを作成

まず始めにREST APIを作成します。これはaws_api_gateway_rest_apiリソースになります。
多くのリソースがaws_api_gateway_rest_apiリソースの下に付きます。

resource "aws_api_gateway_rest_api" "test_api" {
  name        = "test-api"
}

② リソース定義(APIのパスと動作を定義)

実際にどのようなリクエストに対してどのような動作をするか、REST APIに定義します。
これにはaws_api_gateway_resourceaws_api_gateway_methodを中心に使います。 aws_api_gateway_resourceでURLパスを定義し、そのURLの各HTTPメソッドに対してどのような動作をするかはaws_api_gateway_methodで定義します。

たとえば、/test/apitest1へのGETリクエストはTerraformで以下のように定義します。

# /testの定義
resource "aws_api_gateway_resource" "test" {
  path_part   = "test"
  rest_api_id = aws_api_gateway_rest_api.test_api.id
  parent_id   = aws_api_gateway_rest_api.test_api.root_resource_id
}
# /test/apitest1の定義
resource "aws_api_gateway_resource" "test_apitest1" {
  path_part   = "apitest1"
  rest_api_id = aws_api_gateway_rest_api.test_api.id
  parent_id   = aws_api_gateway_resource.test.id
}
# /test/apitest1へのGETリクエスト
resource "aws_api_gateway_method" "test_apitest1_get" {
  rest_api_id   = aws_api_gateway_rest_api.test_api.id
  resource_id   = aws_api_gateway_resource.test_apitest1.id
  http_method   = "GET"
  authorization = "NONE"
}
# /test/apitest1のGETリクエストへの実際の動作
resource "aws_api_gateway_integration" "test_apitest1_get" {
  rest_api_id   = aws_api_gateway_method.test_apitest1_get.rest_api_id
  resource_id   = aws_api_gateway_method.test_apitest1_get.resource_id
  http_method   = aws_api_gateway_method.test_apitest1_get.http_method
  type                 = "MOCK"
  .... 実際の各種設定 ....
}

最後のaws_api_gateway_integrationリソースは先の一覧には記載しませんでしたが、APIメソッドの実際の動作に関する設定です。

リソース(URIパス)を定義するaws_api_gateway_resourceparent_idで親のリソースを指定するのが必須になります。
ルート(/)のリソースはREST APIを作成した時に定義され、aws_api_gateway_rest_apiroot_resource_id属性として取得できます。

この時点ではAPIの設計書ができただけのような状態で、実際にアクセス可能なエンドポイントは作成されていません。

③ ステージへデプロイ

実際にステージへデプロイすることで、②で定義したAPIはアクセス可能な状態になります。
AWSコンソール上でAPIのデプロイをしようとすると『API がデプロイされるステージを選択します。』と表示されてステージの選択または新しいステージ名の入力が必須となっています。
しかし、本当はステージを選択しなくてもデプロイメントを作成できます。(ユーザからアクセス可能な状態にするという意味ではステージ選択は必須です)

新規のデプロイに関するAPIを見ると、CreateDeploymentCreateStageがあります。
ここで、CreateDeploymentにはstageNameという項目がありますが必須ではありません。
CreateDeploymentstageNameを指定してステージを作成・紐づけすることも、ステージを選択せずに後から別にステージを作成・紐づけることもできます。
CreateStagedeploymentIdが必須なので、デプロイメントより先にステージを作成することはできません)

APIGatewayデプロイAPI

これらの操作を、Terraformではaws_api_gateway_deploymentリソースとaws_api_gateway_stageリソースで実施できます。
CloudFormationだとAWS::ApiGateway::DeploymentAWS::ApiGateway::Stageのはずです。
AWS::ApiGateway::Stageのドキュメントを見るとStageNameDeploymentIdが何でRequired: Noなのか分かりませんが)

Terraformではaws_api_gateway_deploymentリソースのstage_nameを使わずaws_api_gateway_stageリソースを使うことが推奨されています。
更新時にaws_api_gateway_deploymentリソースを作り直す過程で、一時的にステージが消えてしまうことを避けるためのようです。
以下はTerraformでの設定例です。

# 非推奨(stage_name利用)
resource "aws_api_gateway_deployment" "test_api_dev1" {
  rest_api_id = aws_api_gateway_rest_api.test_api.id
  stage_name  = "dev1" # デプロイメントだけでステージを作成する
  triggers = {
    deploy_trigger    = var.deploy_trigger
    test_apitest1_get = aws_api_gateway_integration.test_apitest1_get.id
  }
}
# 通常設定方法
resource "aws_api_gateway_deployment" "test_api_dev2" {
  rest_api_id = aws_api_gateway_rest_api.test_api.id
  triggers = {
    deploy_trigger    = var.deploy_trigger
    test_apitest1_get = aws_api_gateway_integration.test_apitest1_get.id
  }
  lifecycle {
    create_before_destroy = true
  }
}
resource "aws_api_gateway_stage" "test_api_dev2" {
  deployment_id = aws_api_gateway_deployment.test_api_dev2.id
  rest_api_id   = aws_api_gateway_rest_api.test_api.id
  stage_name    = "dev2"
}

aws_api_gateway_deploymentリソースのtriggersはTerraform固有の項目です。
ここの値を更新することで、デプロイメントを更新させることができます。

また、URLはinvoke_urlで取得可能です。ステージを作ったリソースのinvoke_urlを参照します。

output "apigw_test_api_dev1_url" {
  value = aws_api_gateway_deployment.test_api_dev1.invoke_url
}
output "apigw_test_api_dev2_url" {
  value = aws_api_gateway_stage.test_api_dev2.invoke_url
}

カスタムドメインの設定

カスタムドメインは、Terraformでは以下のリソースで設定可能です。

Terraformリソース 必須参照先リソース 任意参照先リソース
aws_api_gateway_domain_name (ACM証明書)
aws_api_gateway_base_path_mapping domain_name
rest_api
stage

aws_api_gateway_domain_nameでドメイン名やサーバ証明書の設定を行います。
このリソース自体はREST APIとは独立して存在しています。

カスタムドメインと各APIの関連付けはaws_api_gateway_base_path_mappingで行います。
カスタムドメインに対して、どのAPIまたはAPIのステージに接続するかを設定可能です。
これにはbase_pathという設定項目があり、1つのカスタムドメインに対して複数のAPIやステージを設定できます。 たとえば、以下のように1つのカスタムドメインでURLごとに違うAPIのバックエンドを設定可能です。

  • https://<カスタムドメイン>/api2REST_API_2のステージProduction
  • https://<カスタムドメイン>/devREST_API_1のステージDevelop
  • https://<カスタムドメイン>/REST_API_1のステージProduction

ログ出力設定

API Gatewayには以下の2種類のログがあります。

  • アクセスログ
  • 実行ログ

これらは、以下のリソースに設定項目があります。

Terraformリソース 必須参照先リソース CloudFormationリソース
aws_api_gateway_account AWS::ApiGateway::Account
aws_api_gateway_stage rest_api
deployment
AWS::ApiGateway::Stage
aws_api_gateway_method_settings rest_api
stage
-(Stage内のプロパティ)

アクセスログの設定はaws_api_gateway_stageで行います。(aws_api_gateway_deploymentstage_nameでステージを作成していると設定できません)
アクセスログは出力先とログ形式をステージごとに設定するだけです。
AWSコンソール上では、ステージのステージ名を選択した状態でログ/トレースタブにあるカスタムアクセスログの記録という項目になります。

少し分かりにくいのは、実行ログの設定です。 AWSコンソール上で、実行ログの設定はステージのステージ名を選択した状態でログ/トレースタブにあるCloudWatch ログです。
また、ステージの下にあるメソッドを選択した時の選択でこのメソッドの上書きを選ぶとメソッドごとに設定できます。

Terraformでの実行ログの設定はaws_api_gateway_method_settingsで行いますが、CloudFormationではAWS::ApiGateway::Stage内のプロパティになります。
実行ログはログレベルとデータトレースログを出力するかどうかの設定になります。

TerraformやCloudFormationでも、実行ログはメソッドごとに設定できます。逆に、ステージ全体の設定という特別な項目はありません。
全体の設定をする時は、Terraformではmethod_path*/*とし、CloudFormationではResourcePath/*HttpMethodには*を設定します。 また、このメソッドの設定はログだけでなくキャッシュやスロットリングの設定も同時に行えます。

最後に、aws_api_gateway_account(CloudFormationではAWS::ApiGateway::Account)についてです。
これはAWSアカウント+リージョンごとに1つしか作成しないリソースで、CloudWatch等への出力を行うためのIAMロールを設定します。
すべてのAPI Gatewayは、同じリージョンに設定された同じロールを使ってログ出力等を行います。

終わりに

API GatewayをTerraformとCloudFormationで設定するためのリソースをいくつか紹介しました。
冒頭に書いたように、実際にはIaCツールでAPI Gatewayをすべて構築することは少ないかと思います。
IaCの設定項目を通してAPI Gatewayへの理解を深めるとともに、何をIaCツールで定義して何を開発フレームワークで定義するのか、考えるきっかけになればと思います。