[JAWS-UG CLI] S3:#3 静的Webホスティングのアクセスログ設定 (バケットのライフサイクル設定 & バケットのACL設定)

S3で公開している静的コンテンツのアクセスログの設定と保存を行ないます。

* http://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/ServerLogs.html

前提条件
========

* [JAWS-UG CLI] 総合案内: http://qiita.com/tcsh/items/14c3278f69ab073afe0f を確認して、必要な手順を終えていること。

S3への権限
----------------------

S3に対してフルアクセス権限があること。


AWS CLIのバージョン
-------------------

以下のバージョンで動作確認済

* AWS CLI 1.10.1
* AWS CLI 1.7.39
* AWS CLI 1.7.12

```bash:コマンド:
aws --version
```

```text:結果(例):
aws-cli/1.10.1 Python/2.7.5 Darwin/13.4.0 botocore/1.3.23
```



0. 準備
=======

0.1. リージョンの決定
---------------------

```bash:変数の設定:
export AWS_DEFAULT_REGION='ap-northeast-1'
```


0.2. 変数の確認
---------------

```bash:変数の確認:
aws configure list
```

```text:結果(例):
            Name                    Value             Type    Location
            ----                    -----             ----    --------
         profile        s3Full-prjZ-mbp13              env    AWS_DEFAULT_PROFILE
      access_key     ****************LOAQ shared-credentials-file
      secret_key     ****************I1O1 shared-credentials-file
          region           ap-northeast-1              env    AWS_DEFAULT_REGION
```

AssumeRoleを利用している場合はprofileが '\<not set\>'と表示されます。
それ以外のときにprofileが '\<not set\>'  と表示される場合は、以下を実行してください。

```bash:コマンド:
export AWS_DEFAULT_PROFILE=<IAMユーザ名>
```


0.3. コンテンツの公開
---------------------

http://qiita.com/tcsh/items/70694da357c1738c6bf8 (ハイレベルS3コマンドで静的Webホスティング)の手順を実施しておいてください。


1. 事前作業
=============

## 1.1. AWSアカウント(メールアドレス)の指定

```bash:変数の設定:
AWS_ACCOUNT='example@example.jp'
```


1.2. 対象バケットの決定
----------------------

${S3_BUCKET_NAME}に、静的コンテンツのバケット名が定義されていることを確認してください。

```bash:コマンド:
S3_BUCKET_NAME=<バケット名>
```

```bash:コマンド:
aws s3 ls s3://${S3_BUCKET_NAME}/
```

```text:結果(例)
example-handson-20160201
```


# 2. [ログ用バケット] 作成

まず最初に、ログ保存用のバケットの作成とACL設定をします。

```bash:変数の確認:
cat << ETX

  AWS_DEFAULT_REGION: ${AWS_DEFAULT_REGION}
  S3_BUCKET_NAME: ${S3_BUCKET_NAME}

ETX
```

```bash:コマンド:
aws s3api create-bucket \
  --create-bucket-configuration LocationConstraint=${AWS_DEFAULT_REGION} \
  --bucket accesslog-${S3_BUCKET_NAME}
```

```json:結果(例):
{
  "Location": "http://accesslog-example-handson-20160201.s3.amazonaws.com/"
}
```

```bash:コマンド:
aws s3api get-bucket-location \
  --bucket ${S3_BUCKET_NAME}
```

```json:結果(例):
{
    "LocationConstraint": "ap-northeast-1"
}
```

# 2. [ログ用バケット] ACL設定

* http://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/WhenToUseACLvsBucketPolicy.html

  * ACL は大まかなアクセス許可モデルを提供し、単純にバケットまたはオブジェクトへのアクセス許可を付与します。


* http://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/ACLOverview.html

  * 1 つの ACL には最大 100 個の許可を指定することができます。


## 2.1. ACL設定(デフォルト)の確認

バケットを作成したら、ACLを確認してみましょう。

```bash:コマンド:
aws s3api get-bucket-acl \
  --bucket accesslog-${S3_BUCKET_NAME}
```

```json:結果(例):
{
    "Owner": {
        "DisplayName": "example", 
        "ID": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    }, 
    "Grants": [
        {
            "Grantee": {
                "DisplayName": "example", 
                "ID": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
            }, 
            "Permission": "FULL_CONTROL"
        }
    ]
}
```

管理者にフル制御の権限が割り当てられていますが、それ以外のリソースからはアクセスできない状態になっています。



## 2.2. ACLの変更

S3のログが書き込めるようにACLの設定を変更します。

```bash:変数の確認:
cat << ETX

  S3_BUCKET_NAME: ${S3_BUCKET_NAME}

ETX
```

