Firehoseに対応したAPI Gatewayのアクセスログ設定を試してみた

2019.10.20

AWSチームのすずきです。

Amazon Kinesis Data Firehose への アクセスログ出力が可能になった Amazon API Gateway。 その設定を試す機会がありましたので、紹介させていただきます。

Amazon API Gateway が Amazon Kinesis Data Firehose へのアクセスログ記録をサポート開始

設定

Firehose

API Gatewayのログ出力先とする Kinesis Data Firehoseのストリームを作成します。

ストリームの名称は「amazon-apigateway-」で始まる名称とします。

Firehoseの出力先はS3としました。

API Gateway のログ設定で利用する「Delivery stream ARN」を確認します。

IAM

API Gateway のサービスロール「AWSServiceRoleForAPIGateway」が存在、 AWS 管理ポリシー「 APIGatewayServiceRolePolicy が適用されている事を確認します。

  • arn:aws:iam::<アカウントID>:role/aws-service-role/ops.apigateway.amazonaws.com/AWSServiceRoleForAPIGateway

「AWSServiceRoleForAPIGateway」が存在しない場合、API GatewayのWeb設定画面で「X-Ray Tracing」の有効化することで、サービスロールが作成されます。

APIGateway

ログを有効とするAPIのステージを指定、「Log/Tracing」ので 「Custom Access Logging」を有効、

Access Log Destination ARN は、API Gateway用に作成した 名称「amazon-apigateway-」で始まる FirehoseのARNを指定します。

ログの形式、今回は「JSON」の設定例をそのまま利用しました。

確認

Firehose の出力先として指定した S3配下に API Gatewayのアクセスログが出力されている事を確認します。

「S3 Select」を利用して、JSON形式 で API Gatewayのアクセスログが保存されている事を確認できました。

まとめ

API Gateway のアクセスログ、従来から利用できた CloudWatch Logs に加え、Kinesis Data Firehose 経由で S3 を 出力先として利用する事が可能となりました。

CloudWatch Logs は、CloudWatch Logs Insights といった便利な分析機能を備えますが、東京リージョンでは、収集したログ1GBあたり 0.76 USD の費用が課題となる事がありました。

【新機能】Amazon API Gateway でアクセスログを記録する #reinvent

Kinesis Data Firehose は、1GBあたり0.036 USD、CloudWatch Logs の 1/20の費用で利用可能です。

これまで コストが課題となり API Gateway アクセスログの取得を見送っていた場合、今回のアップデートをぜひお試しください。

Firehose設定テンプレート

API Gateway ログ用の S3バケット、 Firehose を設置する CloudFormationテンプレート例です。

S3BucketFirehose:
    Type: AWS::S3::Bucket
    DeletionPolicy: Delete
    Properties:
      BucketName: !Sub '${AWS::StackName}-firehose-${AWS::Region}-${AWS::AccountId}'
      LifecycleConfiguration:
        Rules:
          - Id: AutoDelete
            Status: Enabled
            ExpirationInDays: 14
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      Tags:
        - Key: StackId
          Value: !Sub '${AWS::StackId}'
      VersioningConfiguration:
        Status: Enabled
  FirehoseStreamRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Sid: ''
            Effect: Allow
            Principal:
              Service: firehose.amazonaws.com
            Action: sts:AssumeRole
            Condition:
              StringEquals:
                sts:ExternalId: !Ref 'AWS::AccountId'
  FirehoseStreamPolicy:
    Type: AWS::IAM::Policy
    Properties:
      PolicyName: firehose_delivery_policy
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Action:
              - s3:AbortMultipartUpload
              - s3:GetBucketLocation
              - s3:GetObject
              - s3:ListBucket
              - s3:ListBucketMultipartUploads
              - s3:PutObject
            Resource:
              - !Sub 'arn:aws:s3:::${S3BucketFirehose}'
              - !Sub 'arn:aws:s3:::${S3BucketFirehose}/*'
      Roles:
        - !Ref 'FirehoseStreamRole'
  FirehoseStreamApigw:
    Type: AWS::KinesisFirehose::DeliveryStream
    Properties:
      DeliveryStreamName: !Sub 'amazon-apigateway-${AWS::StackName}'
      ExtendedS3DestinationConfiguration:
        BucketARN: !Sub 'arn:aws:s3:::${S3BucketFirehose}'
        Prefix: !Sub 'apigw/dt=!{timestamp:YYYY}-!{timestamp:MM}-!{timestamp:dd}/'
        ErrorOutputPrefix: !Sub 'apigw-error/!{firehose:error-output-type}/dt=!{timestamp:YYYY}-!{timestamp:MM}-!{timestamp:dd}/'
        BufferingHints:
          IntervalInSeconds: '300'
          SizeInMBs: '10'
        CompressionFormat: GZIP
        RoleARN: !GetAtt 'FirehoseStreamRole.Arn'
        ProcessingConfiguration:
          Enabled: 'false'