データ活用基盤を作ってみたその９(構築・データ蓄積-S3)

## はじめに
こんにちは。NTTデータ先端技術の@EumJinmanです。
本記事は、データ活用基盤を作ってみた連載記事のその９(構築・データ蓄積-S3)です。
本シリーズの取り組みの内容については[その１(構成シナリオ)](https://qiita.com/kamein/items/81df29ef9d32bf0a0810)をご覧ください。
前の記事は、[その８(構築・データ収集-Lambda)](https://qiita.com/tsuchidahrk/items/92cee4db92d68010e3c9)からご覧ください。
今回は、データ活用基盤のストレージの設計、構築方法、注意点について記載します。
※S3に対するアクセスポリシーは[その７(構築・IAM)](https://qiita.com/fujitak-intellilink/items/4c4d5b62dac2d7b4d39f)に記載しております。

## 目次
・ ストレージ設計
・ 構築方法
・ 注意点
・ 最後に

## ストレージ設計
データ活用基盤を構築し、データを活用するために欠かせないストレージの設計について紹介します。
本システムではシステム内で定めた機能・非機能要望を満たすためにAWS上のストレージ容量に制限のないAmazon Simple Storage Service (S3)を利用しており、大きく以下4種類に分割しています。

　①データ加工用バケット：元データ、活用データを格納するバケット。
　②監査ログ用バケット：監査ログ用のデータを格納するバケット。
　③監査レポート用バケット：AuditManagerで作成した監査レポートを格納するバケット。
　④リソース監視用バケット：リソース設定や監視などリソース状況を記録するバケット。
　⑤Athenaの結果出力用バケット：Athenaのクエリ実行結果を格納するバケット。

以上の分割方針に則り、作成したバケットは以下の通りになります。

![qiita_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821879/6f1d2734-ac72-9c14-bb77-295df7918712.png)
※本システムはシングルリージョン構成のためバケットの作成リージョンはすべて<b>東京リージョン</b>になります。

## 構築方法
今回作成しているバケットリソースはTerraformを用いたInfrastructure as Code（IaC）で作成しています。以下に作成したTerraform構成ファイル（storage.tf）の内容について記載します。

#### S3バケット作成（storage.tf）
ストレージ設計を基に各バケットリソースを作成します。

```terraform:storage.tf
#データ加工用バケット（加工前）
resource "aws_s3_bucket" "biwa-prod-s3-bucket-datastorage-001" {
  bucket = "biwa-prod-s3-bucket-datastorage-001"
  force_destroy = true
}

#データ加工用バケット（加工後）
resource "aws_s3_bucket" "biwa-prod-s3-bucket-datastorage-002" {
  bucket = "biwa-prod-s3-bucket-datastorage-002"
  force_destroy = true
}

#監査ログ用バケット
resource "aws_s3_bucket" "biwa-prod-s3-bucket-audit-001" {
  bucket = "biwa-prod-s3-bucket-audit-001"
  force_destroy = true
  
  object_lock_enabled = true
}

#監査レポート用バケット（AuditManager）
resource "aws_s3_bucket" "biwa-prod-s3-bucket-auditmanager-001" {
  bucket = "biwa-prod-s3-bucket-auditmanager-001"
  force_destroy = true
}

#リソース確認用バケット（CloudWatch）
resource "aws_s3_bucket" "biwa-prod-s3-bucket-cloudwatch-001" {
  bucket = "biwa-prod-s3-bucket-cloudwatch-001"
  force_destroy = true
}

#Athenaの結果出力用バケット
resource "aws_s3_bucket" "biwa-prod-s3-bucket-athena-001" {
  bucket = "biwa-prod-s3-bucket-athena-001"
  force_destroy = true
}
```

#### ライフサイクル設定（storage.tf）
バケットのライフサイクルを設定する<b>「lifecycle_rule」</b>属性が廃止されてしまい、バケット作成時にライフサイクルルールを設定することができなくなったのでバケット作成とは別途リソース<b>「aws_s3_bucket_lifecycle_configuration」</b>を作成しルールを設定する必要があります。

```terraform:storage.tf
#データ加工用バケット（加工前）_ライフサイクル設定
resource "aws_s3_bucket_lifecycle_configuration" "biwa-prod-s3-bucket-datastorage-001_lifecycle" {
  bucket = aws_s3_bucket.biwa-prod-s3-bucket-datastorage-001.id

  rule {
    id     = "rule_1"
    status = "Enabled"

    expiration {
      days = 7
    }
  }
}

#データ加工用バケット（加工後）_ライフサイクル設定
resource "aws_s3_bucket_lifecycle_configuration" "biwa-prod-s3-bucket-datastorage-002_lifecycle" {
  bucket = aws_s3_bucket.biwa-prod-s3-bucket-datastorage-002.id

  rule {
    id     = "rule_1"
    status = "Enabled"

    expiration {
      days = 32
    }
  }
}

#監査ログ用バケット_ライフサイクル設定
resource "aws_s3_bucket_lifecycle_configuration" "biwa-prod-s3-bucket-audit-001_lifecycle" {
  bucket = aws_s3_bucket.biwa-prod-s3-bucket-audit-001.id

  rule {
    id     = "rule_1"
    status = "Enabled"

        transition {
      days          = 32
      storage_class = "GLACIER"
    }

    expiration {
      days = 365
    }
  }
}

#監査レポート用バケット（AuditManager）_ライフサイクル設定
resource "aws_s3_bucket_lifecycle_configuration" "biwa-prod-s3-bucket-auditmanager-001_lifecycle" {
  bucket = aws_s3_bucket.biwa-prod-s3-bucket-auditmanager-001.id

  rule {
    id     = "rule_1"
    status = "Enabled"

    expiration {
      days = 32
    }
  }
}

#リソース確認用バケット（CloudWatch）_ライフサイクル設定
resource "aws_s3_bucket_lifecycle_configuration" "biwa-prod-s3-bucket-cloudwatch-001_lifecycle" {
  bucket = aws_s3_bucket.biwa-prod-s3-bucket-cloudwatch-001.id

  rule {
    id     = "rule_1"
    status = "Enabled"

    expiration {
      days = 32
    }
  }
}

#Athenaの結果出力用バケット_ライフサイクル設定
resource "aws_s3_bucket_lifecycle_configuration" "biwa-prod-s3-bucket-athena-001_lifecycle" {
  bucket = aws_s3_bucket.biwa-prod-s3-bucket-athena-001.id

  rule {
    id     = "rule_1"
    status = "Enabled"

    expiration {
      days = 7
    }
  }
}
```
#### オブジェクトロックの設定（storage.tf）
監査ログ用バケットについては一定期間オブジェクトが削除または上書きされることを防止するためにオブジェクトロック設定をする必要があります。オブジェクトロックの設定についてもライフサイクルルールと同じく<b>「object_lock_configuration」</b>属性が廃止されてしまい、バケット作成時にオブジェクトロックを設定することができなくなりました。対処法としてはライフサイクルルールと同じく別途リソース<b>「aws_s3_bucket_object_lock_configuration」</b>を作成し設定する必要があります。

```terraform:storage.tf
#監査ログ用バケット_オブジェクトロック設定
resource "aws_s3_bucket_object_lock_configuration" "biwa-prod-s3-bucket-audit-001_object_lock" {
  bucket = aws_s3_bucket.biwa-prod-s3-bucket-audit-001.id

  rule {
    default_retention {
      mode = "GOVERNANCE"
      days = 365
    }
  }
}
```
#### S3の暗号化方式（storage.tf）
Amazon S3ではサーバ側のデータを安全に保管するためにデフォルトで暗号化（SSE-S3）が適用されていますが、今回はデフォルトの暗号化ではなくAWS Key Management Service に保存されている<b>KMSキーによるサーバー側の暗号化（SSE-KMS）</b>を利用します。
※SSE-KMSで利用するKMSキーはデフォルトのものではなく、追加で作成するカスタマーマネージドキーを指定します。

```terraform:security.tf
# KMS
resource "aws_kms_key" "biwa-prod-kms-key-s3bucket-001" {
  description             = "This key is used to encrypt bucket objects"
  #deletion_window_in_days = 10
}

#それぞれのS3バケットにKMS暗号化を設定する
resource "aws_s3_bucket_server_side_encryption_configuration" "biwa-prod-s3-sseconfig-datastore-001" {
  bucket = aws_s3_bucket.biwa-prod-s3-bucket-datastorage-001.id

  rule {
    apply_server_side_encryption_by_default {
      kms_master_key_id = aws_kms_key.biwa-prod-kms-key-s3bucket-001.arn
      sse_algorithm     = "aws:kms"
    }
    bucket_key_enabled = "true"
  }
}

resource "aws_s3_bucket_server_side_encryption_configuration" "biwa-prod-s3-sseconfig-datastore-002" {
  bucket = aws_s3_bucket.biwa-prod-s3-bucket-datastorage-002.id

  rule {
    apply_server_side_encryption_by_default {
      kms_master_key_id = aws_kms_key.biwa-prod-kms-key-s3bucket-001.arn
      sse_algorithm     = "aws:kms"
    }
    bucket_key_enabled = "true"
  }
}

resource "aws_s3_bucket_server_side_encryption_configuration" "biwa-prod-s3-sseconfig-audit-001" {
  bucket = aws_s3_bucket.biwa-prod-s3-bucket-audit-001.id

  rule {
    apply_server_side_encryption_by_default {
      kms_master_key_id = aws_kms_key.biwa-prod-kms-key-s3bucket-001.arn
      sse_algorithm     = "aws:kms"
    }
    bucket_key_enabled = "true"
  }
}

resource "aws_s3_bucket_server_side_encryption_configuration" "biwa-prod-s3-sseconfig-auditmanager-001" {
  bucket = aws_s3_bucket.biwa-prod-s3-bucket-auditmanager-001.id

  rule {
    apply_server_side_encryption_by_default {
      kms_master_key_id = aws_kms_key.biwa-prod-kms-key-s3bucket-001.arn
      sse_algorithm     = "aws:kms"
    }
    bucket_key_enabled = "true"
  }
}

resource "aws_s3_bucket_server_side_encryption_configuration" "biwa-prod-s3-sseconfig-cloudwatch-001" {
  bucket = aws_s3_bucket.biwa-prod-s3-bucket-cloudwatch-001.id

  rule {
    apply_server_side_encryption_by_default {
      kms_master_key_id = aws_kms_key.biwa-prod-kms-key-s3bucket-001.arn
      sse_algorithm     = "aws:kms"
    }
    bucket_key_enabled = "true"
  }
}

resource "aws_s3_bucket_server_side_encryption_configuration" "biwa-prod-s3-sseconfig-athena-001" {
  bucket = aws_s3_bucket.biwa-prod-s3-bucket-athena-001.id

  rule {
    apply_server_side_encryption_by_default {
      kms_master_key_id = aws_kms_key.biwa-prod-kms-key-s3bucket-001.arn
      sse_algorithm     = "aws:kms"
    }
    bucket_key_enabled = "true"
  }
}
```
## 注意点
上記[3 構築方法](#3-構築方法)で説明したライフサイクルルールや、オブジェクトロックの設定以外にも多くの属性が廃止されています。（バージョン管理（versioning）、ロギング（logging）など）S3に限らず<b>Terraformで構成ファイルを作成する際には必ずTerraform公式サイトから最新の情報を確認しIaCを作成する必要がある</b>ことに注意してください。

## 最後に
今回はストレージの設計や、TerraformのIaCを用いてS3リソースを作成する方法について紹介しました。Terraformは短いスパンでバージョンアップされており、コードの書き方が進化しているのでコードを作成する際には公式サイトで最新の情報を確認した上で作成してください。
次の記事は[その１０(構築・データ加工-Glue）](https://qiita.com/shiraki_ils/items/0f8ff256f230d85275d6)です。
最後までお読みいただきありがとうございました。