8
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

TerraformでAmazon API Gatewayを構築する(ゲートウェイのレスポンス&ステージ詳細編)

Last updated at Posted at 2020-07-25

はじめに

以前の記事で、TerraformでAPI Gatewayを構築することを書いてみたが、基本的な部分過ぎて実用的ではなかったので今回はゲートウェイのレスポンスと、ステージの詳細設定をするためのIaCをまとめる。

例によって、Terraformの公式ドキュメントは書き味が薄くて困るので、内容の薄い部分について、AWSの開発者ガイドやCLIのリファレンス等を組み合わせながらまとめる。

文中の画面キャプチャや画面文言は2020年7月25日時点のものなので、今後文言が変わったり、項目の増減があるかもしれないことをご了承いただきたい。

前提条件

  • 以前のTerraform+Amazon API Gatewayの記事の中身がなんとなく理解できる
  • Terraformについてはある程度書き方を理解していて、自力でリファレンスを見ながら書くことができる程度の知識量を期待する

ゲートウェイのレスポンスを設定する

以下の画面のことを指す。

キャプチャ1.png

Terraformのリソースとしては、api_gateway_gateway_responseとなる。

これを見ると、

response_type - (Required) The response type of the associated GatewayResponse.
と書かれていて、いきなり心が折れることになる。
一体画面の項目が何のタイプにマッピングされるのよ……

ということで、TerraformはバックエンドではCLIを動かしていると思われるので、該当のCLIのリファレンスを見てみる。

The response type of the associated GatewayResponse . Valid values are

  • ACCESS_DENIED
    (以下略)

とある。よしよし、これならいけそうだ。

というわけで、画面の日本語とマッピングしていってみる。

マネコン画面の日本語 CLIのパラメータ(Terraformでも使える)
アクセスが拒否されました ACCESS_DENIED
API 設定エラー API_CONFIGURATION_ERROR
オーソライザー設定エラー AUTHORIZER_CONFIGURATION_ERROR
オーソライザーエラー AUTHORIZER_FAILURE
リクエスト本文が不正です BAD_REQUEST_BODY
リクエストパラメータが不正です BAD_REQUEST_PARAMETERS
DEFAULT 4XX DEFAULT_4XX
DEFAULT 5XX DEFAULT_5XX
期限切れのトークン EXPIRED_TOKEN
統合の失敗 INTEGRATION_FAILURE
統合のタイムアウト INTEGRATION_TIMEOUT
無効な API キー INVALID_API_KEY
無効な署名 INVALID_SIGNATURE
認証トークンが見つかりません MISSING_AUTHENTICATION_TOKEN
クォータを超過しました QUOTA_EXCEEDED
リクエストが大きすぎます REQUEST_TOO_LARGE
リソースは存在しません RESOURCE_NOT_FOUND
スロットル済み THROTTLED
権限がありません UNAUTHORIZED(たぶん)
サポートされていないメディアタイプ UNSUPPORTED_MEDIA_TYPE
WAF フィルター WAF_FILTERED

ちなみに、CLIのリファレンスやmanにはWAFフィルター該当するCLI項目がない。
開発者ガイドを見ると、どうやらWAF_FILTEREDらしい。いや、これ日本語おかしいだろ。WAFにフィルターされたとかにしないと分かりにくい……。
※ちなみに、リファレンスやmanには載っていないが、WAF_FILTEREDで設定変更できたので、パラメータとしては有効なようだ。

それでは、よくcurlで間違ったURIとかメソッドを狙って返される

{"message":"Missing Authentication Token"}

を変更してみよう。response_typeMISSING_AUTHENTICATION_TOKENで、デフォルトのHTTPレスポンスコードは403なので、レスポンスコードも変えてみよう(存在しないパスが403 Forbiddenになるのはある意味正しいので、本来はコードまでは変更する必要がないかもしれないが、今回はおためしということで)。

resource "aws_api_gateway_gateway_response" "missing_authentication_token" {
  rest_api_id   = aws_api_gateway_rest_api.my_api.id
  response_type = "MISSING_AUTHENTICATION_TOKEN"
  status_code   = "404"

  response_templates = {
   "application/json" = "{'message':'Resource Not Found'}"
  }

  response_parameters = {
    "gatewayresponse.header.test-header" : "'test'"
  }
}

response_parametersでは、統合レスポンスを使用している場合に、その値をAPIのレスポンスにマッピングすることができる。詳細はAmazon API Gateway API リクエストおよびレスポンスデータマッピングのリファレンスを見ると良い。
今回のケースでは、このレスポンスのパターンになった場合、test-header: testを返す。