```bash:コマンド:
aws s3api put-bucket-acl \
  --bucket accesslog-${S3_BUCKET_NAME} \
  --grant-write 'URI="http://acs.amazonaws.com/groups/s3/LogDelivery"' \
  --grant-read-acp 'URI="http://acs.amazonaws.com/groups/s3/LogDelivery"' \
  --grant-full-control "EmailAddress=${AWS_ACCOUNT}"
```

```text:結果:
(戻り値なし)
```


## 2.3. ACLの確認

変更をしたら、ACLの内容を確認します。


```bash:コマンド:
aws s3api get-bucket-acl \
  --bucket accesslog-${S3_BUCKET_NAME}
```

```json:結果(例):
{
    "Owner": {
        "DisplayName": "example", 
        "ID": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    }, 
    "Grants": [
        {
            "Grantee": {
                "DisplayName": "example", 
                "ID": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
            }, 
            "Permission": "FULL_CONTROL"
        },
        {
            "Grantee": {
                "URI": "http://acs.amazonaws.com/groups/s3/LogDelivery"
            }, 
            "Permission": "WRITE"
        }, 
        {
            "Grantee": {
                "URI": "http://acs.amazonaws.com/groups/s3/LogDelivery"
            }, 
            "Permission": "READ_ACP"
        }
    ]
}
```

* S3のログについて、バケットへの書き込み(WRITE)およびACL情報の読み取り(READ_ACP)が許可されていることがわかります。

  * log-delivery-write(既定ACL)と同じ設定


# 3. [コンテンツ用バゲット] ログ保存設定

## 3.1. 設定ファイルの作成

```bash:変数の設定:
FILE_S3_LOGGING='s3-logging.json'
```

```bash:変数の確認:
cat << ETX

  FILE_S3_LOGGING: ${FILE_S3_LOGGING}
  S3_BUCKET_NAME: ${S3_BUCKET_NAME}
  AWS_ACCOUNT: ${AWS_ACCOUNT}

ETX
```

```bash:コマンド:
cat << EOF > ${FILE_S3_LOGGING}
{
  "LoggingEnabled": {
    "TargetBucket": "accesslog-${S3_BUCKET_NAME}",
    "TargetPrefix": "Logs/",
    "TargetGrants": [
      {
        "Grantee": {
          "Type": "AmazonCustomerByEmail",
          "EmailAddress": "${AWS_ACCOUNT}"
        },
        "Permission": "FULL_CONTROL"
      },
      {
        "Grantee": {
          "Type": "Group",
          "URI": "http://acs.amazonaws.com/groups/global/AllUsers"
        },
        "Permission": "READ"
      }
    ]
  }
}
EOF

cat ${FILE_S3_LOGGING}
```



```json:s3-logging.json(sample):
{
  "LoggingEnabled": {
    "TargetBucket": "accesslog-example-01",
    "TargetPrefix": "Logs/",
    "TargetGrants": [
      {
        "Grantee": {
          "Type": "AmazonCustomerByEmail",
          "EmailAddress": "example@example.jp"
        },
        "Permission": "FULL_CONTROL"
      },
      {
        "Grantee": {
          "Type": "Group",
          "URI": "http://acs.amazonaws.com/groups/global/AllUsers"
        },
        "Permission": "READ"
      }
    ]
  }
}
```

JSONファイルを作成したら、フォーマットが壊れてないか必ず確認します。

```bash:コマンド:
jsonlint -q ${FILE_S3_LOGGING}
```

```text:結果:
(戻り値なし)
```


## 3.2. ログ設定

```bash:変数の確認:
cat << ETX

  S3_BUCKET_NAME: ${S3_BUCKET_NAME}
  FILE_S3_LOGGING: ${FILE_S3_LOGGING}

ETX
```

```bash:コマンド:
aws s3api put-bucket-logging \
  --bucket ${S3_BUCKET_NAME} \
  --bucket-logging-status file://${FILE_S3_LOGGING}
```

```text:結果:
(戻り値なし)
```


## 3.3. ログ設定の確認

```bash:コマンド:
aws s3api get-bucket-logging \
  --bucket ${S3_BUCKET_NAME}
```


```json:結果(例):
{
    "LoggingEnabled": {
        "TargetPrefix": "Logs/", 
        "TargetBucket": "accesslog-example-handson-20160201", 
        "TargetGrants": [
            {
                "Grantee": {
                    "DisplayName": "example", 
                    "ID": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
                }, 
                "Permission": "FULL_CONTROL"
            }, 
            {
                "Grantee": {
                    "URI": "http://acs.amazonaws.com/groups/global/AllUsers"
                }, 
                "Permission": "READ"
            }
        ]
    }
}
```


## 3.4. コンテンツにアクセスする。

