【Google Cloud】VMインスタンスのDBサーバにSQLクライアントをセキュアに繫ぐには?

2023-08-16

こんにちは!
近頃Google CloudのIAP(Identity-Aware Proxy)のありがたさを実感しまくっているエヌデーデーの金子です😌
皆様、クラウド内でアプリケーション開発は快適に出来ていますでしょうか?

クラウド内のアプリケーションはネットワーク外からの攻撃を気にせず安全に動くことが大きなメリットですが、反面 ローカル端末 からクライアントツールを繫ぐなどの行為も制限が出てきます。

今回開発用のWebアプリケーションをクラウド環境で動かすにあたって開発用データベース IBM Db2(以下Db2) をVMインスタンス内に構築する運びとなったのですが、サーバに入って Db2 コマンドでSQLを発行するのは開発体験が何とも。。といった懸念がありました。

この記事ではIAPトンネリングを利用して、ローカルの端末からクライアントツールを使って 外部公開しないVMに建てたDBサーバ接続する方法をご紹介します。

IAP接続はGoogle認証が前提ですが、Googleアカウントを持たない社外パートナーさん等も利用できるようにサービスアカウントを渡して接続する方法もご紹介しますので、参考にしていただければと思います。

※ VMインスタンスを秘匿してWebアプリケーションを特定のアカウントに公開する方法はこちらでご紹介しています。

VMに Db2 をインストール

既にデータベースをCompute Engineに作っている場合、本セクションはスキップしてOKです。ただし、IAPトンネリング接続でgcloudコマンドを使用するので、ローカル端末にCloud SDKを入れておく必要があります。今回は以下の環境でVMインスタンスにDBサーバを作ります。

VMインスタンスブートディスク:CentOS7・40GB
Db2 : Db2 Community Edition 11.5.8

Cloud SDKをセットアップ

まずはGoogle Cloud上のリソース操作に便利なCloud SDKを ローカル端末に入れておきましょう。
ローカル端末OSに合わせたインストールを行うとともに、LANとインターネットの間にプロキシがある場合は適切な設定を行ってください。

プロキシ / ファイアウォールの背後で gcloud CLI を使用する場合

Cloud Storage経由でインストーラをVM内へ

欲しいDb2のバージョンをIBM Db2 Download Centerから ローカル端末に落としてきます。
※ダウンロードにはIBMアカウントが必要です

次に以下のコマンドをローカル端末で実行し、ファイルをCloud Storageにコピーします。

 gsutil cp [ローカルファイルパス] gs://[バケット名] 

バケット内に圧縮ファイルがコピーされました。
今度はコレをVM内に持っていくため、 VMにSSH接続して次のコマンドを実行します 。

gsutil cp gs://[バケット名]/[ファイル名] [VMインスタンス名]:[ディレクトリパス]

⇧ サーバ内の狙ったディレクトリに圧縮ファイルが入っていることを確認します。

VMインスタンスにブラウザSSH接続して直接ファイルをアップロードすることもできますが、圧縮ファイルでも2ギガあるため単純にアップロードするとネットワークの断絶やサービス遅延により失敗するリスクが高いです。

ですので、一旦、コンソールやgsutilなどのコマンドを使ってCloud StorageにアップロードしてからVMにコピーすることを推奨します。これらは再試行やアップロードの再開が行えます。

Db2 セットアップ

続いてVMインスタンス内で圧縮ファイルを解凍し、サーバ内の Db2 セットアップを進めます。
ここからの手順は【備忘録】Db2 インストール手順まとめ(Linux)が詳しいです。

#ファイル解凍
tar -zxvf <ファイル> 

#インストール前提条件を満たしているかチェック
#足りないライブラリを教えてくれるので、必要に応じてインストール
db2prereqcheck -i -v 11.5.8

#Db2インストール
./db2_install -b /opt/ibm/db2/V11.5.8 -p SERVER -f NOTSAMP

#インスタンス所有者を作成し追加
#このユーザとしてローカルから接続されるので、パスワードも設定しておく
useradd db2inst1
groupadd db2iadm1
gpasswd -a db2inst1 db2iadm1

#fencedユーザを作成し追加
groupadd db2fadm1
useradd -u 1003 -g db2fadm1 -m -d /home/db2fenc1 db2fenc1

#fencedユーザとしてDb2インスタンスを作成
#/opt/ibm/db2/V11.5.8/instance に移動して以下のコマンド実行
./db2icrt -u db2fenc1 db2inst1

#db2inst1に切り替え、導入されたDB2のバージョンを確認
su - db2inst1
db2level

#Db2を起動し、データベースを作成&接続
db2start
CREATE DATABASE <データベース名>
CONNECT TO <データベース名>

#動作確認(システムテーブルに対して応答確認)
db2 "select * from SYSIBM.SYSDUMMY1"

Db2 インスタンス上にデータベースが正常に構築されたことを確認したら、
必要なテーブルを作成しデータを流し込んでおきます。

IAPトンネリングで接続

本題です。通信イメージは以下です。