では、これをterraform applyした後にアクセスしてみよう。

curl -i https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/user?id=11111\&name=Taro
HTTP/2 404 
date: Sat, 25 Jul 2020 08:57:45 GMT
content-type: application/json
content-length: 32
x-amzn-requestid: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
test-header: test
x-amzn-errortype: MissingAuthenticationTokenException
x-amz-apigw-id: xxxxxxxxxxxxxxxx

{'message':'Resource Not Found'}

といった具合で、設定した通りのレスポンスが返却されるようになった。

ステージの詳細設定

次に以下の画面について。

キャプチャ2.png

主なTerraformのリソースとしてはaws_api_gateway_stageだ。

ここも、マネコン画面に表示されている日本語とTerraformの引数の内容をマッピングしてみる。

設定タブ

設定タブについては、aws_api_gateway_stageの他にapi_gateway_method_settingsが重要になる。
なぜapi_gateway_method_settings?と思うかもしれないが、このリソースは、method_path のプロパティを */* にすることで、stage_name で指定したステージ全体のデフォルトの設定をすることができる。

ステージは以下のリソースのツリーを選択すると、以下のようにラジオボタンが表示される。

キャプチャ9.png

ここで、「このメソッドの上書き」を選択すると、

キャプチャ8.png

のように設定項目が展開され、リソースとメソッド固有の設定で上書きすることができる。

Terraformでも同様に、stage_name に「リソースパス/メソッド」を設定することで */* で設定した内容を上書きすることができる。

キャッシュ設定

マネコン画面の日本語 Terraformの引数
キャッシュ設定 cache_cluster_enabled ※true/falseのboolean

なお、キャッシュ設定は、マネコン画面上ではチェックボックスをONにすると、

キャプチャ3.png

な画面が表示されるが、これを詳細設定するリソースは、aws_api_gateway_method_settingsになる。
aws_api_gateway_stageで設定できるのは、「キャッシュキャパシティー(cache_cluster_size)」までだ。aws_api_gateway_method_settingsでは、以下のようにマッピングされる。

マネコン画面の日本語 Terraformの引数
キャッシュデータを暗号化する cache_data_encrypted ※true/falseのboolean
キャッシュ有効期限 (TTL) cache_ttl_in_seconds
認可が必要 require_authorization_for_cache_control ※true/falseのboolean
未認可リクエストの処理 unauthorized_cache_control_header_strategy

デフォルトのメソッドスロットリング

これも、aws_api_gateway_stageではなくてaws_api_gateway_method_settingsで定義する。

マネコン画面の日本語 Terraformの引数
デフォルトのメソッドスロットリング スロットリングの制御内容は開発者ガイドを参照。Terraformでは、以下の throttling_rate_limit か throttling_burst_limit のいずれかが-1だとチェックOFFになる
レート throttling_rate_limit
バースト throttling_burst_limit

ウェブアプリケーションファイアウォール (WAF)

これはイマイチよく分からなかった……。
aws_wafregional_web_acl_associationのリソースに

API Gateway Association Example

という項があるので、おそらくこのことだろうか。

クライアント証明書

実験できていないので、多分この引数で合っていると思うが、詳細は不明。

マネコン画面の日本語 Terraformの引数
証明書 client_certificate_id

ログ/トレースタブ

CloudWatch 設定

この項目は、aws_api_gateway_stageではなくてaws_api_gateway_method_settingsで定義する。

マネコン画面の日本語 Terraformの引数
CloudWatch ログを有効化 logging_level(OFFで未チェック、ERRORまたはINFOでチェック済み)
詳細 CloudWatch メトリクスを有効化 metrics_enabled

なお、CloudWatch ログを有効化をチェックすると、画面上では以下の項目が表示される。

キャプチャ4.png

マネコン画面の日本語 Terraformの引数
ログレベル logging_level
リクエスト/レスポンスをすべてログ data_trace_enabled ※true/falseのboolean
詳細CloudWatch メトリクスを有効化 metrics_enabled ※true/falseのboolean

また、CloudWatch ログを有効化するためには、以下の「設定」で、CloudWatchLogsの書き込み権を持ったIAMロールを設定する必要がある。

キャプチャ6.png

このため、今回は以下のようにIAMロールを定義する。CloudWatchLogsの書き込みポリシについては、AmazonAPIGatewayPushToCloudWatchLogsを使えとAWSのブログに書いてあった。

