ALBとCLBのアクセスログを保存するS3バケットポリシーをCloudFormation(YAML)で書いてみた

AWS CloudFormation

はじめに

Application Load BalancerやClassic Load Balancerのアクセスログ機能を有効化すると、S3バケットにログを格納できます。
バケットにはポリシーを設定する必要があります。
ポリシーはALBのユーザーガイドCLBのユーザーガイドに記載されています。
AWSコンソールでログ有効化する場合、"この場所の作成"を選択するとポリシーが設定されたS3バケットが作成されるため、あまりポリシーを意識することはないかもしれません。

今回は、YAML形式のCloudFormationテンプレートを作る際にバケットポリシーの書き方にはまったので、共有します。

テンプレート

テンプレートでは、バケットポリシーが設定されたS3バケットを作成します。
ELBの種類(ALB,CLB)に関わらず必要なポリシーは同一です。

AWSTemplateFormatVersion: 2010-09-09
Description: ELB Bucket Test
Mappings:
  S3Config:
    us-east-1:
      BucketPrincipal: "127311923021"
    us-east-2:
      BucketPrincipal: "033677994240"
    us-west-1:
      BucketPrincipal: "027434742980"
    us-west-2:
      BucketPrincipal: "797873946194"
    ca-central-1:
      BucketPrincipal: "985666609251"
    eu-west-1:
      BucketPrincipal: "156460612806"
    eu-central-1:
      BucketPrincipal: "054676820928"
    eu-west-2:
      BucketPrincipal: "652711504416"
    ap-northeast-1:
      BucketPrincipal: "582318560864"
    ap-northeast-2:
      BucketPrincipal: "600734575887"
    ap-southeast-1:
      BucketPrincipal: "114774131450"
    ap-southeast-2:
      BucketPrincipal: "783225319266"
    ap-south-1:
      BucketPrincipal: "718504428378"
    sa-east-1:
      BucketPrincipal: "507241528517"
    us-gov-west-1:
      BucketPrincipal: "048591011584"
    cn-north-1:
      BucketPrincipal: "638102146993"

Resources:
  ELBLogBucket:
    Type: "AWS::S3::Bucket"
    Properties:
      BucketName: !Join [ "-", [ elblog , Ref: "AWS::AccountId" ] ]
  BucketPolicyELBLogBucket:
    Type: "AWS::S3::BucketPolicy"
    Properties:
      Bucket:
        Ref: "ELBLogBucket"
      PolicyDocument:
        Id: "Allow-Put-ELB-logs"
        Version: "2012-10-17"
        Statement:
          -
            Sid: "Stmt1429136633762"
            Action:
              - "s3:PutObject"
            Effect: "Allow"
            Resource:
              Fn::Join:
                - ""
                -
                  - "arn:aws:s3:::"
                  -
                    Ref: "ELBLogBucket"
                  - "/AWSLogs/"
                  -
                    Ref: AWS::AccountId
                  - "/*"
            Principal:
              AWS: !FindInMap [ S3Config, Ref: "AWS::Region", BucketPrincipal ]

解説

リソース

ELBLogBucketがS3バケット、BucketPolicyELBLogBucketがバケットポリシーに関する記述です。

プレフィックスの指定

ELBではアクセスログを配置するS3プレフィックスを指定できます。バケット名/my-appといった形です。
プレフィックスを指定する場合、バケットポリシーの修正が必要です。
"/AWSLogs/"を"/my-app/AWSLogs/"のようにします。
上記テンプレートはプレフィックスを指定しない前提です。

自アカウントIDの指定

"AWS::AccountId"などを擬似パラメーターといいます。
「Ref: AWS::AccountId」とすると、スタックが作成されているアカウントのアカウントIDを返します。

PrincipalでのELBアカウントIDの指定

Principalでは、ELBを配置するリージョンに応じてAWSアカウントIDを指定します。
東京リージョンの場合、"582318560864"、オレゴンリージョンの場合、"797873946194"といった形です。
テンプレートでは、Create Stackしたリージョンと同じアカウントIDがPrincipalに入るようにしました。
東京リージョンでCreate Stackすると、"582318560864"がPrincipalに記載されます。
この仕組みにはMappingsセクションFindInMap組み込み関数、AWS::Region擬似パラメーターを使いました。

バケットの名前

Join組み込み関数を使って、elblog-アカウントIDという名前のバケットが作成されるようにしました。
実環境でお使いの場合、適宜変更してください。

おわりに

YAML形式のCloudFormationテンプレートを作る際にはまったので、共有しました。
同様に、はまったかたのお役に立てれば嬉しいです。

参考

AWS Cloud Roadshow 2017 福岡