LoginSignup
0

More than 3 years have passed since last update.

TerraformでAmazon API Gatewayを構築する(アクセスログ詳細編)

Posted at

はじめに

API Gateway+Terraform記事第3弾。
前回の記事でカスタムアクセスログについてさらっと触れたが、今回はログフォーマット関連でもう少し掘り下げてみる。

アクセスログに出せるもの

以下のドキュメントを参照しよう。

【AWS公式】API Gateway での REST API の CloudWatch ログ記録の設定
【AWS公式】API Gateway マッピングテンプレートとアクセスのログ記録の変数リファレンス

API Gatewayのドキュメントは結構散らかっていて、後者のページではあたかも色々なものをログに出せそうに見えるが、実際には前者のページに記載の通り、$context 変数のものだけしか出力できない。

例えば、ヘッダやパスパラメータやBodyで指定されるようなパラメータについては、出力できないため、あくまでもHTTPサーバとしてのアクセスログといった位置づけだろう。
※統合リクエストでAWSサービスとも統合できるのに、アプリケーションサーバ的なログが出せないのはちょっといただけないのだが……

ログ出力の方法

前回の記事にも書いた通り、カスタムアクセスログについては、Terraformの aws_api_gateway_stageaccess_log_settings を指定してあげることで出力可能だ。CloudWatch Logsの作成や、ログ書き込みのためのロール設定等は前回を参照してほしい。

なお、ログフォーマットには、CLF、JSON、XML、CSVが設定可能だが、CloudWatch Logs Insightsで使えることを考えると、JSONが良いだろうということで、今回はJSONで書いている(後でJSON→CSV変換であれば色々な手段で簡単にできるし)。

今回の記事では、簡単な Mock 統合を作成し、そこの prod ステージに対して以下の設定をした。

resource "aws_api_gateway_stage" "prod" {
  stage_name    = "prod"
  rest_api_id   = aws_api_gateway_rest_api.my.id
  deployment_id = aws_api_gateway_deployment.dev_to_prod.id

  access_log_settings {
    destination_arn = aws_cloudwatch_log_group.apigateway_accesslog.arn
    format          = replace(file("${path.module}/logformat.json"), "\n", "")
  }
}

format には直接書き込んでも良いが、色々と書きだしたい場合はファイルを分けた方が良いだろう。
replace() 関数を入れているのは、JSONを複数行にするとエラーになるためだ(API Gatewayの仕様)。
ファイルに '\' を入れても良いのだが、可読性を上げるために、ファイルは普通のJSON形式にして、Terraformに食わせるときに変換している。

実際の出力

実際に設定した際の出力を確認していってみよう。
なお、全部一気にまとめて出力しようとしたら、ログフォーマット設定は最大で 3,000Byte までしか指定できないらしいので、まとめて出力することはできないようだ。実運用する際は、必要なものをピックアップしよう。

なお、値が "-"のものは、今回の単純な Mock のAPIでは使っていない機能によるものなので、実際には利用シーンに合わせた値が設定されるはずである。

例に記載されているもの

フォーマットでの指定

{
  "requestId": "$context.requestId",
  "ip": "$context.identity.sourceIp",
  "caller": "$context.identity.caller",
  "user": "$context.identity.user",
  "requestTime": "$context.requestTime",
  "httpMethod": "$context.httpMethod",
  "resourcePath": "$context.resourcePath",
  "status": "$context.status",
  "protocol": "$context.protocol",
  "responseLength": "$context.responseLength"
}

ログ出力内容

