🛹

Google Cloud StorageでBasic認証付きでWeb公開(CloudRun Bucket Mount編)

2024/03/06に公開

前書き

Cloud StorageにBasic認証を付けて公開する記事を何度か書いているのですが、
手製のプログラムを使う方法で保守などに不安が残る内容でした。

ついに、Cloud RunでCloud Storage をフォルダとして操作できる「ボリュームのマウント」がきました

記載の通り、Cloud RunでNginxを立ち上げ、任意のCloud Storageをホストして簡単に配信できます。
Nginxを使うだけなので、安心感がありますね。

Cloud StorageをNginxでホストするサーバを構築
gcloud beta run deploy --image nginx [SERVICE_NAME] \
--execution-environment gen2 --port 80 \
--add-volume=name=html-volume,type=cloud-storage,bucket=[YOUR_BUCKET_NAME],readonly=true \
--add-volume-mount=volume=html-volume,mount-path='/usr/share/nginx/html'

ドキュメント↓
https://cloud.google.com/run/docs/configuring/services/cloud-storage-volume-mounts?hl=ja

やりたいこと

Google Cloud Platform(GCP)で静的なWebサイトをCloud Storage(GCS)に置いてBasic認証をつけて公開したい。

サーバレス(Cloud Run)でNginxをホストして配信したい。
Nginxの設定も簡単に差し替えれるようにしたい。(ボリュームマウントの機能でファイルを差し替えで対応)

構築の流れは、

  1. 公式NginxイメージでCloud Run立ち上げ
  2. Cloud Runに任意のCloud Storageをボリュームマウント
  3. Cloud RunにNginxの設定ファイルをボリュームマウント

やることはこれだけです。
シンプルですね。

Cloud StorageをCloud Run経由でWeb配信する

まず、Cloud RunでCloud StorageをWeb配信する機能を作ります。
配信できることを確認したら、Basic認証を付けます。

さっそく作っていきましょう。
google cloudのコンソール(管理画面)で作業を進めます。

Webファイルを置くCloud Storageを作る

Cloud Storageのバケットを用意します。
Storageを"公開"状態にする必要はありません。

Cloud Storageを作成したら、相通確認のために適当なファイルを置きましょう。

NginxのCloud Runを立ててCloud Storageをマウントする

NginxはDocker公式のものを使います。
Google Cloudでは主要なDocker Imageをmirror.gcr.ioへミラーしています。そちらを使用します。

現在、Cloud Storage ボリュームのマウント機能は"プレビュー"で、コマンドからの作成しかサポートされていません。(はやく対応してくれー)
作成されたCloud RunはCloud Storageのボリュームマウント以外の機能は管理画面で後からの変更もできますので安心して作業してください。

では、ターミナルを立ち上げます

Cloud Runの作成コマンドは以下です

Cloud Run作成コマンド
gcloud beta run deploy SERVICE \
--image nginx \
--port=80 \
--use-http2 \
--region=asia-northeast1 \
--allow-unauthenticated \
--execution-environment gen2 \
--add-volume=name=VOLUME_NAME,type=cloud-storage,bucket=BUCKET_NAME,readonly=true \
--add-volume-mount=volume=VOLUME_NAME,mount-path=/MOUNT_PATH

# SERVICE: Cloud Runにつける名前
# MOUNT_PATH: ボリュームをマウントする相対パス(/cache など)に置き換えます。
# VOLUME_NAME: ボリュームに付ける名前に置き換えます。VOLUME_NAME 値は、ボリュームをボリューム マウントにマッピングするために使用されます。オプションで読み取り専用にしています。
# BUCKET_NAME: Cloud Storage バケットの名前
# MOUNT_PATH: マウントするパス

大文字のところを置き換えて、コマンドを実行してください。

コマンドの内容(気になる人向け)

1行目、"SERVICE"名でCloud Runをデプロイします
2行目、Dockerイメージの"nginx"をソースとして作ります
3行目、80番ポートで通信する
4行目、http2通信を行う
5行目、東京(asia-northeast1)にサーバを立てます。通信経路を短くするためにバケットと同じ場所に建てる方が良いでしょう
6行目、誰でもURLにアクセスできます(許可ユーザのみアクセス許可する制限を行わない)
7行目、Cloud Runの第2世代で作ります
8行目、Cloud Storageの"BUCKET_NAME"のバケットをボリュームとして使用します。読み取り専用です
9行目、作成した"VOLUME_NAME"ボリュームを"MOUNT_PATH"にマウントします

実行例
gcloud beta run deploy nginx-proxy \
--image nginx \
--port=80 \
--use-http2 \
--region=asia-northeast1 \
--allow-unauthenticated \
--execution-environment gen2 \
--add-volume=name=web-bucket,type=cloud-storage,bucket=hoge-web-bucket,readonly=true \
--add-volume-mount=volume=web-bucket,mount-path=/web-bucket

ターミナルにコマンドを流して、Cloud Runを構築しましょう。


Nginxを設定する

Cloud Runが無事に立ち上がったらNginxの設定をしましょう。
以下に設定例を示します。

