CloudFormation (S3＋CloudFront)

## 概要
CloudFormationに慣れるため、外部公開するS3バケットとCloudFront(CDN)を自動作成してみる。

## 前提条件
* macOS
* Docker Toolbox ( Docker for mac )

## ファイル構成
下記のようなファイルを作成します。

```:ファイル構成
opt
　├ docker
　│　└ aws-cli
　│　   └ Dockerfile
　├ src
　│  └ template.yml
　│
　└ docker-compose.yml
```

## Dockerfile作成
aws-cliコマンドが使えるコンテナを構築するファイルです。

```Dockerfile:docker/aws-cli/Dockerfile
FROM python:3.6

ARG pip_installer="https://bootstrap.pypa.io/get-pip.py"
ARG awscli_version="1.16.168"

# install aws-cli
RUN pip install awscli==${awscli_version}

# install sam
RUN pip install --user --upgrade aws-sam-cli
ENV PATH $PATH:/root/.local/bin

# install command.
RUN apt-get update && apt-get install -y less vim

# copy source code.
COPY ./src /src

WORKDIR /root
```

## docker-compose.yml作成
下記の内容で作成します。

```yaml:docker-compose.yml
version: '3'
services:
  aws-cli:
    container_name: 'aws-cli'
    image: aws-s3/aws-cli
    build:
      context: ./
      dockerfile: ./docker/aws-cli/Dockerfile
    tty: true
    environment:
      AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID}
      AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY}
      AWS_DEFAULT_REGION: ap-northeast-1
      AWS_DEFAULT_OUTPUT: json
```

## template.yml作成
CloudFormationの設定ファイルを作成します。
※ 「 ＜image-bucket＞ 」には、自分の作りたいS3バケット名を記載ください。

```yaml:src/template.yml
AWSTemplateFormatVersion: 2010-09-09
Description: "create public s3 bucket."
Resources:

  # S3Bucket作成
  ImageBucket:
    Type: "AWS::S3::Bucket"
    DeletionPolicy: "Retain"
    Properties:
      AccessControl: "PublicRead"
      BucketName: !Sub <image-bucket>

  # S3Bucketのポリシーを定義する
  ImageBucketPolicy:
    Type: "AWS::S3::BucketPolicy"
    Properties:
      Bucket: !Sub ${ImageBucket}
      PolicyDocument:
        Statement:
          - Action:
              - s3:GetObject
            Effect: "Allow"
            Principal: "*"
            Resource: !Sub arn:aws:s3:::${ImageBucket}/*

  # CloudFront
  MyDistribution:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        Origins:
          - DomainName: <image-bucket>.s3.amazonaws.com
            Id: myS3Origin
            S3OriginConfig: {}
        Enabled: 'true'
        Comment: distribution for content delivery
        DefaultRootObject: index.html
        DefaultCacheBehavior:
          TargetOriginId: myS3Origin
          ForwardedValues:
            QueryString: 'true'
            Cookies:
              Forward: 'none'
          ViewerProtocolPolicy: allow-all
          MinTTL: '100'
          SmoothStreaming: 'false'
          Compress: 'true'
        PriceClass: PriceClass_All
        ViewerCertificate:
          CloudFrontDefaultCertificate: 'true'

Outputs:
  ImageBucket:
    Value: !Ref ImageBucket
    Export:
      Name: !Sub "${AWS::StackName}-ImageBucket"

  MyDistribution:
    Value: !Ref MyDistribution
    Export:
      Name: !Sub "${AWS::StackName}-MyDistribution"
```

## サーバ構築
下記コマンドにてdockerコンテナのイメージを構築します。

```bash:ターミナル
$ docker-compose build
```

## AWSの環境設定
下記のように環境変数を定義します。
※ ここで定義した環境変数は、自動的にdockerコンテナに取り込まれます

```bash:ターミナル
$ export AWS_ACCESS_KEY_ID='xxxxxxxxxxxxx'
$ export AWS_SECRET_ACCESS_KEY='xxxxxxxxxxxxxxxxxx'
```

## CloudFormation実行
下記コマンドにて実行し、S3バケットとそのS3バケットのバケットポリシー、CloudFrontを自動作成します。

```bash:ターミナル
# aws-cliコンテナ起動＆接続
$ docker-compose run --rm aws-cli bash

# aws-cliコンテナ内でcloudformationのデプロイを実行する
$ aws cloudformation deploy \
        --template-file /src/template.yml \
        --stack-name "{ここにスタック名を入力する}"

$ exit  <- aws-cliコンテナの接続解除 (コンテナも破棄されます)
```

以上