terraformでお手軽に静的サイトを公開

Bullet Group Advent Calendar 2020 19日目の記事です。

こんにちは!SREチームたかはしです!

栄えあるアドベントカレンダーの19日目、どんな記事を書かせて頂こうか悩みましたが「terraformで s3 + cloudfront を構築し、静的サイトを公開する方法」をご紹介したいと思います!
こちら以前自分が業務上で行ったことなのですが、とてもとても楽に環境構築 & サイト公開までできて感動しました。
簡単なポートフォリオサイトの公開などで使用することもあるかと思いますので、皆さんにもお試しいただければと思います。

前提

  • pcにterraformがインストール済み(もしまだインストールされていない場合はこちらの記事を参考にインストールをお願いします)
  • AWSアカウントは作成済み

以上を前提に手順を説明していきます!

手順

AWSコンソールにて

IAMユーザーの作成

  • IAMコンソールに遷移
  • サイドバー"ユーザー" より "ユーザーを追加" をクリック
    f:id:Takahashi_Blt:20201217192155p:plain
  • 任意のユーザー名を設定
  • アクセスの種類 : プログラムによるアクセス を選択
  • 次のステップ をクリック
  • アクセス許可の設定 より 既存のポリシーを直接アタッチ 選択
  • AdministratorAccessをチェック
  • 次のステップ をクリック
  • タグの追加任意のタグを設定
  • 確認後、ユーザーの作成をクリック

これで、アクセスキー/シークレットキーの取得ができるので保存してください
AWSコンソールでの作業はいったん以上です!

ローカルにて

terraformファイルの作成

まずはこちらのAWSドキュメントを参考に、~/.aws/credentialsに先ほどのキー情報を登録してください

その後、任意のディレクトリを作成(自分はterraform-awsとしました)し、
作成したディレクトリ内にvariables.tfファイルを作成してください。
このファイルでは、Terraformで使うプロバイダーの設定をします。
プロバイダーとはインフラを管理する対象プラットフォームのことです。
今回はAWSを利用しますので、AWS用のプロバイダー設定を記述します。

ファイルの中身は下記のように記述してください。

provider "aws" {
  version = "~> 2.0"
  region  = "ap-northeast-1"
}

同じようにterraform-aws配下にresouce.tfファイルを作成してください。
ここにはAWSクラウド上に作成したいリソースを記述します。

基本的にこちらのコピペで大丈夫ですが、 default_root_object ではCloudFrontのデフォルトルートオブジェクトを指定できます。 自分はindex.htmlとしていますが、任意のものをしてしてください。

#s3
resource "aws_s3_bucket" "image-bucket" {
  bucket = "20201219"
  acl    = "private"
  region = "ap-northeast-1"
}

#cloudfront
resource "aws_cloudfront_origin_access_identity" "origin_access_identity" {
  comment = "origin access identity for s3"
}


resource "aws_cloudfront_distribution" "s3_distribution" {
  origin {
    domain_name = "${aws_s3_bucket.image-bucket.bucket_regional_domain_name}"
    origin_id   = "${aws_s3_bucket.image-bucket.id}"

    s3_origin_config {
      origin_access_identity = "${aws_cloudfront_origin_access_identity.origin_access_identity.cloudfront_access_identity_path}"
    }
  }

  enabled         = true
  is_ipv6_enabled = false
  default_root_object = "index.html"

  logging_config {
    include_cookies = false
    bucket          = "${aws_s3_bucket.image-bucket.bucket_domain_name}"
    prefix          = "prefix"
  }

  default_cache_behavior {
    allowed_methods  = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
    cached_methods   = ["GET", "HEAD"]
    target_origin_id = "${aws_s3_bucket.image-bucket.id}"

    forwarded_values {
      query_string = false

      cookies {
        forward = "none"
      }
    }

    viewer_protocol_policy = "allow-all"
    min_ttl                = 0
    default_ttl            = 3600
    max_ttl                = 86400
  }

  price_class = "PriceClass_200"

  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }

  tags = {
    Environment = "dev"
  }

  viewer_certificate {
    cloudfront_default_certificate = true
  }
}

#iam
data "aws_iam_policy_document" "cf_to_s3_policy" {
  statement {
    actions = ["s3:GetObject", "s3:ListBucket"]

    resources = [
      "${aws_s3_bucket.image-bucket.arn}",
      "${aws_s3_bucket.image-bucket.arn}/*",
    ]

    principals {
      type        = "AWS"
      identifiers = ["${aws_cloudfront_origin_access_identity.origin_access_identity.iam_arn}"]
    }
  }
}

resource "aws_s3_bucket_policy" "cf-to-s3" {
  bucket = "${aws_s3_bucket.image-bucket.id}"
  policy = "${data.aws_iam_policy_document.cf_to_s3_policy.json}"
}

terraform実行

これら二つのファイルが用意できましたら、あとは簡単です。
CUIでterraform-aws/に移動し、まずterraform initコマンドを実行してください。

cd 任意のパス/terraform-aws/
terraform init

こちらのコマンドで Terraform の実行に必要なバイナリがダウンロードされます。Terraform has been successfully initialized! と表示されたら成功です。

次にterraform planを実行してください。リソースが正常に作成できるか実際に作成する前に確認できます。

terraform plan

最後にterraform applyを実行してください。こちらのコマンドで実際に、クラウド上にリソースが作成されます。
実行途中Do you want to perform these actions?と、本当に実行するか確認されるのでyesと入力してEnterを押してください。

terraform apply

Apply complete!と表示されたら成功です。
早速AWSコンソールにリソースを確認しにいきましょう!

AWSコンソールにて

cloudfrontコンソール

ディストリビューションが作成されていますね f:id:Takahashi_Blt:20201217191907p:plain

Origin Domain Name を確認するとオブジェクトの取得先がs3になっていることがわかります。
それではs3も見に行ってましょう!

s3コンソール

resouce.tfで指定したバケット名でバケットが作成されていることがわかります。
f:id:Takahashi_Blt:20201217191910p:plain

これで問題なく静的サイト公開に必要なリソースを作成できました!!
それでは、バケットに静的サイトのコンテンツをアップロードしましょう。
該当のバケットをクリックし、コンテンツをアップロードします!

f:id:Takahashi_Blt:20201218102546p:plain

(今回アップロードしたファイルはこちらのサイトで配布されているものです。)

ブラウザにて

Coludfrontドメインにアクセスすると、静的サイトが公開されていますことが確認できます! f:id:Takahashi_Blt:20201216230426p:plain

最後に

いかがでしたでしょうか!
あっという間に静的サイトを公開できる環境を構築できたと思います。
別のアカウントに同じ環境を作りたい、となった時もこのコードを保存しておけば瞬時に作成できますね!
infrastructure as code のメリットはとても大きいので、今後もどんどん取り入れていきたいです!