人間になりたい類人猿

人間以前の技術屋ブログ

GCPのCloud SQLでネットワークタグを用いた接続制限を行う方法

概要

f:id:wannabehuman:20210525224356j:plain
意外と言及している記事が見当たらない、GCEのVMインスタンスからCloud SQLインスタンスに対してネットワークタグを使った接続制限を行う方法を記載する。

方法としてはプライベートサービス接続を作成し、VMとCloud SQLをプライベートIPで接続可能とした上で、VMからの送信トラフィックをデフォルト拒否、接続させたいVMのネットワークタグだけ送信トラフィックを許可する形。

はじめに~Cloud SQLの接続方法について~

まず始めにGCPのCloud SQLインスタンスに対してVMインスタンスから接続許可する方法としては主に以下の2つがある。

①承認済みネットワークで接続

いわゆるIP許可。Cloud SQLインスタンスの接続画面から承認済みネットワークとしてVMの外部IPを許可設定する形。
Cloud SQLのコンソール上では接続方法として真っ先にこの方法が案内される。

しかしこの方法には以下のような問題点がある

  • VMに静的IPを付与しないと、起動の度に設定IPの変更が必要になる。
  • VMがオートスケールで構築されると構築されたVMから疎通させたい時、設定IPの変更が必要になる。

ちょっとした開発や小さいアプリケーションなら問題ないが、少し規模が大きくなるとこれは現実的ではない。

②Cloud SQL Proxyを使う方法

もう一つの方法としてCloud SQL Proxyを利用する方法がある。
認証用のCloud SQLの権限を持ったサービスアカウントを作成、jsonファイルをVMに配備、cloud_sql_proxyをVMでDLして実行する。
参照:https://cloud.google.com/sql/docs/mysql/connect-admin-proxy?hl=ja

この場合、①で上げられた問題点は解消され、VMインスタンス起動時にこのツールを起動する様に構築すれば良い。
しかしこの方法にも以下のような問題点がある

  • 接続IPがローカルIP(127.0.0.1)になる為、プログラム側では「どこにつないでいるか」がプログラム側の設定ファイルから確認しづらくなる。
  • 複数のCloud SQLインスタンスと接続しようとすると、インスタンス毎にポートを分ける必要がある
    • つまり2台のCloud SQLインスタンスと接続しようとすると、127.0.0.1:3306と127.0.0.1:3307に対して接続する事になる
    • DBをつなぐ際の実装として、ホストに対してこのポートなんて実装は普通しない。
      • 接続情報としてホスト:ポートで設定しているパターンもあるので100%ではないが。
  • ツール起動が手間
  • ツール起動時の引数をミスる可能性もある。

一応接続用のライブラリも存在するが、javaとGoだけしか無いようで、phpやその他の言語では使えない状態になっている。

ネットワークタグを使って制御したい

以上を解決する為には、VMインスタンスの接続制限のようにネットワークタグを使えると非常に便利。
ネットワークタグを元にしたファイアウォールを利用する事で、Cloud SQLインスタンスに対して接続できる/できないVMインスタンスを制御出来れば、以下のような事が実現できる。

これを実現する方法について備忘録も兼ねて記載する。

①プライベートサービス接続の作成

まずはCloud SQLインスタンスにプライベートIPで接続できるようにする為、VPCネットワーク側にプライベートサービス接続を作成する。
Cloud SQLインスタンスと接続したVPCネットワークの詳細画面を開き、「プライベートサービス接続」タブを押下する。

①-1.IP範囲の割当
タブのIP範囲の割当を押下し、
名前を任意に入力し、Cloud SQLインスタンスに付与されるプライベートIPの範囲を指定する。
既存のサブネットと範囲を被らせない様にする必要もあるので、本番運用する際は、設定値に注意する必要はあるが、ここでは「自動」で設定し、サイズは16を指定した。
f:id:wannabehuman:20210525222216p:plain
参考:https://cloud.google.com/vpc/docs/configure-private-services-access?hl=ja


