1. ホーム
  2. 記事一覧
  3. 【Terraformハンズオン】OACを利用したCloudFrontを構築してみよう

2025.01.08

【Terraformハンズオン】OACを利用したCloudFrontを構築してみよう

AWSのCloudFrontは、画像や動画などのウェブコンテンツの配信を効率化し、遅延を少なくユーザーに提供するためのCDN(Contents Delivery Network)サービスです。世界中に分散されたエッジロケーションを活用することで、ユーザーに近い場所からコンテンツを配信できる点が特徴です。

CDNについては、以下の記事で解説しています。

【徹底解説】みんな知らずに使ってるCDN、コンテンツデリバリーネットワークって何?

CloudFrontを利用する際に重要な点として、オリジンサーバーとの安全な通信の確保があります。ここで必要になるのが、OAI(Origin Access Identity)とOAC(Origin Access Control)です。

この記事では、IaCツールのTerraformを使用してOACを利用したCloudFrontの構築方法を説明します。

OAIとOACの仕組みと違いを理解し、実際にハンズオンでOACを使ったCloudFrontを構築してみましょう。

OAIとは

OAIは、CloudFrontがAmazon S3バケット内のオブジェクトに安全にアクセスするための機能です。OAIを使用することで、S3バケットへの直接アクセスを防ぎ、CloudFront経由でのみコンテンツを配信することができます。

以前はOAIを使用してS3バケットへのアクセスを制限することが一般的でしたが、S3バケット側でAWS Key Management Service (AWS KMS)を使った暗号化やSSE-KMSを使用した場合に、OAIは使用できないといった課題がありました。

その課題を解決するために登場したのが、OACです。

現在AWSでは、OACを使うことが推奨されています。

オリジンアクセスアイデンティティを使用する (レガシー、非推奨)

OACとは

OACは、2022年8月にリリースされた機能で、OAIと同様にCloudFrontからS3バケットへのアクセスを制御するための仕組みです。

OAIで課題とされていたS3バケットの暗号化への対応などがOACではサポートされています。

ここからは、OACにはどのような特徴があるのか解説します。

Amazon CloudFront でオリジンアクセスコントロール (OAC) をリリース

セキュリティの向上

OACでは資格情報が頻繁に更新されるため、万が一資格情報が盗まれても悪用されるリスクを最小限に抑えることができます。

この機能により、Confused Deputy Attack(混乱した代理攻撃)への防御が強化され、CloudFrontのセキュリティが向上します。

包括的なHTTPメソッドのサポート

OACは、GETやPOST、PUT、PATCH、DELETE、OPTIONS、HEADなど、幅広いHTTPメソッドをサポートしています。

OAIではSigV4のみをサポートするリージョンのS3に対して、PUTメソッドでオブジェクトをアップロードする時に特定のヘッダーを付与する必要がありました。

OACではこの制約にも対応していて、HTTPメソッドを使用したより細かい設定を行うことが可能です。

SigV4は、AWSサービスにリクエストを送る際、そのリクエストの認証情報を付与するための仕組み(プロトコル)です。このプロトコルを利用することで、AWSはリクエストが正当なユーザーから送信されたものであることを確認できます。

Authenticating Requests (AWS Signature Version 4)

S3の暗号化オプションへの対応

OACでは、SSE-KMSによるS3オブジェクトのダウンロードとアップロードがサポートされました。この機能によって、S3バケットにアクセスする際自動的にSSE-KMSによる暗号化・復号化を行います。

そのため、SSE-KMSを使用して暗号化されたデータをCloudFront経由で安全にやり取りすることができ、データ漏洩のリスクを低減できます。

全てのAWSリージョンでのサポート

OACは、既存のリージョンのサポートはもちろん、今後利用可能となるすべてのAWSリージョンでのS3アクセスをサポートします。

新しいリージョンが追加されてもOACは常に利用可能なため、リージョンごとに対応状況が異なるといった事象を気にする必要がありません。

Amazon CloudFront がオリジンアクセスコントロール (OAC) を導入

TerraformでOAC CloudFrontの構築をしてみよう

ここからはIaCツールであるTerraformを利用して、OACとCloudFrontを構築していきます。

TerraformでのCloudFrontハンズオンは以下の記事でも紹介しています。

【Terraformハンズオン】AWS CloudFront&ALB構成を実現しよう

【Terraformハンズオン】CloudFrontにACMで発行したSSL証明書を紐付けてみよう

versions.tfの作成

はじめにTerraformのバージョン、プロバイダーを指定するため**versions.tf**を作成します。

terraform {
  required_version = ">= 1.0.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "5.3.0"
    }
  }
}

provider "aws" {
  region = "ap-northeast-1"
}

main.tfの作成

次に、main.tfファイルで必要なリソースを作成します。

以下、ファイル全体の内容です。

