【アップデート】Cloud CDN と外部 Application Load Balancer でプライベートな Cloud Storage バケットにアクセスできるようになりました

【アップデート】Cloud CDN と外部 Application Load Balancer でプライベートな Cloud Storage バケットにアクセスできるようになりました

Google CloudがPrivate Bucket Access 機能を一般提供開始。Cloud CDN と外部 Application Load Balancer から IAM ベースの認証でプライベートな Cloud Storageバケットへセキュアにアクセスできます。署名付き URL 不要で簡潔な設定を実現。
2026.07.06

はじめに

こんにちは。
クラウド事業本部コンサルティング部の渡邉です。

2026年7月3日、Cloud CDN および外部 Application Load Balancer において、プライベートな Cloud Storage バケットへのアクセス(Private Bucket Access)が一般提供(GA)になりました。

https://docs.cloud.google.com/cdn/docs/release-notes#July_03_2026

これまで Cloud CDN のバックエンドバケットとして Cloud Storage を利用する場合、バケットをパブリックに公開するか、署名付き URL を使う必要がありました。
バケットをパブリックに公開することに抵抗がある方も多かったのではないでしょうか。

今回のアップデートにより、バケットを公開せずに IAM 経由のサービスアカウント認証でコンテンツを配信できるようになり、よりセキュアな静的コンテンツ配信が実現します。

本記事では、Private Bucket Access の仕組みと設定手順をご紹介します。

Private Bucket Access の仕組み

従来の構成との比較

従来、Cloud CDN のバックエンドバケットとして Cloud Storage を利用する場合の方式として、バケットをパブリックに公開するか署名付きURLを利用する必要がありました。
バケットをパブリックに公開する場合、設定としては簡単ですが、パブリックに公開しているため、誰でもバケットにアクセスすることができてしまうデメリットがありました。
署名付き URLを利用すればバケットをプライベートにすることは可能ですが、独自の署名付きURLを生成する仕組みが必要になります。
今回のPrivate Bucket Accessは、Load Balancer専用のサービスアカウントからのみアクセス可能とするIAMを付与することで、バケットをプライベートにしながらコンテンツを配信することができます。

方式 セキュリティ 手間
バケットをパブリック公開 誰でもアクセス可能 設定が簡単
署名付き URL URL ごとに有効期限あり URL 生成の仕組みが必要
Private Bucket Access(今回) LB 専用 SA のみアクセス可 IAM 設定のみ

サービスアカウントについて

Private Bucket Access では、Google が管理する以下の形式のサービスアカウントを使用します。

service-PROJECT_NUM@https-lb.iam.gserviceaccount.com

このサービスアカウントに roles/storage.objectViewer ロールを付与することで、Cloud CDN および外部 Application Load Balancer がプライベートバケットのオブジェクトを読み取れるようになります。

サポート対象のロードバランサー

ロードバランサー Private Bucket Access
Global external Application Load Balancer サポート
Classic Application Load Balancer サポート
Regional external Application Load Balancer 非サポート
Regional internal Application Load Balancer 非サポート

実際に試してみる

前提条件

  • Google Cloud プロジェクトで課金が有効になっていること
  • gcloud CLI がインストール・認証済みであること
  • プロジェクトで以下の API が有効になっていること
    • Cloud Storage API
    • Compute Engine API

事前準備: 変数を設定する

以降のコマンドで共通して使用する変数を設定します。YOUR_PROJECT_ID を実際のプロジェクト ID に置き換えてください。
PROJECT_NUM はサービスアカウントのメールアドレス(service-PROJECT_NUM@https-lb.iam.gserviceaccount.com)に使用します。

export PROJECT_ID="YOUR_PROJECT_ID"
export PROJECT_NUM=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")
export BUCKET_NAME="private-cdn-bucket"       # グローバルに一意なバケット名
export BACKEND_BUCKET_NAME="cdn-backend-bucket"
export LB_IP_NAME="cdn-lb-ip"
export URL_MAP_NAME="cdn-url-map"
export PROXY_NAME="cdn-http-proxy"
export FORWARDING_RULE_NAME="cdn-forwarding-rule"

ステップ1: プライベートな Cloud Storage バケットを作成する

Uniform Bucket-Level Access(統一バケットレベルアクセス)を有効にしたプライベートバケットを作成します。この設定により ACL が無効化され、IAM のみでアクセス制御が行われます。

gcloud storage buckets create gs://$BUCKET_NAME \
  --project=$PROJECT_ID \
  --default-storage-class=standard \
  --location=asia-northeast1 \
  --uniform-bucket-level-access