################################################################################
# IAM Role for API Gateway Put CloudWatch Logs                                 #
################################################################################
resource "aws_iam_role" "apigateway_putlog" {
  name = local.rest_api_putlog_role_name

  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "apigateway.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
}

resource "aws_iam_role_policy_attachment" "apigateway_putlog" {
  role       = "${aws_iam_role.apigateway_putlog.name}"
  policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs"
}

これを、以下のようにaws_api_gateway_accountで設定すれば良い。

resource "aws_api_gateway_account" "my_api" {
  cloudwatch_role_arn = aws_iam_role.apigateway_putlog.arn
}

で、ここで油断してはならないのは、aws_api_gateway_account はそのままだと aws_api_gateway_method_settings との依存関係がないため、順序性が保証されず、ログ設定がエラーになってしまう。そのため、以下のように依存関係を定義しておく。

resource "aws_api_gateway_method_settings" "all" {
  depends_on = [
    aws_api_gateway_account.my_api,
  ]

  rest_api_id = "${aws_api_gateway_rest_api.my_api.id}"
  stage_name  = "${aws_api_gateway_stage.prod.stage_name}"
  method_path = "*/*"

  settings {
    logging_level = "ERROR"
  }
}

カスタムアクセスのログ設定

この項目はなんか日本語が変な気が…。「の」は要らないような。

マネコン画面の日本語 Terraformの引数
アクセスログの有効化 access_log_settings ※ブロックに以下の項目を記載する

なお、アクセスログの有効化をチェックすると、画面上では以下の項目が表示される。

キャプチャ5.png

これは、aws_api_gateway_stageのリソースのaccess_log_settingsのブロックで定義する。

マネコン画面の日本語 Terraformの引数
Access Log Destination ARN destination_arn
ログの形式 format

ログの形式の出力例は、画面のボタンをポチっと押すか、AWSの開発者ガイドを参照。

この項目を有効にするためには、まずはCloudWatch Logsのリソースを作らなければいけないので、以下のように作成する。

resource "aws_cloudwatch_log_group" "apigateway_accesslog" {
  name = local.rest_api_accesslog_loggroup_name
}

次に、aws_api_gateway_stageに以下のように定義したアクセスログを設定すれば良い。

resource "aws_api_gateway_stage" "prod" {
  stage_name    = "prod"
  rest_api_id   = aws_api_gateway_rest_api.my_api.id
  deployment_id = aws_api_gateway_deployment.dev.id

  access_log_settings {
    destination_arn = aws_cloudwatch_log_group.apigateway_accesslog.arn
    format          = "$context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] \"$context.httpMethod $context.resourcePath $context.protocol\" $context.status $context.responseLength $context.requestId"
  }
}

X-Ray トレース

これはシンプルに設定可能。

マネコン画面の日本語 Terraformの引数
X-Ray トレースの有効化 xray_tracing_enabled

ステージ変数タブ

これはvariablesの引数で渡すことができる。
Terraformのドキュメントでは、

(Optional) A map that defines the stage variables

と書かれているので、渡し方に注意が必要。

SDKの生成/エクスポート/デプロイ履歴/ドキュメント履歴タブ

この辺は設定項目ではなく参照系であるため、特にTerraformに紐づく項目は無い。

Canaryタブ

うーん、これはTerraform未実装な気がする。

CLIのドキュメントには--canary-settingsオプションが存在するが、Terraformでは難しいということだろうか(いずれにしろ、CodeDeployのような便利なCanaryリリースではないので、あまり使えないのだが)。

デプロイについて

API Gatewayのリソースについては、以下のようにデプロイを定義する。
triggersは、「このリソースが変更されたら再デプロイする」という機能らしい。
詳細は、公式のNotesを参照。
lifecycleは、スキマを作らないようにするための施策だ。

resource "aws_api_gateway_deployment" "dev" {
  rest_api_id = aws_api_gateway_rest_api.my_api.id
  stage_name  = "dev"

  triggers = {
    redeployment = sha1(join(",", list(
      jsonencode(module.get_user),
      jsonencode(module.put_user),
      jsonencode(aws_api_gateway_gateway_response.missing_authentication_token),
    )))
  }

  lifecycle {
    create_before_destroy = true
  }
}

ただ、これだけだと、devにデプロイした機能がprodまで伝播してくれない。
うーむ、prod側にも設定を入れるべきなのだろうか。それとも、そこは別契機でデプロイするということか。

8
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?