default.conf
server {
	listen 80;
	http2  on;
	server_name  _;# Server at localhost
	
	# Enables gzip compression to make our app faster
	# gzip on;



	# Backet Path
	root   /web-bucket;

	location / {
		index  index.html index.htm;
		
		# Basic Auth
		# auth_basic "Authentication required";
		# auth_basic_user_file /etc/nginx/.htpasswd;
		
		# allow bigger uploads
		client_max_body_size 300M;
		
		# kill cache
		expires -1;
		
		
		sendfile on;
		sendfile_max_chunk 10m;
		tcp_nopush on;
		
		# Accept-Range
		proxy_force_ranges on;
	}

	#error_page  404              /404.html;

	# redirect server error pages to the static page /50x.html
	#
	error_page   500 502 503 504  /50x.html;
	location = /50x.html {
		root   /usr/share/nginx/html;
	}
}

Cloud Storageは「実行例」の"web-bucket"でマウントされている想定にしています。
その他、お好みでカスタマイズしてください。(良い設定をコメントしてもらえるとうれしいです)

Nginxの設定をシークレットマネージャーに保存

シークレットマネージャーを開きましょう。

「シークレットを作成」するボタンから、作成しましょう。

Nginxの設定を保存してください
(シークレットの設定の反映は少しかかります)

例では、名前を「web-proxy-config」にしました。

Cloud Runで「シークレット」の値を使用する

Cloud Runでシークレットを読むように設定を行います。


今回は、「シークレット」の値をファイルにして、Cloud Run内のファイルに置きます。

編集画面(↓)では、
➀「シークレット」をファイルとして読み込む設定をする「ボリューム」
➁「ボリューム」で設定した"ファイル"をCloud Runの指定パスに配置する「ボリュームのマウント」
に分かれています。

➀「ボリューム」設定 => ➁「ボリュームのマウント」の順に設定します。


➀「ボリューム」設定

「ボリューム」設定を開いて、「ボリュームを追加」を押下します。
添付画像を参考にシークレットを設定ください。
「パス」は、 default.conf を設定します。
「バージョン」は数値で明確に指定したほうが良いです。

➁「ボリュームのマウント」

「コンテナ」タブの「ボリュームのマウント」を開きます。
先ほど作ったボリュームを選び、
「マウントパス」は etc/nginx/conf.d を設定します。

設定したらページ一番下の「デプロイ」から設定を反映してください。

Cloud RUNのURLを開いて、Cloud Storageのコンテンツが表示されることを確認しましょう

Basic認証をかける

basic認証をかけましょう。

Nginxの設定変更

Nginxの設定でbasic認証を有効化し、htpasswdをCloud Runに配置すれば完了です。
手順は、上で行ったNginxの設定とほぼ同じですね。

上で示した、Nginxの設定から、下の部分の"#"を消してコメントアウトを解除しましょう。

"#"を消してコメントアウトを解除
# auth_basic "Authentication required";
# auth_basic_user_file /etc/nginx/.htpasswd;

シークレットマネージャで「新しいバージョン」から作成したNginx設定を追加します。

値に、新しいNginxの設定を入れて「新しいバージョンを追加」してください。


.htpasswdファイルの生成

basic認証のID/PWを作りましょう。

htpasswdファイルの生成を作成します。
bashコマンドなら以下です。(windowsはWSLで実行できます)
username を任意の名前に変更してください。

bash(wsl)コマンド
htpasswd -n -B username

Google Cloudのシークレットマネージャに追加します。


Cloud Runに設定を反映

Cloud Runの設定内の「ボリューム」が参照しているNginx設定の最新を反映します。
新しく作成したシークレットのバージョンを設定します。(バージョンが反映されないときは、ブラウザリロード)


「ボリューム」に.htpasswdを追加しましょう。
「パス」を".htpasswd"で追加します。


「ボリュームのマウント」で.htpasswdを配置します。
「マウントパス」は、etc/nginxです。

設定したらページ一番下の「デプロイ」から設定を反映してください。

おわりに

無事構築できましたか?
お好みで、Cloud RunのスペックやNginxの設定をカスタマイズしてください。

以上です。


おまけ1
この記事では中継するので、"遅さ"などが発生します。
ユーザをID/PWで制限するだけなら
Google Cloudで WebページをStorageに置いてBasic認証のような簡易認証をつけて表示する
もあります。

おまけ2
GCPの機能の一つとして Firebase があります。
Firebaseを使って、Basic認証をつける方法もあります。
https://note.com/rubymade/n/nafa8c82bd4cc

おまけ3
basic認証から公開状態にする際に、ロードバランサーからCloud Storageに直接アクセスへの変更は注意が必要です。
basic認証した状態のブラウザは、認証情報(Authorizationヘッダー)を送るのですがStorageは認証チェックを行います。(そして認証エラーになります)
対策として、ブラウザを開きなおす or サーバでヘッダーを削除する必要があります。
(ロードバランサーで削除は可能、需要があれば書く)

めんどくさいので、みんなこのissueに投票して!
https://issuetracker.google.com/u/1/issues/258717489

Discussion