ローカル端末がIAPに443でアクセスし、IAPが代理としてVMインスタンスにSSH接続します。会社のネットワークでは社外へのSSH接続が禁じられているケースは少なくないかと思いますが、この手法では通信が443に内包されるためSSH接続が出来る、というのが素晴らしい点です。

IAPを介してSSH接続を行うので、ファイアウォールの上りルールで 35.235.240.0/20 (IAPの接続元アドレス)からの 22/TCP (SSH)を許可しておきましょう。

対象メンバのアカウントに適切なIAMロールを付与したうえで、 PowerShell上で以下のコマンドを実行します 。

# Googleログイン
gcloud auth login

# VMインスタンスにSSH接続
gcloud compute ssh [VMインスタンス名] --[ゾーン] --project=[プロジェクトID] --tunnel-through-iap '--' -4 -N -L 25010:localhost:25010

「 '–' -4 -N -L 25010:localhost:25010 」がコマンドオプションであり、以下の意味を持ちます。

  • -4: IPv4を使用して接続します。
  • -N: リモートシェルを実行せず、ポートフォワーディングだけを行います。
  • -L 25010:localhost:25010: ローカルポートフォワーディングを設定します。リモートポート25010のトラフィックをローカルホストのポート25010に転送します。

25010はDBサーバが空けているポートを指定してください。
これは VMインスタンスで 以下の Db2 コマンドを実行することで、調べることが出来ます。

#サービス名を取得
db2 get dbm cfg | grep "SVCENAME"

#ポート番号を取得
grep "上記で取得したサービス名" /etc/services

正常にアクセスできると、PuTTY(※ Windows版のCloud SDKに内用されているsshクライアント )が開きます。

これが開いている状態で、SQLクライアントツールを繋げます。
今回はSQLクライアント A5M2(A5:SQL Mk-2) を使用します!
データベースの追加と削除 > 汎用接続ADO と進みます。
※接続にはDb2 Clientが必要になります。 IBM Supportから適切なバージョンを取得して設定しておきます。

接続文字列は Db2 の設定を反映させます。

設定
ユーザID Db2 インスタンス所有者
パスワード Db2 インスタンス所有者のパスワード
接続先localhost:25010

テスト接続が成功すればOKです!お疲れさまでした。😎

おまけ① サービスアカウントでIAP接続する

本記事の接続は、各自のアカウントに権限を付与するのが前提です。
ですが Googleアカウントを持たないメンバがIAP接続をするには、サービスアカウントを使用するという方法があります。 gcloudコマンドを使ってSSH接続する上で、最低限の権限を渡すためサービスアカウントを使う、というコトです。

IAP越しにVMインスタンスにアクセスするサービスアカウントには以下のロール及び権限が必要です。

ロール・権限役割
roles/compute.viewer( Compute 閲覧者 )compute.instances.get 権限でVMインスタンスにアクセス
roles/iap.tunnelResourceAccessor( IAP で保護された トンネル ユーザー )IAPを介して接続する
roles/iam.serviceAccountUser( サービスアカウントユーザ )VMインスタンスを使用するサービスアカウントに成り代わるため
compute.instances.setMetadata(メタデータ設定権限)Googleアカウントを持たないユーザがサービスアカウントとして接続する場合、最初に公開鍵をComputeEngineのメタデータサーバに保存する。(※ユーザが一度サービスアカウントのログインを終えたら、不要

compute.instances.setMetadata を所持している基本ロールは現状Compute管理者しかありませんので、必要に応じてカスタムロールを作っておくとスマートかもしれません。サービスアカウントを作成してロールを付与したら、シークレットを使って以下のコマンドをローカル端末で実行し、サービスアカウントとしてログインを試みます。

gcloud auth activate-service-account --key-file=.\[シークレットJSONファイル名]

gcloud config list でサービスアカウントに成り代われているかどうかをチェックします。

※この方法はサービスアカウントのシークレットを対象者に配る必要がありますので、サービスアカウントの権限設定および配布範囲を適切に見極めることが重要です。

おまけ②  VM起動時に Db2 も同時起動する

開発用のVMは常に稼働させると料金がかさむため、スケジューラで自動停止することをお勧めします。ただし、そうなると毎度VM立ち上げてdb2startコマンドでDBを起こして。。という手間が発生します。

これをVMインスタンスの起動スクリプトによって自動化します。
以下のシェルスクリプトをVMに登録しておくことで、VM立ち上げ時にDb2が自動起動するようになります。

VMインスタンスの設定

※db2start実行ファイルは Db2 インスタンス所有者が保持しています。これを起動時に叩くにはDB2INSTANCEという環境変数の設定が必要な点に注意です。

終わりに

外部公開しないVMインスタンスをHTTPS通信に包んだSSH接続でローカルホストのように扱う、というIAPトンネリングによるセキュアな接続はクラウド開発の可能性を広げてくれるものだと思います。

Compute Engineでアプリケーション開発を試みている方にとっては、代えがたい技術なのではないでしょうか。