【AWS】TerraformでS3バケットを構築してみる
新年あけましておめでとうございます
スキルゼロの監視オペレータ(今年からWebエンジニアにジョブチェンジします)です。
今年は厳しい1年になるかもですので、糞ほど勉強してスキル向上に努めて、より良い1年にしたいと思います。
この記事で何をするか
AWSの基本的なサービスや操作を理解するためにAWSアソシエイト
を勉強しています。
ただUdemyの動画や本を読んでいてもつまらないなと思い、インフラ構成管理ツールのTerraform
と平行で勉強している最中です
前回は、VPC構築〜EC2構築までをやっていましたが今回はS3を作成したいと思います。
大まかな記事の流れは下記です。
- S3の基礎知識
- よくある本とかWebで入手できる内容を自分用にまとめたものです
- Terraformでバケット(パブリックアクセス無し)作成
- Terraformでバケット(パブリックアクセス有り)作成
- HTMLファイルをホスティングしてアクセスできる事を確認します。
この記事で得られるもの
- S3って何か、基本的なサービスについて理解できる
- Terraformを使って、S3バケットを構築することができる
S3の基礎知識
そもそもS3って?
AWSが、マネージド型で提供しているストレージサービスです。
S3以外のストレージサービスにはEBS,インスタンスストア
やEFS
などがありますが、今回のS3はオブジェクト型
のストレージとなります。
各ストレージの特徴を簡単にまとめました。
ストレージタイプ | AWSサービスの例 | 特徴 | プロトコル |
---|---|---|---|
ブロック型 | EBS、インスタンスストア | 保存されるファイルやオブジェクトのデータを複数のブロックに分散する。頻繁かつ高速なアクセスが必要な場合の用途 | SATA, SCSI |
オブジェクト型 | S3 | ファイルに任意のメタデータを追加してオブジェクトとして管理する。作成済みデータに対するCRD(Create, Read, Delete)のみが可能 | HTTP(S) |
ファイル型 | EFS | ブロックストレージ上にファイルシステムを構築。複数クライアントからNW経由でファイルアクセスするデータ共有など。ファイルサーバ的なやつ | NFS |
何が特徴的なのか?
- 高い耐久性(イレブンナイン)と可用性(99.99%)
- ストレージクラスが
STANDARD
の場合 - S3作成時にリージョンを選択するが、S3は3箇所以上のAZに同期される
- ストレージクラスが
- HTTP(S)を利用して、AWS CLIやWEB APIから操作が可能
結果整合性モデル
を採用している- 更新・削除の結果が反映されるまで時間がかかる(
Eventual Consistency Read
) - 新規登録は即時にデータが反映される(
Consistency Read
)
- 更新・削除の結果が反映されるまで時間がかかる(
何が保存されるのか?
データ(オブジェクト)は指定したリージョンのバケット(データの入れ物)に保存されます。
- バケット
オブジェクト
- S3に格納されるデータ本体。
- 各オブジェクトにはキー(オブジェクト名)が付与され、「バケット名+キー名+バージョンID」で必ず一意なURLが作成される
-
- オブジェクトを管理するための情報
- オブジェクトの作成日時やサイズなどのメタデータやアプリケーションが必要な情報(ユーザ定義)が保持できる
- バージョンID
S3の機能
ここからはバージョン管理やライフサイクルなどのS3で使える機能群を簡単にまとめていきます。
アクセス管理
S3のバケット(もしくはオブジェクト)に対するアクセス管理には、3種類が存在します
{ "Version":"2012-10-17", "Statement":[ { "Sid":"PublicRead", "Effect":"Allow", "Principal": "*", "Action":["s3:GetObject"], "Resource":["arn:aws:s3:::examplebucket/*"] } ] }
IAMポリシー
-
- 各バケット/オブジェクトごとに付与された対象のアクセスを制御できる
暗号化
S3に保存するデータを暗号化して保存することができる
- サーバサイド暗号化
- S3のサーバリソースを利用して格納データを暗号化
- クライアントサイド暗号化
レプリケーション
バケット内のデータを異なる(もしくは同一の別AZ)のバケットにレプリケーション(同期)することが可能
バックアップやBCP用途に使うことができる
バージョン管理
バケット単位で有効
もしくは無効
を管理する
ライフサイクル管理
バケットに保存されたオブジェクトの利用頻度に基づいてライフサイクルを管理できる。
ライフサイクル管理によって、
- 古いデータはより安く保存できるストレージサービス(Glacier)に保存する
- それよりも古いデータは削除する
といったことができるようになる。
移行アクション
- データの利用頻度に応じて、ストレージクラスを変更するアクション
- 一定期間がすぎると利用頻度が低くなるオブジェクトをアーカイブとして保存するなど
- データの利用頻度に応じて、ストレージクラスを変更するアクション
有効期限アクション
- 指定された期限を超えたオブジェクトをS3から削除する
- S3は保存容量に応じて課金されるため、不要なデータを削除することでコスト削減が見込める
ホスティング
静的コンテンツ(HTML, 画像や動画, Javascript)をバケット内に保管して、Webサイトとしてホスティングさせることができる。
独自ドメインでホスティングする場合にはバケット名とドメイン名を一致させる必要がある
Terraformでバケットを作成する
本記事で扱っていない機能だとかオプションは公式を参照してください。
https://www.terraform.io/docs/providers/aws/r/s3_bucket.html
下準備
- バケットポリシーも設定しいきたいので、IAMユーザを作成しておきます。
- ポリシーは何もアタッチしていない状態。
aws iam list-users \ > --query 'Users[].UserName' [ Your User Name, "unauthorize-user" ] aws iam list-attached-user-policies \ > --user-name 'unauthorize-user' { "AttachedPolicies": [] }
パブリックアクセス無しのバケットを作成
作成するバケットの要件は下記とします。
- ログ保管用とデータ保管用のバケット2つを作成する
- バケットは共に外部(インターネット)に公開しない
- バケットにCRDできるのは、作成してユーザ(上で言うところのYour User Name)のみ
- unauthorize-userからはアクセスできないことを確認する
実装コード
ログ保管用バケット
- リソースは
aws_s3_bucket
で作成ができる bucket
はバケット名を指定する- 前述だが、グローバルで一意な名前でなければならない
acl
はバケットへのACLを設定log-delivery-write
でログの書き込みができるはず
lifecycle_rule
では、有効期限アクションを設定
############################################## # Create Log Backet for Private Bucket # ############################################## resource "aws_s3_bucket" "logging_for_sapmle_private_bucket" { bucket = "logging-for-private-turedure-study-bucket" acl = "log-delivery-write" lifecycle_rule { enabled = true expiration { days = "180" } } }
データ保管用のバケット
重複している部分の説明は割愛します。
versioning
でバージョニングを有効化server_side_encryption_configuration
でサーバサイド暗号化を有効化logging
で上で作成したバケットにログを記録するように設定- 別リソース
aws_s3_bucket_public_access_block
でパブリックへオブジェクトが公開されることを防止
############################################## # Create Private Bucket # ############################################## resource "aws_s3_bucket" "sample_private_bucket" { bucket = "private-turedure-study-bucket" versioning { enabled = true } server_side_encryption_configuration { rule { apply_server_side_encryption_by_default { sse_algorithm = "AES256" } } } logging { target_bucket = "${aws_s3_bucket.logging_for_sapmle_private_bucket.id}" target_prefix = "log/" } } resource "aws_s3_bucket_public_access_block" "for_sample_private_bucket" { bucket = "${aws_s3_bucket.sample_private_bucket.id}" block_public_acls = true block_public_policy = true ignore_public_acls = true restrict_public_buckets = true }
結果確認
terraform plan
~terraform apply
を実行後にバケットの一覧を取得してみると作成ができている
aws s3 ls 2020-01-04 16:20:39 logging-for-private-turedure-study-bucket 2020-01-04 16:20:56 private-turedure-study-bucket
- 続いてファイルをアップロードしてみる
aws s3 cp ./sample.txt s3://private-turedure-study-bucket upload: ./sample.txt to s3://private-turedure-study-bucket/sample.txt aws s3 ls s3://private-turedure-study-bucket 2020-01-04 16:24:37 20 sample.txt
aws s3 ls s3://private-turedure-study-bucket --profile terraform An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
試しに作成したバケットの設定は上手くいってるみたいです。
下準備で作成したユーザがアクセスできるようにバケットポリシーを作成していこうと思います。
バケットポリシーを作成
新しくリソースaws_s3_bucket_policy
を作成して、バケットポリシーをアタッチをしていきます。
resource "aws_s3_bucket_policy" "private_bucket_policy" { bucket = "${aws_s3_bucket.sample_private_bucket.id}" policy =<<POLICY { "Version": "2012-10-17", "Id": "PrivateBucketPolicy", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::{作成したユーザのARN}" }, "Action": "S3:ListBucket", "Resource": "${aws_s3_bucket.sample_private_bucket.arn}" } ] } POLICY }
terraform plan
からterraform apply
をもう一度実行して、S3のオブジェクトを取得ができている
aws s3 ls s3://private-turedure-study-bucket --profile terraform 2020-01-04 16:24:37 20 sample.txt
プライベートバケットの作成ハンズオンはここで終わり!
バケット(パブリックアクセス有り)作成
HTMLをホスティングしてインターネットから参照できるバケットを作成します。
先ほどとほぼ同じではあるが、作成するバケットの要件は下記とします。
ホスティング用のバケット
ログ保管用のバケットは先ほどとほぼ同じなので割愛します
website
でホスティングサービスを有効化index_document
でデフォルトルートのオブジェクトを指定error_document
で400番系のエラーが発生した際に表示するオブジェクトを指定する
- バケットポリシーは、AWSの公式ドキュメントをそのまま設定
############################################## # Create Public Bucket # ############################################## resource "aws_s3_bucket" "hosting_bucket" { bucket = "hosting-turedure-study-bucket" versioning { enabled = true } acl = "public-read" website { index_document = "index.html" error_document = "error.html" } } resource "aws_s3_bucket_policy" "hosting_bucket_policy" { bucket = "${aws_s3_bucket.hosting_bucket.id}" policy = <<POLICY { "Version": "2012-10-17", "Id": "HostingPolicy", "Statement": [ { "Sid": "PubcliReadForGetBucketObjects", "Effect": "Allow", "Principal": "*", "Action": ["s3:GetObject"], "Resource": "${aws_s3_bucket.hosting_bucket.arn}/*" } ] } POLICY }
terraform apply
後にindex.htmlとerror.htmlをバケットに配置
aws s3 cp index.html s3://hosting-turedure-study-bucket upload: ./index.html to s3://hosting-turedure-study-bucket/index.html aws s3 cp error.html s3://hosting-turedure-study-bucket upload: ./error.html to s3://hosting-turedure-study-bucket/error.html
- curlで
index.html
とerror.html
表示できることが確認できる
curl http://hosting-turedure-study-bucket.s3-website-ap-northeast-1.amazonaws.com/ <!doctype html> <html lang="ja"> <head> <title>Sample Hosting</title> </head> <body> <h1>This is Sample Hosting Page </h1> </body> </html> curl http://hosting-turedure-study-bucket.s3-website-ap-northeast-1.amazonaws.com/error <!doctype html> <html lang="ja"> <head> <title>Sample Hosting</title> </head> <body> <h1>Sorry, error is occured</h1> </body> </html>
まとめ
新年一発目の投稿がこれで終わりです。
(実用的な記事を投稿するにはまだまだ文章力や知識も足りていなくて自己嫌悪ですね。。)