①-2.プライベートサービス接続の作成
「サービスへのプライベート接続」タブを押下し、接続の作成を押下
接続サービスプロデューサーは「Google Cloud Platform」、割当を上で作ったIP範囲に設定、接続を押下
f:id:wannabehuman:20210525222249p:plain

以上でプライベートサービス接続が作成できる。

②Cloud SQLインスタンスにプライベートIPを追加

Cloud SQLインスタンスの構築/編集(編集の際は接続メニュー)にてプライベートIPのチェックを入れる。
VPCネットワークの選択が出るので、プライベートサービス接続を作成したVPCを選択。正常であれば以下のような表示になる。
f:id:wannabehuman:20210525222307p:plain

ファイアウォールの設定

②ままではVPCネットワーク内の全てのVMインスタンスからCloud SQLインスタンスにデフォルトで疎通可能となってしまう。
※以下のように任意のVMから疎通できる。(IPを隠す意味は無い気がするが念の為)
f:id:wannabehuman:20210525222332p:plain

その為、ファイアウォールを設定しVMインスタンスとCloud SQLインスタンスへの接続を制御する。

③-1.デフォルト拒否
まずはデフォルトとして、全てのVMインスタンスからCloud SQLインスタンスへの接続をNGとするファイアウォールを設定する。
この時Cloud SQLインスタンスの上り(受信)トラフィックを制御する訳ではなく、VMインスタンスからの下り(送信)トラフィックを制御する。

名前 ネットワーク 優先度 トラフィックの方向 一致した時のアクション ターゲット ソースフィルタ IP範囲 プロトコルとポート
deny-vm-to-mysql
※適当
test-cloudsql-vpc
VMがあるVPC
2000
※後で設定する許可より優先度を下げる
下り(送信)
GCPは上り/下りが一般の認識と逆
拒否 ネットワーク上の全てのインスタンス IP範囲 [プライベートサービス接続の割当IP範囲] 3306


③-2.対象のネットワークタグのみ接続許可
次にCloud SQLインスタンスと接続したいVMに付けるネットワークタグからはCloud SQLインスタンスへ接続できるようファイアウォールを設定する。
こちらもVMインスタンスからの下り(送信)トラフィックを制御する形。

名前 ネットワーク 優先度 トラフィックの方向 一致した時のアクション ターゲット ターゲットタグ ソースフィルタ IP範囲 プロトコルとポート
allow-mysqlclient-vm-to-mysql
※適当
test-cloudsql-vpc
VMがあるVPC
1000 下り(送信) 許可 指定されたターゲットタグ mysql-client-vm IP範囲 [プライベートサービス接続の割当IP範囲]
※ここはIPを直指定でも良いと思う。全てが全て接続できて良いわけではないと思うので
3306
④動作確認

VMsshでログイン/mysqlコマンドで確認可能だが、せっかくなのでGCPの接続テスト機能で確認してみる。
(もちろん最終的にはmysqlコマンドで接続確認するが)

適当にVMインスタンスを構築し、接続テストにて以下の設定を行い、接続テストを実行

mysql-clientが無い場合
VMのネットワークタグが以下の状態の時
f:id:wannabehuman:20210525222533p:plain

疎通が通らない。
f:id:wannabehuman:20210525222543p:plain

mysql-clientがある場合
このVMインスタンスにネットワークタグ「mysql-client-vm」を設定し、再実行
※勿論本来は別インスタンス
f:id:wannabehuman:20210525222614p:plain

この通り疎通が成功する。
f:id:wannabehuman:20210525222623p:plain


まとめ

以上の方法を行えば、VMインスタンスとCloud SQLインスタンスをネットワークタグを用いて接続制御が出来る。
公式ドキュメント(https://cloud.google.com/sql/docs/mysql/connect-compute-engine?hl=ja)にも書いてないの、ホント不親切というか……

以上。

久々にエンジニアっぽい記事書いた。