CloudFormationで静的なウェブサイトホスティングするS3を自動構成してみる

CloudFormationでStatic Website HostingするS3を自動構成してみた

![cf_s3static_hosting.png](https://qiita-image-store.s3.amazonaws.com/0/16768/b6daf39c-01f2-f95b-c2ed-ca22f79f09d6.png)

## CloudFormationのTemplate

 * 入力パラメータ
  * 静的なWebサイトに使用するサブドメイン
  * StaticDomain：静的なWebサイトを提供するサブドメイン
  * StaticHostedZone：サブドメインを提供するRoute53のHostedZone名
 * 以下のリソースを作成
  * Static Website HostingするS3バケット
  * 特定のIP（192.168.0.0/16）からのGetObjectを許可するS3バケットポリシー
  * Route53のレコード(CNAMEでS3のStatic Websiteを登録)
 * 出力
  * StaticURL：静的なWebサイトへのURL
 
```json
{                                                                                                     
  "AWSTemplateFormatVersion" : "2010-09-09",
  "Description" : "Sample",

  "Parameters" : { 
     "StaticDomain" : { 
        "Type" : "String",
        "Default" : "hogemoge.test.com",
        "Description" : "domain for static"
     },  
     "StaticHostedZone" : { 
        "Type" : "String",
        "Default" : "test.com",
        "Description" : "hosted zone for static"
     }   
  },  

  "Resources" : { 

    "StaticBucket" : { 
      "Type" : "AWS::S3::Bucket",
      "Properties" : { 
        "BucketName" : { "Ref" : "StaticDomain" },
        "WebsiteConfiguration" : { "IndexDocument" : "index.html", "ErrorDocument" : "error.html" }
      }
    },

    "StaticBucketPolicy" : {
      "Type" : "AWS::S3::BucketPolicy",
      "Properties" : {
        "Bucket" : { "Ref" : "StaticBucket" },
        "PolicyDocument" : {
           "Statement": [{
             "Effect": "Allow",
             "Principal": { "AWS": "*" },
             "Action": ["s3:GetObject"],
             "Resource": { "Fn::Join" : ["", ["arn:aws:s3:::", { "Ref" : "StaticBucket" } , "/*" ]] },
             "Condition": {
               "IpAddress": {
                  "aws:SourceIp": [
                    "192.168.0.0/16"
                  ]
               }
             }
           }]
        }
      }
    },

    "StaticRecord" : { 
      "Type" : "AWS::Route53::RecordSet",
      "Properties" : { 
        "HostedZoneName" : { "Fn::Join" : ["", [{ "Ref" : "StaticHostedZone" }, "."]] },
        "Name" : { "Fn::Join" : ["", [{ "Ref" : "StaticDomain" }, "."]] },
        "Type" : "CNAME",
        "Comment" : "TestCreated",
        "TTL" : "300",
        "ResourceRecords" : [
           { "Fn::Join" : ["", [{ "Ref" : "StaticBucket" }, ".s3-website-", { "Ref" : "AWS::Region" }, ".amazonaws.com" ]] }                                                                                
        ]
      }   
    }

  },

  "Outputs" : {
    "StaticURL" : {
      "Value" : { "Fn::Join" : ["", ["http://", { "Ref" : "StaticDomain" } ]] }
    }
  }
}
```

## Template作成について

* リソースの記述については以下を参照
 * [AWS Resource Types Reference - AWS CloudFormation](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html)

* Rubyスクリプトでtemplate validate
 * eclipseのplugin利用しなくてもこの程度の規模のtemplateならこれくらいのvalidateで問題なかった

```rb
#!/bin/env ruby                                                                 
require 'json'
require 'aws-sdk'

target = File.read(ARGV[0])

JSON.parse(target)

cf = AWS::CloudFormation.new(proxy_uri: ENV['HTTP_PROXY'] || ENV['http_proxy'])
puts cf.validate_template(target)
```