関連記事で実装しているサーバレスWebアプリのサンプルのアクセスログ確認をAthenaでお手軽にしたいと思いました。そこでCloudFront/WAF/API Gatewayのアクセスログをデータレイクとして用意したS3バケットへ保存するようにしてみました。
今回のコード
それぞれ記事時点のコードにタグを打ってあります。
- GitHub - nihemak/aws-sls-spa-sample-terraform at v0.0.5
- GitHub - nihemak/aws-sls-spa-sample-api at v0.0.5
- GitHub - nihemak/aws-sls-spa-sample-web at v0.0.4
アクセスログ保存の設定概要
全体構成は下記です。
データレイクとして作成するS3バケットは下記です。
- CloudFront(API):
${var.resource_prefix}-cloudfront-logs-api-01
- CloudFront(SPA):
${var.resource_prefix}-cloudfront-logs-web-01
- WAF(API):
${var.resource_prefix}-waf-logs-api-01
- WAF(SPA):
${var.resource_prefix}-waf-logs-web-01
- API Gateway:
${var.resource_prefix}-apigw-logs-01
CloudFront
CloudFrontのアクセスログをS3バケットに保存するには下記の対応が必要です。*1
プルリクは下記です。
ログ保存用のS3バケット
aws-sls-spa-sample-terraform/environments/service/base/after_api/main.tf:L95-L99
module "s3_bucket_cloudfront_log_api" { source = "../../../../modules/s3/bucket/cloudfront_log_api" resource_prefix = "${local.resource_prefix}" logging_bucket_id = "${local.s3_bucket_audit_log_id}" }
そしてSPAのS3バケットです。
aws-sls-spa-sample-terraform/environments/service/base/pre/main.tf:L219-L223
module "s3_bucket_cloudfront_log_web" { source = "../../../../modules/s3/bucket/cloudfront_log_web" resource_prefix = "${local.resource_prefix}" logging_bucket_id = "${var.s3_bucket_audit_log_id}" }
CloudFrontのログ出力先
まずAPIのCloudFrontです。s3_bucket_log_domain_name
にS3バケットドメイン名を指定します。
aws-sls-spa-sample-terraform/environments/service/base/after_api/main.tf:L101-L108
module "cloudfront_api" { source = "../../../../modules/cloudfront/api" resource_prefix = "${local.resource_prefix}" stage = "${var.stage}" apigw_api_domain_name = "${var.apigw_api_id}.execute-api.ap-northeast-1.amazonaws.com" s3_bucket_log_domain_name = "${module.s3_bucket_cloudfront_log_api.bucket_domain_name}" waf_acl_id = "${data.terraform_remote_state.service_base_pre.outputs.waf_acl_api_id}" }
モジュールの中は下記です。aws_cloudfront_distribution
リソースのlogging_config
にS3バケットドメイン名を指定します。
aws-sls-spa-sample-terraform/modules/cloudfront/api/main.tf:L71-L73
resource "aws_cloudfront_distribution" "api" { # ...(省略)... logging_config { bucket = "${var.s3_bucket_log_domain_name}" }
そしてSPAのCloudFrontです。こちらもs3_bucket_log_domain_name
にS3バケットドメイン名を指定します。
aws-sls-spa-sample-terraform/environments/service/base/pre/main.tf:L231-L238
module "cloudfront_web" { source = "../../../../modules/cloudfront/web" resource_prefix = "${local.resource_prefix}" s3_bucket_log_domain_name = "${module.s3_bucket_cloudfront_log_web.bucket_domain_name}" s3_bucket_web_id = "${module.s3_bucket_web.id}" s3_bucket_web_domain_name = "${module.s3_bucket_web.domain_name}" waf_acl_id = "${module.waf_acl_web.id}" }
モジュールの中は下記です。こちらもaws_cloudfront_distribution
リソースのlogging_config
にS3バケットドメイン名を指定します。
aws-sls-spa-sample-terraform/modules/cloudfront/web/main.tf:L25-L28
resource "aws_cloudfront_distribution" "web" { # ...(省略)... logging_config { include_cookies = false bucket = "${var.s3_bucket_log_domain_name}" }
WAF
WAFのアクセスログをS3バケットに保存するには下記の対応が必要です。*2
プルリクは下記です。
- Enable WAF log by nihemak · Pull Request #29 · nihemak/aws-sls-spa-sample-terraform · GitHub
- Divide waf into web and api by nihemak · Pull Request #30 · nihemak/aws-sls-spa-sample-terraform · GitHub
ログ保存用のS3バケット
aws-sls-spa-sample-terraform/environments/service/base/pre/main.tf:L106-L110
module "s3_bucket_waf_log_api" { source = "../../../../modules/s3/bucket/waf_log_api" resource_prefix = "${local.resource_prefix}" logging_bucket_id = "${var.s3_bucket_audit_log_id}" }
そしてSPAのS3バケットです。
aws-sls-spa-sample-terraform/environments/service/base/pre/main.tf:L142-L146
module "s3_bucket_waf_log_web" { source = "../../../../modules/s3/bucket/waf_log_web" resource_prefix = "${local.resource_prefix}" logging_bucket_id = "${var.s3_bucket_audit_log_id}" }
Kinesis Firehose
用意するKinesis Firehoseにはいくつか注意点があります。*3*4
- 作成するリージョンを
us-east-1
にする必要がある - 名称のプレフィックスを
aws-waf-logs-
にする必要がある - ログファイルを
GZIP
形式にする必要がある
まずAPIのKinesis Firehoseです。aws_kinesis_firehose_delivery_stream
リソースのs3_configuration
にS3バケットARNを指定します。
aws-sls-spa-sample-terraform/environments/service/base/pre/main.tf:L112-L129
module "iam_role_waf_log_api_firehose_to_s3" { source = "../../../../modules/iam/waf_log_api_firehose_to_s3" path = "../../../../modules/iam/waf_log_api_firehose_to_s3" resource_prefix = "${local.resource_prefix}" s3_bucket_arn = "${module.s3_bucket_waf_log_api.arn}" } resource "aws_kinesis_firehose_delivery_stream" "waf_log_api" { provider = aws.useast1 name = "aws-waf-logs-${local.resource_prefix}-api" destination = "s3" s3_configuration { role_arn = "${module.iam_role_waf_log_api_firehose_to_s3.arn}" bucket_arn = "${module.s3_bucket_waf_log_api.arn}" compression_format = "GZIP" } }
名称プレフィックスとGZIP
は注意点の通りです。リージョンはaws.useast1
というus-east-1
のprovider
を新たに用意して指定しました。aws.useast1
は下記になっています。
aws-sls-spa-sample-terraform/environments/service/base/pre/main.tf:L11-L13
provider "aws" { alias = "useast1" version = ">= 2.24" region = "us-east-1" }
そしてSPAのKinesis Firehoseです。こちらもaws_kinesis_firehose_delivery_stream
リソースのs3_configuration
にS3バケットARNを指定します。
aws-sls-spa-sample-terraform/environments/service/base/pre/main.tf:L148-L165
module "iam_role_waf_log_web_firehose_to_s3" { source = "../../../../modules/iam/waf_log_web_firehose_to_s3" path = "../../../../modules/iam/waf_log_web_firehose_to_s3" resource_prefix = "${local.resource_prefix}" s3_bucket_arn = "${module.s3_bucket_waf_log_web.arn}" } resource "aws_kinesis_firehose_delivery_stream" "waf_log_web" { provider = aws.useast1 name = "aws-waf-logs-${local.resource_prefix}-web" destination = "s3" s3_configuration { role_arn = "${module.iam_role_waf_log_web_firehose_to_s3.arn}" bucket_arn = "${module.s3_bucket_waf_log_web.arn}" compression_format = "GZIP" } }
こちらもリージョン、名称プレフィックスとGZIP
は注意点の通りです。
WAFのログ出力先
まずAPIのWAFです。firehose_arn
にKinesis FirehoseのARNを指定します。
aws-sls-spa-sample-terraform/environments/service/base/pre/main.tf:L131-L138
module "waf_acl_api" { source = "../../../../modules/waf/api" resource_prefix = "${local.resource_prefix}" firehose_arn = "${aws_kinesis_firehose_delivery_stream.waf_log_api.arn}" rule_size_constraint_id = "${module.waf_rule.rule_size_constraint_id}" rule_sql_injection_match_id = "${module.waf_rule.rule_sql_injection_match_id}" rule_xss_match_id = "${module.waf_rule.rule_xss_match_id}" }
モジュールの中は下記です。aws_waf_web_acl
リソースのlogging_configuration
にKinesis FirehoseのARNを指定します。
aws-sls-spa-sample-terraform/modules/waf/api/main.tf:L42-L44
resource "aws_waf_web_acl" "api" { # ...(省略)... logging_configuration { log_destination = "${var.firehose_arn}" }
そしてSPAのWAFです。こちらもfirehose_arn
にKinesis FirehoseのARNを指定します。
aws-sls-spa-sample-terraform/environments/service/base/pre/main.tf:L167-L174
module "waf_acl_web" { source = "../../../../modules/waf/web" resource_prefix = "${local.resource_prefix}" firehose_arn = "${aws_kinesis_firehose_delivery_stream.waf_log_web.arn}" rule_size_constraint_id = "${module.waf_rule.rule_size_constraint_id}" rule_sql_injection_match_id = "${module.waf_rule.rule_sql_injection_match_id}" rule_xss_match_id = "${module.waf_rule.rule_xss_match_id}" }
モジュールの中は下記です。こちらもaws_waf_web_acl
リソースのlogging_configuration
にKinesis FirehoseのARNを指定します。
aws-sls-spa-sample-terraform/modules/waf/web/main.tf:L42-L44
resource "aws_waf_web_acl" "web" { # ...(省略)... logging_configuration { log_destination = "${var.firehose_arn}" }
API Gateway
API GatewayのアクセスログをS3バケットに保存するには下記の対応が必要です。*5*6*7*8*9
- API GatewayのCloudWatch Logsへのアクセスログ保存を有効にする*10
- ログ保存用のS3バケットを用意する
- ログフォーマットをAthena用に変換するLambdaを用意する
- Kinesis Firehoseを用意して出力先に2.のS3バケットARN、ログ変換Lambdaに3のLambdaのARNを指定する
- CloudWatch Logsのサブスクリプションフィルタを用意してロググループに1.のロググループ名、出力先にKinesis FirehoseのARNを指定する
プルリクは下記です。
- Enable to restApi logs by nihemak · Pull Request #69 · nihemak/aws-sls-spa-sample-api · GitHub
- Change restApi logs format to json by nihemak · Pull Request #70 · nihemak/aws-sls-spa-sample-api · GitHub
- Add permissions for API Gateway logs by nihemak · Pull Request #25 · nihemak/aws-sls-spa-sample-terraform · GitHub
- Add data lake of API Gateway log by nihemak · Pull Request #26 · nihemak/aws-sls-spa-sample-terraform · GitHub
- Add lambda to transform apigw log to Athena format by nihemak · Pull Request #27 · nihemak/aws-sls-spa-sample-terraform · GitHub
- Move s3_bucket_api_log to environments.service.base.pre by nihemak · Pull Request #28 · nihemak/aws-sls-spa-sample-terraform · GitHub
API GatewayのCloudWatch Logsへのアクセスログ保存
serverless.yml
にrestApi
を追加しました。*11*12Athenaで操作しやすくするためにJSONフォーマットです。*13
aws-sls-spa-sample-api/serverless.yml:L11-L25
provider: name: aws logs: restApi: format: '{ "request_id":"$context.requestId", "ip": "$context.identity.sourceIp", "caller": "$context.identity.caller", "user": "$context.identity.user", "request_time": "$context.requestTime", "http_method": "$context.httpMethod", "resource_path": "$context.resourcePath", "status": "$context.status", "protocol": "$context.protocol", "response_length": "$context.responseLength" }'
これで/aws/api-gateway/${local.cloudformation_api_stack}
というロググループにアクセスログが保存されるようになります。
ログ保存用のS3バケット
aws-sls-spa-sample-terraform/environments/service/base/pre/main.tf:L41-L45
module "s3_bucket_apigw_log" { source = "../../../../modules/s3/bucket/apigw_log" resource_prefix = "${local.resource_prefix}" logging_bucket_id = "${local.s3_bucket_audit_log_id}" }
ログフォーマット変換Lambda
amazon-kinesis-firehose-cloudwatch-logs-processorを使いました。*14めんどくさかったので今回はindex.js
をダウンロードしてserverless frameworkでLambdaデプロイして使うようにしました。
まず、serverless frameworkのプロジェクトです。amazon-kinesis-firehose-cloudwatch-logs-processorのindex.js
はCodeBuildのタイミングで取得するためbuildspec.yml
でcurlしました。
aws-sls-spa-sample-terraform/serverless/buildspec.yml:L6-L10
commands: - cd serverless - npm install -g serverless@1.49.0 - COMMIT="ec522aa8c09df0eafbfe286cd1275ca5eb418e98" - curl -s -qL -o index.js "https://raw.githubusercontent.com/tmakota/amazon-kinesis-firehose-cloudwatch-logs-processor/${COMMIT}/index.js"
次にCodeBuildプロジェクトの作成です。
aws-sls-spa-sample-terraform/environments/service/base/pre/main.tf:L6-L10
## tool module "iam_role_build_tool" { source = "../../../../modules/iam/build_tool" path = "../../../../modules/iam/build_tool" aws_account_id = "${data.aws_caller_identity.current.account_id}" resource_prefix = "${local.resource_prefix}" cloudformation_tool_stack = "${local.cloudformation_tool_stack}" } module "s3_bucket_build_tool" { source = "../../../../modules/s3/bucket/build_tool" resource_prefix = "${local.resource_prefix}" logging_bucket_id = "${var.s3_bucket_audit_log_id}" } module "iam_role_exec_tool" { source = "../../../../modules/iam/exec_tool" path = "../../../../modules/iam/exec_tool" aws_account_id = "${data.aws_caller_identity.current.account_id}" resource_prefix = "${local.resource_prefix}" cloudformation_tool_stack = "${local.cloudformation_tool_stack}" } module "codebuild_tool" { source = "../../../../modules/codebuild/tool" codecommit_repository = "${data.terraform_remote_state.setup.outputs.codecommit_infra_repository}" iam_role_build_tool_arn = "${module.iam_role_build_tool.arn}" s3_bucket_build_tool_id = "${module.s3_bucket_build_tool.id}" resource_prefix = "${var.resource_prefix}" stage = "${var.stage}" iam_role_exec_tool_arn = "${module.iam_role_exec_tool.arn}" service_name = "${local.service_name}" }
最後にCodeBuildプロジェクトを実行してLambdaのデプロイです。
aws-sls-spa-sample-terraform/bin/create_development_environment.sh:L52-L56
## echo "START: base..." ## # ...(省略)... cd environments/service/base/pre/ || exit 99 codebuild_name=$(terraform output codebuild_tool_name) cd - || exit 99 ./bin/exec_codebuild.sh "${codebuild_name}" master
staging/productionも同様なbashですが割愛します。
- aws-sls-spa-sample-terraform/bin/create_staging_environment.sh
- aws-sls-spa-sample-terraform/bin/create_production_environment.sh
Kinesis Firehose
aws_kinesis_firehose_delivery_stream
リソースのextended_s3_configuration
にS3バケットARNとLambdaのARNを指定します。
aws-sls-spa-sample-terraform/environments/service/base/pre/main.tf:L47-L78
module "iam_role_apigw_firehose_to_s3" { source = "../../../../modules/iam/apigw_firehose_to_s3" path = "../../../../modules/iam/apigw_firehose_to_s3" resource_prefix = "${local.resource_prefix}" s3_bucket_arn = "${module.s3_bucket_apigw_log.arn}" aws_account_id = "${data.aws_caller_identity.current.account_id}" cloudformation_tool_stack = "${local.cloudformation_tool_stack}" } resource "aws_kinesis_firehose_delivery_stream" "apigw" { name = "${local.resource_prefix}-apigw-cwl-to-s3-stream" destination = "extended_s3" extended_s3_configuration { role_arn = "${module.iam_role_apigw_firehose_to_s3.arn}" bucket_arn = "${module.s3_bucket_apigw_log.arn}" compression_format = "GZIP" processing_configuration { enabled = "true" processors { type = "Lambda" parameters { parameter_name = "LambdaArn" parameter_value = "arn:aws:lambda:ap-northeast-1:${data.aws_caller_identity.current.account_id}:function:${local.cloudformation_tool_stack}-logsProcessor:$LATEST" } } } } }
CloudWatch Logsのサブスクリプションフィルタ
aws_cloudwatch_log_subscription_filter
リソースにロググループ名とKinesis FirehoseのARNを指定します。
aws-sls-spa-sample-terraform/environments/service/base/pre/main.tf:L80-L93
module "iam_role_apigw_cloudwatchlogs_to_s3_policy" { source = "../../../../modules/iam/apigw_coudwatchlogs_to_s3_policy" path = "../../../../modules/iam/apigw_coudwatchlogs_to_s3_policy" aws_account_id = "${data.aws_caller_identity.current.account_id}" resource_prefix = "${local.resource_prefix}" } resource "aws_cloudwatch_log_subscription_filter" "apigw_logfilter" { name = "${local.resource_prefix}-apigw_logfilter" role_arn = "${module.iam_role_apigw_cloudwatchlogs_to_s3_policy.arn}" log_group_name = "/aws/api-gateway/${local.cloudformation_api_stack}" filter_pattern = "" destination_arn = "${aws_kinesis_firehose_delivery_stream.apigw.arn}" }
Athenaで確認
SPAで色々と操作をしてしばらく経つとS3バケットにアクセスログファイルが溜まってきます。
とりあえず今回は凝ったことをせずテーブル作ってSELECTするところまでしました。*15*16*17
CloudFront
S3バケット名はAPIが${var.resource_prefix}-cloudfront-logs-api-01
、SPAが${var.resource_prefix}-cloudfront-logs-web-01
です。
CREATE EXTERNAL TABLE IF NOT EXISTS `cloudfront_logs`( `date` date, `time` string, `location` string, `bytes` bigint, `request_ip` string, `method` string, `host` string, `uri` string, `status` int, `referrer` string, `user_agent` string, `query_string` string, `cookie` string, `result_type` string, `request_id` string, `host_header` string, `request_protocol` string, `request_bytes` bigint, `time_taken` float, `xforwarded_for` string, `ssl_protocol` string, `ssl_cipher` string, `response_result_type` string, `http_version` string, `fle_status` string, `fle_encrypted_fields` int) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' STORED AS INPUTFORMAT 'org.apache.hadoop.mapred.TextInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat' LOCATION 's3://[S3バケット名]/' TBLPROPERTIES ( 'skip.header.line.count'='2');
テーブルができたので検索できるようになりました。
SELECT * FROM "default"."cloudfront_logs" limit 10;
WAF
S3バケット名はAPIが${var.resource_prefix}-waf-logs-api-01
、SPAが${var.resource_prefix}-waf-logs-web-01
です。
CREATE EXTERNAL TABLE IF NOT EXISTS `waf_logs`( `timestamp` bigint, `formatversion` int, `webaclid` string, `terminatingruleid` string, `terminatingruletype` string, `action` string, `httpsourcename` string, `httpsourceid` string, `rulegrouplist` array< struct< rulegroupid: string, terminatingrule: string, nonterminatingmatchingrules: array< struct< action: string, ruleid: string > >, excludedrules: array< struct< exclusiontype: string, ruleid: string > > > >, `ratebasedrulelist` array< struct< ratebasedruleid: string, limitkey: string, maxrateallowed: int > >, `nonterminatingmatchingrules` array< struct< action: string, ruleid: string > >, `httprequest` struct< clientip: string, country: string, headers: array< struct< name: string, value: string > >, uri: string, args: string, httpversion: string, httpmethod: string, requestid: string>) ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe' STORED AS INPUTFORMAT 'org.apache.hadoop.mapred.TextInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.IgnoreKeyTextOutputFormat' LOCATION 's3://[S3バケット名]/';
テーブルができたので検索できるようになりました。
SELECT * FROM "default"."waf_logs" limit 10;
API Gateway
まずはテーブルを定義します。CREATE 文はserverless.yml
のrestApi
に指定したJSONフォーマットから作りました。
S3バケット名は${var.resource_prefix}-apigw-logs-01
です。
CREATE EXTERNAL TABLE IF NOT EXISTS `apigw_logs`( `request_id` string, `ip` string, `caller` string, `user` string, `request_time` string, `http_method` string, `resource_path` string, `status` string, `protocol` string, `response_length` string) ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe' WITH SERDEPROPERTIES ( 'ignore.malformed.json'='true') STORED AS INPUTFORMAT 'org.apache.hadoop.mapred.TextInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.IgnoreKeyTextOutputFormat' LOCATION 's3://[S3バケット名]/' TBLPROPERTIES ( 'has_encrypted_data'='false');
テーブルができたので検索できるようになりました。
SELECT * FROM "default"."apigw_logs" limit 10;
まとめ
今回はCloudFront/WAF/API GatewayのアクセスログをS3に保存しデータレイクとしてAthenaで確認できるようにしてみました。
- DynamoDBの情報もGlueなどでS3データレイクに同期するようにしても良いかも。そうすればAthenaでSQL使えるし分析のためにRCUを消費してサービスに影響するということもないし。
- Cognitoの情報もS3データレイクに同期するようにしても良いかも。ただお手軽に同期する手段がないのでCognitoトリガーで一旦DynamoDBに同期してからのGlueなどでの同期になるかも。
- LambdaのログもS3データレイクに同期するようにしても良いかも。
関連記事
- TerraformでAWSサーバーレスなサービスのインフラ構築をコード化する
- Serverless FrameworkとTypeScriptでClean ArchitectureライクなREST APIを作ってみる
- Angular6でマテリアルデザイン/ReduxアーキテクチャなSPAフロントエンドを作ってみた
- Angular+Serverless Framework+AWSな構成のサーバレスWebアプリにAmplify+API Gateway Lambda AuthorizerでCognitoユーザ認証を組み込んでみた
- SPA/サーバレスAPIのCodePipelineにlint/ユニットテスト/E2Eテストを加えてみた
*1:CloudFrontのアクセスログの設定および使用:https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/AccessLogs.html
*2:ウェブ ACL トラフィック情報のログ記録:https://docs.aws.amazon.com/ja_jp/waf/latest/developerguide/logging.html
*3:ウェブ ACL でログ記録を有効にするには:https://docs.aws.amazon.com/ja_jp/waf/latest/developerguide/logging.html#logging-procedure
*4:Athena圧縮形式:https://docs.aws.amazon.com/ja_jp/athena/latest/ug/compression-formats.html
*5:API Gateway CloudWatch の API ログ作成をセットアップする:https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/set-up-logging.html
*6:CloudWatch Logs サブスクリプションフィルタの使用:https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/SubscriptionFilters.html#FirehoseExample
*7:Amazon Kinesis Data Firehose のデータ変換:https://docs.aws.amazon.com/ja_jp/firehose/latest/dev/data-transformation.html
*8:AWS CloudWatch Logs に貯めこんだログをどうにかしようとしてハマった話:https://tech.actindi.net/2019/05/29/105748
*9:AWS Black Belt Online Seminar「Amazon Athena」の資料およびQA公開:https://aws.typepad.com/sajp/2017/03/aws-black-belt-online-seminaramazon-athena_slides_and_qa.html ... Q8にAmazon Kinesis FirehoseのData Transformationの必要性
*10:Firehoseを直接指定できるようになったので手順は変えた方が良いかも → Amazon API Gateway が Amazon Kinesis Data Firehose へのアクセスログ記録をサポート開始:https://aws.amazon.com/jp/about-aws/whats-new/2019/10/amazon-api-gateway-now-supports-access-logging-to-amazon-kinesis-data-firehose/
*11:serverless/API Gateway REST API logs:https://serverless.com/blog/framework-release-v142/#api-gateway-rest-api-logs
*12:serverless/API Gateway REST API logshttps://serverless.com/framework/docs/providers/aws/events/apigateway/#logs
*13:API Gateway マッピングテンプレートとアクセスのログ記録の変数リファレンス:https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html
*14:Lambda設計図のKinesis Data Firehose CloudWatch Logs Processor (Kinesis Data Firehose CloudWatch ログプロセッサ) と同じ?
*15:S3のデータをAmazon Athenaを使って分析する:https://aws.amazon.com/jp/blogs/news/analyzing-data-in-s3-using-amazon-athena/
*16:CREATE TABLE:https://docs.aws.amazon.com/ja_jp/athena/latest/ug/create-table.html
*17:SELECT:https://docs.aws.amazon.com/ja_jp/athena/latest/ug/select.html
*18:Amazon CloudFront ログのクエリ:https://docs.aws.amazon.com/ja_jp/athena/latest/ug/cloudfront-logs.html
*19:CloudFrontログ形式:https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/AccessLogs.html#LogFileFormat
*20:AWS WAFのフルログをAthenaで分析できるようにしてみた:https://dev.classmethod.jp/cloud/aws/query-aws-waf-full-log-by-athena/
*21:ログの例:https://docs.aws.amazon.com/ja_jp/waf/latest/developerguide/logging.html