🌐

Cloud SQL Auth Proxyで安全にPublicなCloud SQLを使う

2022/11/06に公開

前回のGoogle Cloud Runで手軽にはじめる Webアプリに続いて、今回はCloud RunからCloud SQLへの接続についての紹介です。
Cloud RunからCloud SQLに接続するにはPrivate IPとPublic IPの2パターンあります。
Private IPだとVPCが必要になりますが、Public IPならCloud SQL Auth Proxyを使って暗号化しつつ安全に使えるので手軽でおすすめです。

実際に私の運営するLismisでも、データベースはCloud SQLのMySQLをPublic IPで使っているので、実例を交えて紹介します。

Cloud SQLをPublic IPで使う

データベースは内部ネットワークからのみアクセスを許可するケースが多いと思いますが、Cloud SQLなら内部ネットワークを構築せずに使えます。
これは安全性が担保できるなら、規模の小さい個人サービスなど管理の手間をかけたくないケースではかなりのメリットです。
実際にLismisでは Cloud RunとCloud SQLで運営しており、インフラ面での管理コストがほぼゼロにできたので非常に助かっています。

まずはCloud SQLの準備

https://cloud.google.com/sql/docs/mysql/connect-instance-cloud-run?hl=ja#gcloud_3

クイックスタート通り作ります。まずはインスタンスの作成しMySQLデータベースを作成します。
--database-versionは適当に置き換えてください。

$gcloud sql instances create [INSTANCE_NAME] \
	--database-version=MYSQL_8_0 \
	--region=[REGION] \
	--root-password=[ROOT_PASSWORD]

$ gcloud sql databases create [DATABASE_NAME] \
	--instance=[INSTANCE_NAME]

次にユーザーを作成します。
Cloud SQL Auth Proxyを使って接続するので、それ以外からのアクセスは除外します。
そのため--host=cloudsqlproxy~%を指定してユーザーを作成します。

$ gcloud sql users create [USER_NAME] \
   --host=cloudsqlproxy~% \
   --instance=[INSTANCE_NAME]

https://cloud.google.com/sql/docs/mysql/sql-proxy?hl=ja#user

Cloud Run のサービスアカウントにCloud SQLのアクセス権を追加

Cloud Runのサービスアカウントがなければ作成しておきます。

$ gcloud iam service-accounts create [SERVICE_ACCOUNT_NAME]

Cloud Runで使うサービスアカウントに、Cloud SQLへ接続するための権限を追加します。

$ gcloud projects add-iam-policy-binding [PROJECT_ID] \
  --member="serviceAccount:[SERVICE_ACCOUNT_NAME]@[PROJECT_ID].iam.gserviceaccount.com" \
  --role="roles/cloudsql.client"

Cloud RunにCloud SQLへの接続を設定してデプロイする

先程権限を追加したCloud Runで使うサービスアカウントを--service-accountで指定し、--add-cloud-sql-instancesでCloud SQLのインスタンスを指定してデプロイします。

$ gcloud run deploy server \
	--service-account=[CLOUD_RUN_SERVICE_ACCOUNT] \
	--region=$(REGION) \
	--image=[CONTAINER_IMAGE] \
	--add-cloudsql-instances=[PROJECT_ID]:[REGION]:[CLOUD_SQL_INSTANCE_NAME]

Cloud Run から接続する

サンプルとして使える、Cloud SQLへの接続方法の詳細はこちらに記載されています。

https://github.com/GoogleCloudPlatform/php-docs-samples/tree/master/cloud_sql/mysql/pdo

Lismisではphpを使っているので、PDOにユーザー名とDSNを渡して接続します。
サンプルにある通り環境変数を使って渡すなどするほうがセキュアですが、本記事ではわかりやすく直接記載しています。

$dsn  = 'mysql:dbname=[DATABASE_NAME];unix_socket=/cloudsql/[PROJECT_ID]:[REGION]:[CLOUD_SQL_INSTANCE_NAME]';
$user = '[USER_NAME]';
$pdo  = new PDO($dsn, $user);

ローカルで確認する場合

ここまででCloud RunからCloud SQLへの接続はできました。
そしてローカルで開発を行うときにCloud SQLへ接続したい場合は、下記のようにCloud SQL Auth Proxyを使います。

下記はローカルから接続する際のdocker-compose.yamlの例です。
webサーバー用コンテナなどは省き、必要最低限の部分のみ記載していますので、適宜補完してください。

docker-compose.yaml
services:
  cloud-sql-auth-proxy:
    image: gcr.io/cloudsql-docker/gce-proxy:latest
    container_name: sql_proxy
    volumes:
      - cloud-sql-service-account-credentials.json:/var/credentials.json:ro
    command:
      - "/cloud_sql_proxy"
      - "-instances=[PROJECT_ID]:[REGION]:[CLOUD_SQL_INSTANCE_NAME]=tcp:0.0.0.0:3306"
      - "-credential_file=/var/credentials.json"
    ports:
      - "13306:3306"

cloud-run-service-account-credentials.jsonは、Cloud SQLのアクセス権を追加したサービスアカウントの鍵を作成/DLしたものです。
これで、localhostの13306ポートを使ってCloud SQLに接続することができました。

なお開発用のCloud SQLを使いたい場合はこれで良いのですが、単体テストだったりlocalhost内で完結させい場合は、接続先をCloud SQLからローカルに立てたMySQLのコンテナを使うとよいと思います。
Cloud SQLと同一バージョンのイメージであればほとんど問題になることはないでしょう。

余談

コストに問題がなければCloud Spannerも良い選択肢です。

Cloud SQLはおよそ四半期に1回、10分ほどの計画メンテナンスが行われるのが玉に瑕ですが、Spannerにはありませんし、負荷に応じた自動スケーリングや様々な利点があります。
ただしCloud SQLに比べると料金もお高めになります。
個人的にはCloud SQLの計画メンテナンスはネックですが、上記のようにCloud SQL Auth Proxyを使えばVPCも不要ですし、Cloud RunだけでなくGKEやApp Engineからも使えるので、小規模であればCloudSQLがおすすめです。

Discussion