こんにちは、DX推進室の安齋です。
今回はAWSサーバーレスリソース構築でハマった・工夫した箇所の紹介の第2回目となります。
- 第1回は API GatewayでIAM認証を行う
第2回はAPI GatewayのCloudWatch Logsの設定をSAMとCloudFormationで行った方法のTipsとなります。
同方法を調べた際、日本語の検索結果が無かったので、同じように困った人がいた時のために書いておこうと思います。
今回のテーマ
上記構成図の赤枠内の管理者用API GatewayのアクセスログをCloudWatch Logsに流し込みます。全てIaCで。
最初はこれでイケると思った
SAMドキュメントにはAPI Gatewayのアクセスログ出力先とAPI Gateway用のIAMロールを用意する記述がありましたが、同IAMロールをAPI Gatewayにアタッチする方法がありませんでした。
調べた結果、英語サイトに解決策が載っており、AWS::ApiGateway::Account
を使用することでアタッチができました。
しかし、それだけではアクセスログは出力されませんでした。
SAMテンプレート
以下、API GatewayのCloudWatch Logsに関する記述です。
Resources:
#===============================
# API Gateway CloudWatchLogs IAM Role
#===============================
# ★★★ココからポイント★★★ #
ApiGwAccountConfig:
Type: AWS::ApiGateway::Account
Properties:
CloudWatchRoleArn: !ImportValue APIGatewayRoleArn
# ★★★ココまでポイント★★★ #
#===============================
# API Gateway for Admin
#===============================
AdminApiResource:
Type: AWS::Serverless::Api
Properties:
AccessLogSetting:
DestinationArn: !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/apigateway/rest/${ServiceName}-${Env}-admin
...省略(第1回に記述済み)
CloudFormationテンプレート
今回は、API Gateway用のIAMロール、API GatewayのCloudWatch Logs、CloudWatch Logs用のKMSの箇所を抜粋しています。
Resources:
#===============================
# API Gateway IAM Role
#===============================
APIGatewayRole:
Type: AWS::IAM::Role
UpdateReplacePolicy: Retain
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Action: sts:AssumeRole
Effect: Allow
Principal:
Service: apigateway.amazonaws.com
RoleName: !Sub ${ServiceName}-${Env}-apigateway-role
Policies:
- PolicyName: !Sub ${ServiceName}-${Env}-apigateway-policy
PolicyDocument:
Version: 2012-10-17
Statement:
- Sid: CloudWatchLogs
Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:DescribeLogGroups
- logs:DescribeLogStreams
- logs:PutLogEvents
- logs:GetLogEvents
- logs:FilterLogEvents
Resource: !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/*
#===============================
# API Gateway for Admin Log
#===============================
APIGatewayForAdminLogGroup:
Type: AWS::Logs::LogGroup
DeletionPolicy: Retain
UpdateReplacePolicy: Retain
Properties:
LogGroupName: !Sub /apigateway/rest/${ServiceName}-${Env}-admin
KmsKeyId: !GetAtt LogEncryptionKey.Arn
RetentionInDays: 30
#===============================
# Log KMS Key
#===============================
LogEncryptionKey:
Type: AWS::KMS::Key
DeletionPolicy: Retain
UpdateReplacePolicy: Retain
Properties:
EnableKeyRotation: true
KeyPolicy:
Version: '2012-10-17'
Id: key-default-1
Statement:
- Sid: Allow access for Key Administrators
Effect: Allow
Principal:
AWS:
- !Sub arn:aws:iam::${AWS::AccountId}:role/Administrator
Action:
- kms:Create*
- kms:Describe*
- kms:Enable*
- kms:List*
- kms:Put*
- kms:Update*
- kms:Revoke*
- kms:Disable*
- kms:Get*
- kms:Delete*
- kms:TagResource
- kms:UntagResource
- kms:ScheduleKeyDeletion
- kms:CancelKeyDeletion
Resource: '*'
- Sid: Allow use of the key
Effect: Allow
Principal:
AWS:
- !Sub arn:aws:iam::${AWS::AccountId}:role/Administrator
Action:
- kms:DescribeKey
- kms:Encrypt
- kms:Decrypt
- kms:ReEncrypt*
- kms:GenerateDataKey*
Resource: '*'
- Sid: Allow use of the key from CloudWatchLogs
Effect: Allow
Principal:
Service: !Sub logs.${AWS::Region}.amazonaws.com
Action:
- kms:DescribeKey
- kms:Encrypt
- kms:Decrypt
- kms:ReEncrypt*
- kms:GenerateDataKey*
Resource: '*'
Condition:
ArnLike:
kms:EncryptionContext:aws:logs:arn:
- !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/apigateway/*
#==============================
# Outputs
#==============================
Outputs:
#===============================
# API Gateway IAM Role
#===============================
APIGatewayRoleArn:
Value: !GetAtt APIGatewayRole.Arn
Export:
Name: APIGatewayRoleArn
参考資料
- Necessary for API Gateway Logging
- https://gist.github.com/villasv/4f5b62a772abe2c06525356f80299048
これで解決!
SAMドキュメントのAPI GatewayのCloudWatch Logsの設定を読むと、Format
が必須であり、最低限 $context.requestId
が必要でした。Format
必須要否は「条件付き」だったので、デフォルトのフォーマットがあり、カスタマイズしたい場合に Format
を使用するのだと浅く読んでいました。
SAMテンプレート
#===============================
# API Gateway for Admin
#===============================
AdminApiResource:
Type: AWS::Serverless::Api
Properties:
AccessLogSetting:
DestinationArn: !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/apigateway/rest/${ServiceName}-${Env}-admin
# ★★★ココから追記★★★ #
Format: '$context.requestId $context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] "$context.httpMethod $context.resourcePath $context.protocol" $context.status $context.responseLength'
# ★★★ココまで追記★★★ #
...省略(第1回に記述済み)
めでたしめでたし
無事にAPI GatewayのアクセスログをCloudWatch Logsに出力することができました。API GatewayにIAMロールを紐づける設定がSAMやCloudFormationのAPI Gateway V2に無かったことで、半ば全IaCを諦めていたのですが、無事に方法を見つけることができました。