Webブラウザで、コンテンツにアクセスしてみましょう。

```bash:コマンド:
S3_BUCKET_ENDPOINT="${S3_BUCKET_NAME}.s3-website-`aws s3api get-bucket-location --bucket ${S3_BUCKET_NAME} --output text`.amazonaws.com" \
        && echo ${S3_BUCKET_ENDPOINT}
```

```text:結果(例):
example-handson-20160201.s3-website-ap-northeast-1.amazonaws.com
```

Webブラウザで EndPoint が開くと、アクセスログが書き込まれます。



## 3.5. ログ保存の確認

30分から1時間ほど待つと、15分前までのログが書き出されているはずです。

```bash:コマンド:
aws s3 ls s3://accesslog-${S3_BUCKET_NAME}/
```

```text:結果(例):
                           PRE Logs/
```

```bash:コマンド:
aws s3 ls s3://accesslog-${S3_BUCKET_NAME}/Logs/
```

```text:結果(例):
2014-08-24 18:23:27        290 2014-08-24-09-23-26-XXXXXXXXXXXXXXXX
2014-08-24 18:24:12        292 2014-08-24-09-24-11-YYYYYYYYYYYYYYYY
```


* ログはベストエフォート設計のため、全てのアクセスが記録される保証は無いようです。

  * http://docs.aws.amazon.com/AmazonS3/latest/dev/ServerLogs.html



# 4. [ログ用バケット] ログアーカイブの設定

## 4.1. 設定ファイルの作成

```bash:コマンド::
FILE_S3_LIFECYCLE='s3-lifecycle.json'
S3_LIFECYCLE_EXPIRE_DAYS='6000'
S3_LIFECYCLE_TRANS_DAYS='3000'
S3_LIFECYCLE_ID="accesslog-${S3_BUCKET_NAME}-Log-Archive"
```

* S3_LIFECYCLE_IDは、Lifecycle RulesのRule Nameになります。(マネジメントコンソール上ではオプション扱い)

```bash:変数の確認:
cat << ETX

  FILE_S3_LIFECYCLE:        ${FILE_S3_LIFECYCLE}
  S3_LIFECYCLE_EXPIRE_DAYS: ${S3_LIFECYCLE_EXPIRE_DAYS}
  S3_LIFECYCLE_ID:          ${S3_LIFECYCLE_ID}
  S3_LIFECYCLE_TRANS_DAYS:  ${S3_LIFECYCLE_TRANS_DAYS}

ETX
```

```bash:コマンド:
cat << EOF > ${FILE_S3_LIFECYCLE}
{
  "Rules": [
    {
      "Expiration": {
        "Days": ${S3_LIFECYCLE_EXPIRE_DAYS}
      },
      "ID": "${S3_LIFECYCLE_ID}",
      "Prefix": "Logs/",
      "Status": "Enabled",
      "Transition": {
        "Days": ${S3_LIFECYCLE_TRANS_DAYS},
        "StorageClass": "GLACIER"
      }
    }
  ]
}
EOF
```

```json:s3-lifecycle.json
{
  "Rules": [
    {
      "Expiration": {
        "Days": 60
      },
      "ID": "accesslog-example-handson-20160201-Log-Archive",
      "Prefix": "Logs/",
      "Status": "Enabled",
      "Transition": {
        "Days": 30,
        "StorageClass": "GLACIER"
      }
    }
  ]
```

JSONファイルを作成したら、フォーマットが壊れてないか必ず確認します。

```bash:コマンド:
jsonlint -q ${FILE_S3_LIFECYCLE}
```

```text:結果:
(戻り値なし)
```


## 4.2. ログアーカイブの設定

```bash:変数の確認:
cat << ETX

  S3_BUCKET_NAME:    ${S3_BUCKET_NAME}
  FILE_S3_LIFECYCLE: ${FILE_S3_LIFECYCLE} 

ETX
```

```bash:コマンド:
aws s3api put-bucket-lifecycle \
  --bucket accesslog-${S3_BUCKET_NAME} \
  --lifecycle-configuration file://${FILE_S3_LIFECYCLE}
```

```text:結果:
(戻り値なし)
```


## 4.3. ログアーカイブ設定の確認

```bash:コマンド:
aws s3api get-bucket-lifecycle \
  --bucket accesslog-${S3_BUCKET_NAME}
```


```json:結果(例):
{
    "Rules": [
        {
            "Status": "Enabled", 
            "Prefix": "Logs/", 
            "Transition": {
                "Days": 30, 
                "StorageClass": "GLACIER"
            }, 
            "Expiration": {
                "Days": 60
            }, 
            "ID": "accesslog-example-handson-20160201-Log-Archive"
        }
    ]
}
```


完了
=====