Creating gs://private-cdn-bucket/...

バケットがプライベートであること(allUsers に権限がないこと)を確認します。

gcloud storage buckets get-iam-policy gs://$BUCKET_NAME

bindings:
- members:
  - projectEditor:YOUR_PROJECT_ID
  - projectOwner:YOUR_PROJECT_ID
  role: roles/storage.legacyBucketOwner
- members:
  - projectViewer:YOUR_PROJECT_ID
  role: roles/storage.legacyBucketReader
- members:
  - projectEditor:YOUR_PROJECT_ID
  - projectOwner:YOUR_PROJECT_ID
  role: roles/storage.legacyObjectOwner
- members:
  - projectViewer:YOUR_PROJECT_ID
  role: roles/storage.legacyObjectReader
etag: CAE=

ステップ2: テスト用オブジェクトをアップロードする

動作確認に使用するファイルをバケットにアップロードします。

echo "Hello from Cloud CDN Private Bucket!" > test.txt
gcloud storage cp test.txt gs://$BUCKET_NAME/test.txt

Copying file://test.txt to gs://private-cdn-bucket/test.txt
  Completed files 1/1 | 37.0B/37.0B

Cloud Storage バケットへのファイルアップロード確認(TODO: キャプチャ説明を追記)
Cloud Storage バケットへのファイルアップロード確認

ステップ3: 静的 IP アドレスを予約する

ロードバランサーのフロントエンドに使用するグローバル静的 IP アドレスを予約します。

gcloud compute addresses create $LB_IP_NAME \
  --network-tier=PREMIUM \
  --ip-version=IPV4 \
  --global

予約された IP アドレスを確認します。

gcloud compute addresses describe $LB_IP_NAME \
  --format="get(address)" \
  --global

YOUR_LB_IP

予約された IP アドレス
予約された IP アドレス

ステップ4: バックエンドバケットを作成する(Cloud CDN 有効)

Cloud CDN を有効にして、プライベートバケットと紐づけたバックエンドバケットを作成します。

gcloud compute backend-buckets create $BACKEND_BUCKET_NAME \
  --gcs-bucket-name=$BUCKET_NAME \
  --enable-cdn \
  --cache-mode=FORCE_CACHE_ALL

