🕌

IDとパスワードを使わずにCloud SQLに接続したい

2024/09/27に公開

Google Cloud上のCloud SQLに接続するとき,多くのサイトでIDとパスワードを用いた古典的な接続方法が紹介されています.
例えばPostgreSQLの場合,次のような接続情報を用いてDBに接続します.

postgresql://user:password@127.0.0.1/database

課題: クレデンシャルな情報を隠蔽したい

クラウドなどのコンテナを前提とした環境では,DBの接続情報などを環境変数(もしくはVolume Mount)を経由して実行インスタンスに渡します.

# 環境変数の例
DATABASE_URL: postgresql://user:password@127.0.0.1/database

この時,IDやパスワードなどのクレデンシャル情報をどのようにインスタンスに渡すのが良いでしょうか?
クレデンシャル情報はできれば社内の人しかアクセスできないプロジェクトであってもできる限り露出させたくありません.

GitHub ActionsのSecrets Contextを利用する

GitHub Actionsからデプロイする場合,各リポジトリの「Settings > Environments」からSecrets Contextを登録できます.
ここで登録されたSecrets Contextは,GitHub Actions上で利用することができ,その情報はActionsのログ上でも伏せ字になり,隠蔽することができます.

# Actionsの設定例
steps:
- name: Deploy
  run: |
    gcloud run deploy my-service \
      --set-env-vars=DATABASE_URL=${{ secrets.DATABASE_URL }}
# Actionsのログ
gcloud run deploy my-service \
  --set-env-vars=DATABASE_URL=***

このようにGitHub上でクレデンシャル情報が露出しないようにすることができますが,デプロイ先のCloud Runの設定をメンバーが見れる状態の場合,簡単にDBの接続情報を見れてしまいます.

# gcloudコマンド,もしくはウェブコンソールから環境変数の中身を見ることができます
gcloud run services describe my-service

解決1: Secret Managerを用いる

このような課題を解決する上で最初に思い浮かぶのがSecret Managerです.
GitHub ActionsのSecrets Contextと同じ要領でクレデンシャル情報を隠蔽できます.

Secret Managerを用いてデプロイする場合,次のようにデプロイすることができます.

# Actionsの設定例
steps:
- name: Deploy
  run: |
    gcloud run deploy my-service \
      --set-secrets=DATABASE_URL=DATABASE_URL:latest

Secret Managerを用いることで,Cloud Runの設定をメンバーが見ることができたとしてもSecret Managerへのアクセス権限がない限りはクレデンシャル情報が露出することはありません.

クレデンシャル情報を隠蔽できたのは良いのですが,やっていることは従来のIDとパスワードを用いた認証による接続なので,記事のタイトル回収をできていません.

解決2: Service Accountを認証に用いる

多くの場合Secret Managerを使えば良いのですが,正直なところクレデンシャル情報の管理なんてやりたくありません.

Cloud SQLにはService Accountを用いて認証する方法(IAM認証)が用意されており,Service Accountを認証に用いる場合は従来のIDとパスワードによる認証が不要になります.

Service AccountをDBユーザーとして追加する

Service Accountを用いて認証を行う場合,Cloud Runの実行に利用しているService AccountをDBユーザーとして追加する必要があります.

登録するDBユーザー名はMySQLとPostgreSQLによって違いがあり,PostgreSQLの場合はService Accountの末尾の.gserviceaccount.comを省略して登録する必要があります.
例えばservice-account-name@project-id.iam.gserviceaccount.comというService Accountを用いている場合は次のようになります.

gcloud sql users create service-account-name@project-id.iam \
  --instance=my-db \
  --type=cloud_iam_service_account

認証にCloud SQL Auth Proxyを使いたくない

IAM認証を用いてDBに接続する場合,ローカル環境であればCloud SQL Auth Proxyを用いて認証すれば良いのですが,インスタンス上でCloud SQL Auth Proxyを並行稼働させるのはなんだか面倒です.

幸いなことに,GoやNode.jsなどは公式からコネクターの実装が公開されているため,これらを利用することで簡単にIAM認証を実現することができます.

実装例もいくつか用意されており,例えばNode.jsでPrismaを用いた場合の接続方法が次のように紹介されています.

https://github.com/GoogleCloudPlatform/cloud-sql-nodejs-connector/blob/main/examples/prisma/postgresql/connect.ts

この実装例ではPublic IPを用いて接続していますがVPC上のPrivate IPを用いた接続もサポートされているため,次のように実装することができます.

// 実装例の23-37行目の内容
const path = resolve(".s.PGSQL.5432");
const connector = new Connector();
await connector.startLocalProxy({
  instanceConnectionName,
  ipType: IpAddressTypes.PRIVATE,
  authType: AuthTypes.IAM,
  listenOptions: { path },
});

const datasourceUrl = `${env.DATABASE_URL}?host=${cwd()}`;
const prisma = new PrismaClient({ datasourceUrl });
# Actionsの設定例
steps:
- name: Deploy
  run: |
    gcloud run deploy my-service \
      --set-env-vars=DATABASE_URL=postgresql://service-account-name@project-id.iam@192.168.0.1/database

また,PostgreSQLの場合は次のようなSQLを実行することで元々使用していたDBユーザー(user)の権限をService Accountに付与することができます.

GRANT user TO "service-account-name@project-id.iam";

まとめ

Service Accountを認証に利用することにより,DBの接続情報に必要なクレデンシャル情報を管理する必要がなくなりました.
これで皆さんも枕を高くして寝ることができるようになるのではないでしょうか?

株式会社モニクル

Discussion