# main.tf
# オリジンのS3バケットの作成
resource "aws_s3_bucket" "my-cf-origin-xxxx" {
  bucket = "my-cf-origin-xxxx"
}

# パブリックアクセスの無効化
resource "aws_s3_bucket_public_access_block" "my-cf-origin-xxxx" {
  bucket                  = aws_s3_bucket.my-cf-origin-xxxx.bucket
  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

# バケットポリシーを作成
resource "aws_s3_bucket_policy" "my-cf-origin-xxxx" {
  bucket = aws_s3_bucket.my-cf-origin-xxxx.bucket
  policy = data.aws_iam_policy_document.my-cf-origin-xxxx.json
}

# IAM Policyドキュメントの作成
data "aws_iam_policy_document" "my-cf-origin-xxxx" {
  statement {
    principals {
      type        = "Service"
      identifiers = ["cloudfront.amazonaws.com"]
    }
    actions = [
      "s3:GetObject"
    ]
    resources = [
      "${aws_s3_bucket.my-cf-origin-xxxx.arn}/*"
    ]
    condition {
      test     = "StringEquals"
      variable = "aws:SourceArn"
      values = [
        aws_cloudfront_distribution.my-cf-origin-xxxx.arn,
      ]
    }
  }
}

# Origin Access Controlの作成
resource "aws_cloudfront_origin_access_control" "my-cf-origin-xxxx" {
  name                              = "my-cf-origin-xxxx"
  origin_access_control_origin_type = "s3"
  signing_behavior                  = "always"
  signing_protocol                  = "sigv4"
}

# CloudFrontのディストリビューションの作成
resource "aws_cloudfront_distribution" "my-cf-origin-xxxx" {
  enabled = true
  comment = "my-cf-origin-xxxx"
  default_root_object = "index.html"

  # オリジンの設定
  origin {
    domain_name              = aws_s3_bucket.my-cf-origin-xxxx.bucket_regional_domain_name
    origin_id                = aws_s3_bucket.my-cf-origin-xxxx.id
    origin_access_control_id = aws_cloudfront_origin_access_control.my-cf-origin-xxxx.id
  }

  # CloudFrontのデフォルト証明書を利用する
  viewer_certificate {
    cloudfront_default_certificate = true
  }

  # デフォルトのキャッシュ動作の設定
  default_cache_behavior {
    allowed_methods        = ["HEAD", "DELETE", "POST", "GET", "OPTIONS", "PUT", "PATCH"]
    cached_methods         = ["HEAD", "GET"]
    target_origin_id       = aws_s3_bucket.my-cf-origin-xxxx.id
    viewer_protocol_policy = "redirect-to-https"

    # デフォルトのキャッシュ動作の設定
    forwarded_values {
      query_string = false # クエリ文字列を転送しない
      cookies {
        forward = "none" # クッキーを転送しない
      }
    }
  }

  # 地理的な制限の設定。今回は制限なし。
  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }
}

# CloudFrontのディストリビューションのDNS名を出力
output "cloudfront_domain_name" {
  value = aws_cloudfront_distribution.my-cf-origin-xxxx.domain_name
}

次のセクションでは、主なresourceブロックの解説をしていきます。

S3バケットに対するパブリックアクセスの制御

作成したバケットに対して、明示的にパブリックアクセスを無効化します。

こうすることで、意図しないアクセスからバケットを保護することができます。