{
  "requestId": "feee42ea-1b14-4f99-ad2a-5c0e17b01d5c",
  "ip": "xxx.xxx.xxx.xxx",
  "caller": "-",
  "user": "-",
  "requestTime": "26/Sep/2020:13:10:33 +0000",
  "httpMethod": "GET",
  "resourcePath": "/employee",
  "status": "200",
  "protocol": "HTTP/1.1",
  "responseLength": "0",

共通的なコンテキスト変数

フォーマットでの指定

{
  "account_id": "$context.accountId",
  "api_id": "$context.apiId",
  "authorizer_claims_property": "$context.authorizer.claims.property",
  "authorizer_principal_id": "$context.authorizer.principalId",
  "authorizer_property": "$context.authorizer.property",
  "aws_endpoint_request_id": "$context.awsEndpointRequestId",
  "domain_name": "$context.domainName",
  "domain_prefix": "$context.domainPrefix",
  "error_message": "$context.error.message",
  "error_message_string": "$context.error.messageString",
  "error_response_type": "$context.error.responseType",
  "error_validation_error_string": "$context.error.validationErrorString",
  "extended_request_id": "$context.extendedRequestId",
  "identity_account_id": "$context.identity.accountId",
  "identity_api_key": "$context.identity.apiKey",
  "identity_api_key_id": "$context.identity.apiKeyId",
  "identity_cognito_authentication_provider": "$context.identity.cognitoAuthenticationProvider",
  "identity_cognito_authentication_type": "$context.identity.cognitoAuthenticationType",
  "identity_cognito_identity_id": "$context.identity.cognitoIdentityId",
  "identity_cognito_identity_pool_id": "$context.identity.cognitoIdentityPoolId",
  "identity_principal_org_id": "$context.identity.principalOrgId",
  "identity_client_cert_client_cert_pem": "$context.identity.clientCert.clientCertPem",
  "identity_client_cert_subject_d_n": "$context.identity.clientCert.subjectDN",
  "identity_client_cert_issuer_d_n": "$context.identity.clientCert.issuerDN",
  "identity_client_cert_serial_number": "$context.identity.clientCert.serialNumber",
  "identity_client_cert_validity_not_before": "$context.identity.clientCert.validity.notBefore",
  "identity_client_cert_validity_not_after": "$context.identity.clientCert.validity.notAfter",
  "identity_user_agent": "$context.identity.userAgent",
  "identity_user_arn": "$context.identity.userArn",
  "path": "$context.path",
  "request_override_header_header_name": "$context.requestOverride.header.header_name",
  "request_override_path_path_name": "$context.requestOverride.path.path_name",
  "request_override_querystring_querystring_name": "$context.requestOverride.querystring.querystring_name",
  "response_override_header_header_name": "$context.responseOverride.header.header_name",
  "response_override_status": "$context.responseOverride.status",
  "request_time_epoch": "$context.requestTimeEpoch",
  "resource_id": "$context.resourceId",
  "stage": "$context.stage",
  "waf_response_code": "$context.wafResponseCode",
  "webacl_arn": "$context.webaclArn",
  "xray_trace_id": "$context.xrayTraceId"
}

ログ出力内容

{
    "account_id": "xxxxxxxxxxxx",
    "api_id": "xxxxxxxxxx",
    "authorizer_claims_property": "-",
    "authorizer_principal_id": "-",
    "authorizer_property": "-",
    "aws_endpoint_request_id": "-",
    "domain_name": "xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com",
    "domain_prefix": "xxxxxxxxxx",
    "error_message": "-",
    "error_message_string": "-",
    "error_response_type": "-",
    "error_validation_error_string": "-",
    "extended_request_id": "TeaXkGWhNjMFVjw=",
    "identity_account_id": "-",
    "identity_api_key": "-",
    "identity_api_key_id": "-",
    "identity_cognito_authentication_provider": "-",
    "identity_cognito_authentication_type": "-",
    "identity_cognito_identity_id": "-",
    "identity_cognito_identity_pool_id": "-",
    "identity_principal_org_id": "-",
    "identity_client_cert_client_cert_pem": "-",
    "identity_client_cert_subject_d_n": "-",
    "identity_client_cert_issuer_d_n": "-",
    "identity_client_cert_serial_number": "-",
    "identity_client_cert_validity_not_before": "-",
    "identity_client_cert_validity_not_after": "-",
    "identity_user_agent": "curl/7.61.1",
    "identity_user_arn": "-",
    "path": "/prod/employee",
    "request_override_header_header_name": "-",
    "request_override_path_path_name": "-",
    "request_override_querystring_querystring_name": "-",
    "response_override_header_header_name": "-",
    "response_override_status": "-",
    "request_time_epoch": "1601126133567",
    "resource_id": "xxxxxx",
    "stage": "prod",
    "waf_response_code": "-",
    "webacl_arn": "-",
    "xray_trace_id": "-"
}

アクセスログのみのコンテキスト変数

フォーマットでの指定

{
  "authorize_error": "$context.authorize.error",
  "authorize_latency": "$context.authorize.latency",
  "authorize_status": "$context.authorize.status",
  "authorizer_error": "$context.authorizer.error",
  "authorizer_integration_latency": "$context.authorizer.integrationLatency",
  "authorizer_integration_status": "$context.authorizer.integrationStatus",
  "authorizer_latency": "$context.authorizer.latency",
  "authorizer_request_id": "$context.authorizer.requestId",
  "authorizer_status": "$context.authorizer.status",
  "authenticate_error": "$context.authenticate.error",
  "authenticate_latency": "$context.authenticate.latency",
  "authenticate_status": "$context.authenticate.status",
  "integration_error": "$context.integration.error",
  "integration_integration_status": "$context.integration.integrationStatus",
  "integration_latency1": "$context.integration.latency",
  "integration_request_id": "$context.integration.requestId",
  "integration_status1": "$context.integration.status",
  "integration_error_message": "$context.integrationErrorMessage",
  "integration_latency2": "$context.integrationLatency",
  "integration_status2": "$context.integrationStatus",
  "response_latency": "$context.responseLatency",
  "waf_error": "$context.waf.error",
  "waf_latency": "$context.waf.latency",
  "waf_status": "$context.waf.status"
}

ログ出力内容

{
    "authorize_error": "-",
    "authorize_latency": "-",
    "authorize_status": "-",
    "authorizer_error": "-",
    "authorizer_integration_latency": "-",
    "authorizer_integration_status": "-",
    "authorizer_latency": "-",
    "authorizer_request_id": "-",
    "authorizer_status": "-",
    "authenticate_error": "-",
    "authenticate_latency": "-",
    "authenticate_status": "-",
    "integration_error": "-",
    "integration_integration_status": "200",
    "integration_latency1": "0",
    "integration_request_id": "-",
    "integration_status1": "-",
    "integration_error_message": "-",
    "integration_latency2": "0",
    "integration_status2": "200",
    "response_latency": "3",
    "waf_error": "-",
    "waf_latency": "-",
    "waf_status": "-"
}

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
0