Created [https://www.googleapis.com/compute/v1/projects/YOUR_PROJECT_ID/global/backendBuckets/cdn-backend-bucket].
NAME: cdn-backend-bucket
GCS_BUCKET_NAME: private-cdn-bucket
ENABLE_CDN: True

キャッシュの TTL を設定します(ここでは 24 時間)。FORCE_CACHE_ALL モードでは --max-ttl は使用できず、--default-ttl を使います。

gcloud compute backend-buckets update $BACKEND_BUCKET_NAME \
  --default-ttl=86400

Updated [https://www.googleapis.com/compute/v1/projects/YOUR_PROJECT_ID/global/backendBuckets/cdn-backend-bucket].

ステップ5: ロードバランサーを構成する

URL マップ、ターゲットプロキシ、フォワーディングルールを順に作成します。

URL マップの作成

gcloud compute url-maps create $URL_MAP_NAME \
  --default-backend-bucket=$BACKEND_BUCKET_NAME

Created [https://www.googleapis.com/compute/v1/projects/YOUR_PROJECT_ID/global/urlMaps/cdn-url-map].
NAME: cdn-url-map
DEFAULT_SERVICE: backendBuckets/cdn-backend-bucket

ターゲット HTTP プロキシの作成

gcloud compute target-http-proxies create $PROXY_NAME \
  --url-map=$URL_MAP_NAME

Created [https://www.googleapis.com/compute/v1/projects/YOUR_PROJECT_ID/global/targetHttpProxies/cdn-http-proxy].
NAME: cdn-http-proxy
URL_MAP: cdn-url-map

フォワーディングルールの作成

gcloud compute forwarding-rules create $FORWARDING_RULE_NAME \
  --load-balancing-scheme=EXTERNAL_MANAGED \
  --network-tier=PREMIUM \
  --address=$LB_IP_NAME \
  --global \
  --target-http-proxy=$PROXY_NAME \
  --ports=80

Created [https://www.googleapis.com/compute/v1/projects/YOUR_PROJECT_ID/global/forwardingRules/cdn-forwarding-rule]

作成したロードバランサー
作成したロードバランサー

ステップ6: バケットに IAM 権限を付与する

LB サービスアカウントにバケットへの読み取り権限を付与します。

gcloud storage buckets add-iam-policy-binding gs://$BUCKET_NAME \
  --member="serviceAccount:service-${PROJECT_NUM}@https-lb.iam.gserviceaccount.com" \
  --role=roles/storage.objectViewer

bindings:
- members:
  - projectEditor:YOUR_PROJECT_ID
  - projectOwner:YOUR_PROJECT_ID
  role: roles/storage.legacyBucketOwner
- members:
  - projectViewer:YOUR_PROJECT_ID
  role: roles/storage.legacyBucketReader
- members:
  - projectEditor:YOUR_PROJECT_ID
  - projectOwner:YOUR_PROJECT_ID
  role: roles/storage.legacyObjectOwner
- members:
  - projectViewer:YOUR_PROJECT_ID
  role: roles/storage.legacyObjectReader
- members:
  - serviceAccount:service-YOUR_PROJECT_NUMBER@https-lb.iam.gserviceaccount.com
  role: roles/storage.objectViewer
etag: CAI=
kind: storage#policy
resourceId: projects/_/buckets/private-cdn-bucket
version: 1

ステップ7: 設定を確認する

バックエンドバケットの Cloud CDN 設定と IAM バインディングを確認します。

# バックエンドバケットの Cloud CDN 有効化を確認
gcloud compute backend-buckets describe $BACKEND_BUCKET_NAME \
  --format="yaml(name,bucketName,enableCdn,cdnPolicy)"

bucketName: private-cdn-bucket
cdnPolicy:
  cacheMode: FORCE_CACHE_ALL
  defaultTtl: 86400
  negativeCaching: true
  requestCoalescing: true
  serveWhileStale: 86400
enableCdn: true
name: cdn-backend-bucket

enableCdn: true が返れば Cloud CDN が有効です。

# バケットの IAM ポリシーを確認
gcloud storage buckets get-iam-policy gs://$BUCKET_NAME

bindings:
- members:
  - projectEditor:YOUR_PROJECT_ID
  - projectOwner:YOUR_PROJECT_ID
  role: roles/storage.legacyBucketOwner
- members:
  - projectViewer:YOUR_PROJECT_ID
  role: roles/storage.legacyBucketReader
- members:
  - projectEditor:YOUR_PROJECT_ID
  - projectOwner:YOUR_PROJECT_ID
  role: roles/storage.legacyObjectOwner
- members:
  - projectViewer:YOUR_PROJECT_ID
  role: roles/storage.legacyObjectReader
- members:
  - serviceAccount:service-YOUR_PROJECT_NUMBER@https-lb.iam.gserviceaccount.com
  role: roles/storage.objectViewer
etag: CAI=

出力の bindings 内に roles/storage.objectViewerservice-${PROJECT_NUM}@https-lb.iam.gserviceaccount.com が含まれていれば設定完了です。

動作確認

設定が完了したら、以下の3点を確認します。

1. バケットへの直接アクセスが拒否されることを確認

プライベートバケットとして正しく設定されていれば、Cloud Storage への直接アクセスは 403 Forbidden になります。

curl -o /dev/null -w "%{http_code}" \
  https://storage.googleapis.com/$BUCKET_NAME/test.txt

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   673  100   673    0     0   6035      0 --:--:-- --:--:-- --:--:--  6063

403

403 が返れば、バケットが外部から保護されています。

2. LB 経由でコンテンツにアクセスできることを確認

# ロードバランサーの IP アドレスを取得
LB_IP=$(gcloud compute addresses describe $LB_IP_NAME \
  --format="get(address)" \
  --global)

# ヘッダーを表示しながらアクセス確認
curl -D- -o /dev/null http://$LB_IP/test.txt

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0HTTP/1.1 200 OK
x-guploader-uploadid: AJ5rDhEQxkda4hkzVbDGYXP_oVYFqrSJ01zo4FHHKRKd-X1ioovc4B4rd5GcqjvpSOdbKLlYBwNDhj8
x-goog-generation: 1782686040174590
x-goog-metageneration: 1
x-goog-stored-content-encoding: identity
x-goog-stored-content-length: 37
x-goog-hash: crc32c=b2a0wA==
x-goog-hash: md5=VP+xVbgH7gFLUsy3jToZaA==
x-goog-storage-class: STANDARD
accept-ranges: bytes
Content-Length: 37
server: UploadServer
via: 1.1 google
Date: Sun, 05 Jul 2026 20:50:34 GMT
Cache-Control: public,max-age=86400
Last-Modified: Sun, 28 Jun 2026 22:34:00 GMT
ETag: "54ffb155b807ee014b52ccb78d3a1968"
Content-Type: text/plain
Age: 211

100    37  100    37    0     0   2062      0 --:--:-- --:--:-- --:--:--  2176

初回アクセス(キャッシュミス)では Age: 0、2回目以降のアクセス(キャッシュヒット)では Age: N(N は秒数)が返えるようになります。

コンテンツも無事取得できていました。

curl http://$LB_IP/test.txt
Hello from Cloud CDN Private Bucket!

3. Cloud Logging でキャッシュ動作を確認

Logs Explorer で以下のクエリを実行すると、キャッシュヒットのログを確認できます。

resource.type="http_load_balancer"
jsonPayload.statusDetails="response_from_cache"

キャッシュヒット時のログには次のフィールドが含まれます。

{
  "insertId": "yqd7ldf4ahsgs",
  "jsonPayload": {
    "cacheId": "NRT",
    "statusDetails": "response_from_cache",
    "backendTargetProjectNumber": "projects/YOUR_PROJECT_NUMBER",
    "cachePolicySource": "CACHE_POLICY_SOURCE_BACKEND",
    "@type": "type.googleapis.com/google.cloud.loadbalancing.type.LoadBalancerLogEntry",
    "remoteIp": "YOUR_CLIENT_IP",
    "cacheDecision": [
      "RESPONSE_HAS_CACHE_CONTROL",
      "RESPONSE_CACHE_CONTROL_NO_CACHE",
      "RESPONSE_HAS_ETAG",
      "RESPONSE_HAS_LAST_MODIFIED",
      "RESPONSE_HAS_EXPIRES",
      "RESPONSE_HAS_CONTENT_TYPE",
      "CACHE_MODE_FORCE_CACHE_ALL"
    ]
  },
  "httpRequest": {
    "requestMethod": "GET",
    "requestUrl": "http://YOUR_LB_IP/test.txt",
    "requestSize": "85",
    "status": 200,
    "responseSize": "682",
    "userAgent": "curl/8.5.0",
    "remoteIp": "YOUR_CLIENT_IP",
    "cacheHit": true,
    "cacheLookup": true,
    "latency": "0.002400s",
    "protocol": "HTTP/1.1"
  },
  "resource": {
    "type": "http_load_balancer",
    "labels": {
      "url_map_name": "cdn-url-map",
      "backend_service_name": "cdn-backend-bucket",
      "forwarding_rule_name": "cdn-forwarding-rule",
      "zone": "global",
      "target_proxy_name": "cdn-http-proxy",
      "project_id": "YOUR_PROJECT_ID"
    }
  },
  "timestamp": "2026-07-05T20:54:05.024170Z",
  "severity": "INFO",
  "logName": "projects/YOUR_PROJECT_ID/logs/requests",
  "trace": "projects/YOUR_PROJECT_ID/traces/c01d7bdb9b4141468a888c28c6e9e49a",
  "receiveTimestamp": "2026-07-05T20:54:05.816635782Z",
  "spanId": "101ccc4461061969"
}

cacheHit: truestatusDetails: "response_from_cache" が確認できれば、Cloud CDN のキャッシュが正常に機能しています。

まとめ

今回の GA により、Cloud CDN および外部 Application Load Balancer から Cloud Storage のプライベートバケットへセキュアにアクセスできるようになりました。バケットを公開せずに静的コンテンツを配信できるため、機密性の高い画像・動画・ファイルを CDN で配信したい場合のアーキテクチャ選択肢が広がります。

設定の仕組みは IAM による権限付与のみで完結しており、署名付き URL のような期限管理が不要です。Google が管理するサービスアカウント(service-PROJECT_NUM@https-lb.iam.gserviceaccount.com)に roles/storage.objectViewer を付与するだけで有効になります。ただし、Regional external Application Load Balancer では現時点でサポートされていない点と、読み取り専用であるという制約に注意してください。

複数バケットをプライベートに配信したい場合は、バケットごとに同じ手順で roles/storage.objectViewer を付与してください。サービスアカウントはプロジェクト単位で1つ共用されます。

静的コンテンツをセキュアに CDN で配信したいユースケースがある場合は、ぜひ試してみてください。

この記事が誰かの助けになれば幸いです。

以上、クラウド事業本部コンサルティング部の渡邉でした!

この記事をシェアする

関連記事