# パブリックアクセスの無効化
resource "aws_s3_bucket_public_access_block" "my-cf-origin-xxxx" {
  bucket                  = aws_s3_bucket.my-cf-origin-xxxx.bucket
  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block

バケットポリシーのドキュメント作成

次に、CloudFrontのOACからのみ、S3バケットに対してGetObjectを許可するポリシーを作成します。

# IAM Policyドキュメントの作成
data "aws_iam_policy_document" "my-cf-origin-xxxx" {
  statement {
    principals {
      type        = "Service"
      identifiers = ["cloudfront.amazonaws.com"]
    }
    actions = [
      "s3:GetObject"
    ]
    resources = [
      "${aws_s3_bucket.my-cf-origin-xxxx.arn}/*"
    ]
    condition {
      test     = "StringEquals"
      variable = "aws:SourceArn"
      values = [
        aws_cloudfront_distribution.my-cf-origin-xxxx.arn,
      ]
    }
  }
}

このポリシーを作成するバケットに追加することで、valuesで指定したCloudFrontディストリビューションからのアクセスを許可します。

バケットポリシーの内容は、公式ドキュメントから確認できます。

OACの作成

続いてOACを作成します。

OACは任意の名前を付与することができるため、第三者が見ても関連がわかる名前を付与します。

# Origin Access Controlの作成
resource "aws_cloudfront_origin_access_control" "my-cf-origin-xxxx" {
  name                              = "my-cf-origin-xxxx" # 任意のOAC名
  origin_access_control_origin_type = "s3" # OACが対象とする「オリジン」(データの送信元)のタイプを指定
  signing_behavior                  = "always" # CloudFrontがS3へのすべてのリクエストに署名を付与する
  signing_protocol                  = "sigv4" # S3へのリクエストを署名する際に使用するプロトコルを指定
}

リソースの作成

ソースコード作成後、initコマンドでTerraformのプロジェクトを初期化します。

terraform init

続いて、planを実行し想定しているリソース作成が行われるか確認します。

terraform plan

最後にapplyコマンドでリソースを作成します。

terraform apply

applyが完了すると、ターミナルに作成したCloudFrontのドメインが出力されるため保存します。

このドメインは、CloudFront経由でS3バケットへアクセスする時に利用します。

index.htmlファイルの作成

以下コマンドで、S3バケットで利用するテストファイルを作成します。

echo "Hello, CloudFront OAC!" > index.html

S3バケットへファイルをコピー

作成したindex.htmlファイルを、S3バケットへコピーします。

aws s3 cp index.html s3://my-cf-origin-xxxx

upload: ./index.html to s3://my-cf-origin-xxxx/index.html

HTMLファイルの表示確認

はじめに、curlコマンドでindex.htmlの内容が返ってくるか確認します。

curl https://dm7aee5h8tvk1.cloudfront.net
Hello, CloudFront OAC!

続いて、ブラウザにCloudFrontドメインを入力し、表示を確認します。

ブラウザで表示が確認できれば、OACを利用したCloudFrontの作成は完了です。

まとめ

この記事では、Terraformを使用してOAC(Origin Access Control)を利用したCloudFrontの構築方法を解説しました。

OACは、CloudFrontからS3バケットへの安全なアクセスを実現する機能で、従来のOAIに比べてセキュリティや暗号化対応が向上しています。

この記事を通じて、OACの仕組みと利点、Terraformを活用した実際の構築手順について理解を深めていただければ幸いです。

参考記事

【徹底解説】みんな知らずに使ってるCDN、コンテンツデリバリーネットワークって何?

オリジンアクセスアイデンティティを使用する (レガシー、非推奨)

Amazon CloudFront でオリジンアクセスコントロール (OAC) をリリース

Authenticating Requests (AWS Signature Version 4)

Amazon CloudFront がオリジンアクセスコントロール (OAC) を導入

【番外編】USBも知らなかった私が独学でプログラミングを勉強してGAFAに入社するまでの話

IT未経験者必見 USBも知らなかった私が独学でプログラミングを勉強してGAFAに入社するまでの話

プログラミング塾に半年通えば、一人前になれると思っているあなた。それ、勘違いですよ。「なぜ間違いなの?」「正しい勉強法とは何なの?」ITを学び始める全ての人に知って欲しい。そう思って書きました。是非読んでみてください。

「フリーランスエンジニア」

近年やっと世間に浸透した言葉だ。ひと昔まえ、終身雇用は当たり前で、大企業に就職することは一種のステータスだった。しかし、そんな時代も終わり「優秀な人材は転職する」ことが当たり前の時代となる。フリーランスエンジニアに高価値が付く現在、ネットを見ると「未経験でも年収400万以上」などと書いてある。これに釣られて、多くの人がフリーランスになろうとITの世界に入ってきている。私もその中の1人だ。数年前、USBも知らない状態からITの世界に没入し、そこから約2年間、毎日勉学を行なった。他人の何十倍も努力した。そして、企業研修やIT塾で数多くの受講生の指導経験も得た。そこで私は、伸びるエンジニアとそうでないエンジニアをたくさん見てきた。そして、稼げるエンジニア、稼げないエンジニアを見てきた。

「成功する人とそうでない人の違いは何か?」

私が出した答えは、「量産型エンジニアか否か」である。今のエンジニア市場には、量産型エンジニアが溢れている!!ここでの量産型エンジニアの定義は以下の通りである。

比較的簡単に学習可能なWebフレームワーク(WordPress, Rails)やPython等の知識はあるが、ITの基本概念を理解していないため、単調な作業しかこなすことができないエンジニアのこと。

多くの人がフリーランスエンジニアを目指す時代に中途半端な知識や技術力でこの世界に飛び込むと返って過酷な労働条件で働くことになる。そこで、エンジニアを目指すあなたがどう学習していくべきかを私の経験を交えて書こうと思った。続きはこちらから、、、、

note記事3000いいね超えの殿堂記事 今すぐ読む

エンベーダー編集部

エンベーダーは、ITスクールRareTECHのインフラ学習教材として誕生しました。 「遊びながらインフラエンジニアへ」をコンセプトに、インフラへの学習ハードルを下げるツールとして運営されています。

RareTECH 無料体験授業開催中! オンラインにて実施中! Top10%のエンジニアになる秘訣を伝授します! RareTECH講師への質疑応答可

関連記事