🔬

詳解 Google Compute Engineへの接続

2022/12/19に公開

こんにちは。Google Cloudのカスタマーエンジニアの有賀です。

この記事は Google Cloud Japan Advent Calendar 2022 の「通常版」の(遅れてしまいましたが)9日目の記事です。

クラウド環境へのアクセス制限は、どのようなクラウドを使う場合でも必ず発生する非常に重要な設計・設定の1つだと思います。その中でもVMサービス(Google CloudだとCompute Engine)へのアクセス制限は多くの場合で必要になります。

そこで本記事ではまず、Compute Engine VMへの接続方法にはどのようなものがあるかを詳細に見ていきます。その上で最後に、それらの接続方法をどのように制限・コントロールをすればよいのか検討したいと思います。

TL;DR

  • VMへの接続はVPCファイアウォールで制限
  • Identity-Aware Proxyの利用は、APIへのアクセス制限と組み合わせる(本記事の範囲外)
  • Compute Engineへのその他の接続経路
    • シリアルコンソール接続は一時的な利用にとどめ、本番での利用は組織ポリシーで制限
    • ロードバランサーやプロトコル転送は必要なら組織ポリシーで制限

はじめに

まず初めに、Compute Engineへのアクセス制限という表現には2つ考えられます。

  1. Compute Engineサービスへのアクセス制限

Compute Engine VMを作ったり削除したりといった操作をイメージしてますが、こちらはAPIでの操作になりますので、本記事の範囲外としGoogle APIへのアクセス制限の記事で改めて触れたいと思います。

  1. Compute Engine VMへのアクセス制限

というわけで本記事ではこちらの、VMへのアクセス制限を見ていきたいと思います。

とはいえ、いきなりCompute Engine VMへのアクセス制限を検討する前に、まずはそもそもCompute Engine VMへアクセスする方法にどんなものがあり、具体的にどのような方法でログインがおこなわれているかを詳細に見ていきます。

そうすることで、どのようなところを制限しないといけないのかを理解し、必要十分なアクセス制限を実現できると考えているからです。

VM を起動

というわけで、まずはGoogle Cloudのプロジェクトを作った直後の状態、デフォルトの状態でCompute Engine VMを起動してみます。(リージョンだけ東京リージョン(asia-northeast1)に変更してます。なお、デフォルトのリージョンやゾーンは変更できます。)

VMの作成
Compute Engine VMの作成

さて、この状態からVMに接続するには次の3つの方法があります。

  1. Cloud Console上のSSHボタンで接続する
  2. 手元の環境からgcloudコマンドで接続する
  3. 手元の環境からSSHコマンドで接続する

それぞれ、どう接続されているのか確認します。

SSHボタンで接続

まずは一番簡単な、1つ目のSSHボタンを試してみます。このSSHボタンは「ブラウザからのSSH」という仕組みを使っています。

SSHボタンを押すと、しばらくSSH認証鍵をVMに転送しています。という画面が出て、次にSSHサーバーへの接続を確立しています…と表示されたら、

SSHボタンでの接続1
SSHボタンで接続 1

以下のようにログインできます。

SSHボタンでの接続2
SSHボタンで接続 2

さて、このSSHは一体どこからつながってるんでしょうか?ブラウザのタイトルを見ると、https://ssh.cloud.google.com/v2/ssh/…と表示されており、いかにもSSHのプロキシが動いてそうなURLです。また、wコマンドで見てみると35.235.240.241から接続しているようです。

$ w
 06:50:51 up 1 min,  1 user,  load average: 0.14, 0.07, 0.02
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
user     pts/0    35.235.240.241   06:50    0.00s  0.00s  0.00s w

調べてみると35.235.240.241GoogleのIPアドレスでした。これは上のhttps://ssh.cloud.google.com/からの接続なんでしょうか?

実はこれはIdentity-Aware Proxy(IAP)という仕組みを使っています。手元の環境のブラウザからhttps://ssh.cloud.google.com/へ接続し、さらにそこからIAP用のプロキシにつながり、最終的にIAP用のプロキシからSSHでGCE VMにつないでいます。そのためSSHの接続元がIAP用のIPアドレス範囲(35.235.240.0/20)になっているというわけです。

IAP経由の接続
IAP経由の接続

ではなぜ、35.235.240.241から接続できているのでしょうか。VMへのデフォルトのアクセス制限はどうなってるのでしょう?

プロジェクトを作成した直後の環境には defaultというVPCが用意されており、以下のスクリーンショットにあるようにSSH/RDP/ICMPはどこから(0.0.0.0/0)でも到達できるように設定されています。そして、初めは default VPCしかないので、このVMもそれを使っており、結果としてこのVMにはどこからでもSSHができるようになっています。

デフォルトVPCのファイアウォール
デフォルトVPCのファイアウォール

では、IAPのIPアドレス範囲35.235.240.0/20からの接続をブロックしたらどうなるでしょう。接続に失敗するでしょうか?

以下のように35.235.240.0/20からの接続をすべてブロック(拒否)するファイアウォールルールを設定してみます。(ファイアウォールルールについては、VPCについて解説した別の記事も参照ください。)

IAPからの接続をブロック
IAPからの接続をブロック

すると今度は以下のように、Cloud IAPの使用を推奨するメッセージが出ますが、相変わらずログインはできました。

IAPの利用を推奨
IAPの利用を推奨するメッセージ

ただ、接続元のIPアドレスが変化しました。とはいえ、接続元の172.217.42.59は相変わらずGoogleのIPアドレスのようです。どういうことでしょう。

IAPをブロックしてログインした場合
$ w
 07:21:27 up 31 min,  1 user,  load average: 0.00, 0.00, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
user     pts/0    172.217.42.59    07:18    0.00s  0.00s  0.00s w

「ブラウザからのSSH」のドキュメントのエラーメッセージに関する説明に以下のような記述がありました。どうやら、IAPのIPアドレス範囲だけではなく、GoogleのIPアドレスからもアクセスするようです。

ブラウザベースの SSH セッションの送信元 IP アドレスは、Cloud Console によって動的に割り当てられ、セッションごとに異なることがあります。この機能を動作させるには、任意の IP アドレスからの接続、または公開 SPF レコードを使用して取得できる Google の IP アドレス範囲からの接続を許可する必要があります。

つまりIAPからの接続をブロックしたことでIAPが使われなくなり、(上記SPFレコードで示される)GoogleのIPアドレス範囲から直接VMにSSHで接続してくるようになった、ということのようです。

IAPを経由しない接続
IAPを経由しない接続

というわけで、SSHボタンを使った場合は、GoogleのIPアドレス範囲か、IAPのIPアドレス範囲からVMに接続してくることがわかりました。

最後は試しにSSHでのアクセスを全部ブロックしてみます。SSHのアクセスをブロックするファイアウォールルールを新しく作ってもいいのですが、代わりに既存の「SSHアクセスをどこからでも(0.0.0.0/0)許可する」というルールを無効化してみます。

既存のルール default-allow-ssh をクリックして詳細を表示し、「編集」ボタンをクリック、一番下にある「適用」という項目を「無効」に変更します。

SSH用のファイアウォールルールを無効化
SSH用のファイアウォールルールを無効化

すると、SSH認証鍵をVMに転送しています。という画面までは同じですが、次のSSHサーバーへの接続を確立しています…の後で(期待通り)接続できませんでした というエラーになりました。


VMに接続できませんでした

ついでに「トラブルシューティング」というリンクをクリックすると、「ファイアウォールの設定を確認する」よう促されました。

接続のトラブルシューティング
接続のトラブルシューティング

(ちなみに VM の SSH TCP ポート(通常は TCP ポート 22)で上り(内向き)のトラフィックを許可するようにしてください。 と書かれてますが、どこからを許可すればいいのか分からないので、ちょっと不親切かもしれません。)

SSHボタンで接続時の認証

さて、SSHボタンで接続した場合、どこからつないできているかは分かったので、次はどのように認証されているのかを見てみましょう。

ユーザーID

そもそもユーザーIDやパスワードを入れることなくログインできてますし、最初にSSH認証鍵をVMに転送していますと表示されますがSSH認証鍵を作った覚えもありません。

とりあえず、いったん無効にした default-allow-ssh を再度有効にして、もう一度VMにログインしてみましょう。(また、IAPを経由すると少しパフォーマンスが良いので、IAPをブロックするファイアウォールルールも削除してしまいましょう。)

ログインして、自分のユーザーIDを確認すると、user となっていました。これはCloud Consoleを使っているユーザーのGoogleアカウント user@agira.altostrat.comユーザー名の部分です。つまり、Google Cloudを使っているGoogleアカウントと同じユーザー名のLinuxユーザーが自動的に作られるようです。(一時的なユーザー名の変更は可能です。)

$ whoami
user

試しにTaro Yamada <taro@agira.altostrat.com> という新しいユーザーを作ってみます。(この記事の環境ではCloud Identityを使ってGoogleアカウントを管理してるので、Cloud Identityでユーザーを作成します。)

また、ドキュメントによるとComputeインスタンス管理者権限サービスアカウントユーザー権限が必要なので付与しておきます。


インスタンス管理者権限の付与

できたら、新しく作ったGoogleアカウントでCloud Consoleにログインし、同じくSSHボタンでログインしてみます。期待通り taro という(Linux)ユーザーが新しく作られました。

$ whoami
taro
$ ls /home
taro  user
$ 

その際、syslogには以下のように出ていました。

ユーザーが作成されたログ
# grep taro /var/log/syslog
Dec 12 02:46:34 instance-1 google_guest_agent[409]: Creating user taro.
Dec 12 02:46:34 instance-1 google_guest_agent[409]: Updating keys for user taro.
Dec 12 02:46:48 instance-1 systemd[1]: Started Session 90 of user taro.
Dec 12 02:46:49 instance-1 google_guest_agent[409]: Updating keys for user taro.

ログメッセージを手がかりに検索してみると、Google Guest Agentでユーザーを作成していることが分かります。

https://github.com/GoogleCloudPlatform/guest-agent/blob/20221109.00/google_guest_agent/non_windows_accounts.go#L139-L163

実際にGoogle Guest Agentのドキュメントにも以下のように書かれています。

On Windows, the agent handles creating user accounts and setting/resetting passwords.

On Linux: If OS Login is not used, the guest agent will be responsible for provisioning and deprovisioning user accounts. The agent creates local user accounts and maintains the authorized SSH keys file for each. User account creation is based on adding and remove SSH Keys stored in metadata.

なお上記文中のOS Loginは、IAMを使用してインスタンスへのSSHアクセスを管理する仕組みです。本記事で見てきたここまでの仕組みはOS Loginを使用しない場合の説明になりますが、実際の環境ではOS Loginを使用することをオススメします

(じゃあ最初からOS Loginを前提に書けばいいというのはその通りなんですが、デフォルトの状態から見ていきたかったので、OS Loginなしの環境から始めてみました。)

というわけで、SSHボタンでの接続時は、Cloud Consoleを使う際にすでにGoogleアカウントへのログインという形で認証が行われているので、そのユーザーを使ってGoogle Guest Agentが自動的にGoogleアカウントに対応する(同じユーザー名の)Linuxユーザーを作っていることが分かりました

デフォルトで、VMに接続するユーザーが1つのユーザーアカウントを共有するのではなく個別のユーザーアカウントを使うようになっているのは、セキュリティの観点からも中々いい仕組みだなと思ってます。

SSH鍵認証

さて、ユーザーが動的に作られることは分かりましたが、肝心の認証はどうなってるのでしょう?通常、SSHで接続する場合、そのユーザー用のSSH認証鍵を作って、公開鍵をVMに登録する、というような処理をおこないます。(たとえばAmazon EC2ではキーペアを作成して登録しとくと、EC2インスタンス作成時にデフォルトユーザーの~/.ssh/authorized_keysに公開鍵が配置されます。)

しかし、SSHボタンの接続時(もその前)も、SSH認証鍵を作った覚えはありません。どうなってるのでしょう?

…とかもったいぶった書き方をしましたが、上に引用したGoogle Guest Agentの説明にすでに書かれてました。

The agent creates local user accounts and maintains the authorized SSH keys file for each. User account creation is based on adding and remove SSH Keys stored in metadata.

つまりGoogle Guest Agentがユーザーの作成と同じく、ホームディレクトリへのSSH認証鍵の追加と削除も担っているのです。実際にドキュメントを読むと、以下のように書かれていました。

  1. Compute Engine は、ユーザー名を設定し、次の構成でエフェメラル SSH 認証鍵ペアを作成します。
      ・ユーザー名は、Googleアカウントのユーザー名として設定されます。(略)
      ・公開 SSH 認証鍵と秘密 SSH 認証鍵は、ブラウザ セッションに保存されます。
      ・SSH 認証鍵の有効期限は 5 分です。Compute Engine が鍵を作成して 5 分後に、SSH 認証鍵では VM に接続できなくなります。
  2. Compute Engine が公開 SSH 認証鍵とユーザー名をメタデータにアップロードします。
  3. Compute Engine は、SSH 認証鍵とユーザー名をメタデータから取得し、ユーザー名でユーザーアカウントを作成し、Linux VM では、その公開鍵を VM 上にあるユーザーの ~/.ssh/authorized_keys ファイルに格納します。Windows VM の場合、Compute Engine は公開鍵を VM に保存しません。
  4. Compute Engine が接続を許可します。

ここでポイントとなるのがエフェメラルSSH認証鍵ペアを作成のところです。上でSSH認証鍵を作った覚えはありませんと書きましたが、それもそのはず、エフェメラルな(短い期間だけ有効な)鍵がその場で作られていたからです。

そしてその公開鍵はインスタンスのメタデータに登録されます。


VMの詳細画面で見るSSH認証鍵

Cloud Loggingで監査ログを見てみると以下の通り、操作をしているGoogleアカウントがsetMetadata APIを使って ssh-keys というキーに値(SSHの公開鍵)を登録していることが分かります。

SSH認証鍵のメタデータへの登録時の監査ログの抜粋
{
  "protoPayload": {
    "@type": "type.googleapis.com/google.cloud.audit.AuditLog",
    "authenticationInfo": {
      "principalEmail": "taro@agira.altostrat.com",
      "principalSubject": "user:taro@agira.altostrat.com"
    },
    "requestMetadata": {
      "callerIp": "x.x.x.x",
      "callerSuppliedUserAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36,gzip(gfe)",
    },
    "serviceName": "compute.googleapis.com",
    "methodName": "v1.compute.instances.setMetadata",
    "resourceName": "projects/advent-calendar-2022-370404/zones/asia-northeast1-b/instances/instance-1",
    "metadata": {
      "instanceMetadataDelta": {
        "modifiedMetadataKeys": [
          "ssh-keys"
        ]
      },
      "@type": "type.googleapis.com/google.cloud.audit.GceInstanceAuditMetadata"
    }
  }
}

インスタンスのメタデータに登録されたSSH認証鍵はGoogle Guest Agent経由で、作成されたユーザーのホームディレクトリ配下に配置されます。

ホームディレクトリに登録されたSSH公開鍵
$ cat ~taro/.ssh/authorized_keys 
# Added by Google
ecdsa-sha2-nistp256 AAA...mL4= google-ssh {"userName":"taro@agira.altostrat.com","expireOn":"2022-12-12T05:15:51+0000"}
# Added by Google
ssh-rsa AAA...TuJ google-ssh {"userName":"taro@agira.altostrat.com","expireOn":"2022-12-12T05:16:06+0000"}

上記の通り、ECDSA鍵とRSA鍵の2つが登録されています。(公開鍵自体は長いので"..."で省略してます)また、コメント部分(google-sshから後ろ)にその鍵を作った/使うGoogleアカウント名と有効期限が書かれています。有効期限が過ぎるとGoogle Guest Agentが当該SSH公開鍵を削除します。

https://github.com/GoogleCloudPlatform/guest-agent/blob/20221109.00/google_guest_agent/non_windows_accounts.go#L352-L366

有効期限が切れて公開鍵が削除された際のログ
Dec 12 05:16:08 instance-1 google_guest_agent[409]: ERROR non_windows_accounts.go:209 Invalid ssh key entry - expired key: taro:ecdsa-sha2-nistp256 AAA...mL4= google-ssh {"userName":"taro@agira.altostrat.com","expireOn":"2022-12-12T05:15:51+0000"}
Dec 12 05:16:08 instance-1 google_guest_agent[409]: ERROR non_windows_accounts.go:209 Invalid ssh key entry - expired key: taro:ssh-rsa AAA...TuJ google-ssh {"userName":"taro@agira.altostrat.com","expireOn":"2022-12-12T05:16:06+0000"}
Dec 12 05:16:08 instance-1 google_guest_agent[409]: Removing user taro.

ちなみに上のログに Removing user taro. と出ていますが、デフォルトではユーザー自体を削除するのではなく、SSH公開鍵の削除と、google-sudoers グループからの削除だけです。(以下はグループから削除される前の様子です。)

ログイン直後の google-sudoers グループの設定
$ grep google-sudoers /etc/group
google-sudoers:x:1000:taro

もしユーザー自体を削除したければ、deprovision_remove というオプションを true にするとできます。

ユーザー自体の削除をコントロールするオプション
$ grep deprovision_remove /etc/default/instance_configs.cfg 
deprovision_remove = false

SSHボタンの認証のまとめ

というわけで長々書きましたが、途中で引用したドキュメントに書かれてた通り、以下のようなステップで認証がおこなわれていると分かりました。

  1. 短期的に使うSSH認証鍵をその場で作成
  2. インスタンスのメタデータに登録
  3. 登録されたメタデータにしたがってGoogle Guest Agentがユーザーの作成とSSH公開鍵を登録
  4. Googleアカウントと同じユーザー名と、作成されたSSHの秘密鍵を使ってログイン

gcloudコマンドでSSH接続

SSHボタンでの接続の説明だけで力尽きそうですが、次に手元の環境からgcloudコマンドで接続する方法を見てみます。(こちらのドキュメントgcloudタブに説明があります。)

ここではgcloudコマンドをインストールして認証まで終わった直後を想定します。つまり、gcloudコマンドが使えるようにはなったが、Compute Engine等のサービスにはまだ利用してない想定です。

まず、何はともあれログインを試してみます。(gcloud initでデフォルトゾーンを設定してる場合、--zoneオプションは省略できます。)

初めての gcloud ssh login
$ gcloud compute ssh instance-1 --zone=asia-northeast1-b
WARNING: The private SSH key file for gcloud does not exist.
WARNING: The public SSH key file for gcloud does not exist.
WARNING: You do not have an SSH key for gcloud.
WARNING: SSH keygen will be executed to generate a key.
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/laptopuser/.ssh/google_compute_engine
Your public key has been saved in /home/laptopuser/.ssh/google_compute_engine.pub
The key fingerprint is:
SHA256:cWbvXoA/pP3tyfl+s6pZP3AtN/rmdEwqk28CAUvZepc laptopuser@laptop
The key's randomart image is:
+---[RSA 3072]----+
|         o       |
|        + .      |
|       ..++  .   |
|        o=ooE    |
|        S..o+   o|
|          .* +.*o|
|          ..O.*++|
|           .+O===|
|           oo+B@@|
+----[SHA256]-----+
Updating project ssh metadata...⠏Updated [https://www.googleapis.com/compute/v1/projects/advent-calendar-2022-370404].
Updating project ssh metadata...done.
Waiting for SSH key to propagate.
Warning: Permanently added 'compute.274753849988700752' (ECDSA) to the list of known hosts.
Linux instance-1 5.10.0-19-cloud-amd64 #1 SMP Debian 5.10.149-2 (2022-10-21) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
laptopuser@instance-1:~$ w
 07:06:10 up 2 days, 23:32,  1 user,  load average: 0.00, 0.00, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
laptopus pts/0    20.243.185.154   07:03    0.00s  0.00s  0.00s w
laptopuser@instance-1:~$

無事ログインできました。出力から以下のことが分かります。

  • SSH認証鍵が作成されて、実行してるユーザーの ~/.ssh/google_compute_engine{,.pub} に保存された
  • 実行してるユーザー(例では laptopuser)のユーザー名が、そのままVMでも使われてる
  • プロジェクトのSSHメタデータとやらを更新したっぽい → Updating project ssh metadata...done.
  • gcloudコマンドを実行したホスト(20.243.185.154)から直接ログインしている

SSHボタンで接続する場合に比べだいぶシンプルです。

SSH認証鍵は実際に作成されて、gcloudコマンドを実行している環境に保存されています。(SSHボタンの場合にように、その場でエフェメラルな鍵が生成されているわけではありません。)

また、Linuxユーザー名にはgcloudコマンドを実行しているユーザー名が使われており、SSHボタンの場合のようにGoogleアカウントから生成はされていません。(なお、gcloudコマンドの認証自体は上の例と同じGoogleアカウントでおこなっています。)

さらに、プロジェクトのSSHメタデータとやらがSSHボタンの場合と違いました。SSHボタンの場合はインスタンスのメタデータに接続のタイミングでSSH認証鍵が登録されてましたが、今回はプロジェクトのメタデータが使われてるようです。確認してみます。

まず登録されてる公開鍵を見ると、SSHボタンの場合と違い、"userName""expireOn"のようなコメントはついていません。また、インスタンスのメタデータを見てもこの公開鍵は登録されていません。

登録されてるSSH公開鍵
$ cat .ssh/authorized_keys
# Added by Google
ssh-rsa AAA...mtc= laptopuser@laptop

そこでプロジェクトのメタデータを確認すると、確かに生成されたSSH公開鍵が登録されていました。


プロジェクトメタデータに登録されたSSH公開鍵

SSHボタンの場合のようにエフェメラルではなく、また登録先もインスタンスのメタデータではなくプロジェクトのメタデータなので、今後作られるすべてのVMインスタンスで共用できます。試しに新しいインスタンスを作ってログインしてみます。

別のインスタンスにログイン
laptopuser@laptop:~$ gcloud compute ssh instance-2
Warning: Permanently added 'compute.376864498427584915' (ECDSA) to the list of known hosts.
(中略)
laptopuser@instance-2:~$ cat .ssh/authorized_keys
# Added by Google
ssh-rsa AAA...mtc= laptopuser@laptop
laptopuser@instance-2:~$

SSH認証鍵の生成などはおこなわれず、普通に同じ鍵でログインできました。

そして最後のポイントであるログイン元ですが、普通にgcloudコマンドを実行したホストからになってることは、gcloud --verbosity=debugというデバッグオプションをつけると明示的に分かります。(手で改行を入れました。)

$ gcloud --verbosity=debug compute ssh instance-1
(略)
DEBUG: Executing command: ['/usr/bin/ssh', '-t',
  '-i', '/home/laptopuser/.ssh/google_compute_engine',
  '-o', 'CheckHostIP=no',
  '-o', 'HashKnownHosts=no',
  '-o', 'HostKeyAlias=compute.274753849988700752',
  '-o', 'IdentitiesOnly=yes',
  '-o', 'StrictHostKeyChecking=yes',
  '-o', 'UserKnownHostsFile=/home/laptopuser/.ssh/google_compute_known_hosts',
  'laptopuser@34.85.112.202']

ご覧の通り、要するにgcloudコマンドは、インスタンス名→IPアドレスの変換をした上で、適切なオプションを追加してローカルのSSHコマンドを実行しているだけです。(34.85.112.202instance-1のIPアドレスです。)

というわけでgcloudコマンドでの接続は以下の通り、比較的シンプルでした。

  1. SSH認証鍵を作成
  2. プロジェクトメタデータに登録(ユーザー名はローカルのユーザー名)
  3. Google Guest Agentがユーザーを作成し、SSH公開鍵をホームディレクトリに配置
  4. 作成したSSH認証鍵を使ってSSHコマンドで接続

SSHコマンドで接続

最後に手元の環境から普通のSSHコマンドを使ってログインする方法です。

もしgcloudコマンドで接続したことがあれば、上述の通りgcloudコマンドは実際にはSSHコマンドを実行しているだけなので、そのまま真似をすればログインすることは可能です。

SSHコマンドでログイン
$ ssh -i ~/.ssh/google_compute_engine laptopuser@34.85.112.202
Linux instance-1 5.10.0-19-cloud-amd64 #1 SMP Debian 5.10.149-2 (2022-10-21) x86_64
(後略)

しかしこれだとgcloudコマンドで接続した場合と変わらないので、いったんプロジェクトのメタデータからSSH公開鍵を削除し、デフォルトの状態からSSHコマンドで接続してみます。ドキュメントではサードパーティ製ツール使った場合の接続として説明されています。(とはいえ、やることはgcloudコマンドと同じです。)

まず初めにSSH認証鍵を作成します。試しにわざとローカルユーザー(laptopuser)と違うユーザー名(test)をコメントに入れてみます。

SSH認証鍵の作成
$ ssh-keygen -t rsa -f ~/.ssh/gcp -C test@laptop -b 2048
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/laptopuser/.ssh/gcp
Your public key has been saved in /home/laptopuser/.ssh/gcp.pub
The key fingerprint is:
SHA256:eyqdSoQWaKzD/XyPx+H/mXaHmg8hSl7ytGQl5SGd1W8 test@laptop
The key's randomart image is:
+---[RSA 2048]----+
|          ..oo.. |
| . .       +o.  .|
|  + .     . o   .|
|.o.  o     o    E|
|o. .o . S * .  . |
| . .o. o @ o .   |
|     o.o*.= .  . |
|     .o =*   ++..|
|      .+o...=*o .|
+----[SHA256]-----+

次に、作成したSSH公開鍵をメタデータに登録します。インスタンスメタデータもしくはプロジェクトメタデータのどちらでもいいですが、ここではプロジェクトメタデータに登録してみます。

まず先にSSH公開鍵の内容をコピーしておきます。

クリップボードにSSH公開鍵の内容をコピー
$ cat ~/.ssh/gcp.pub
ssh-rsa AAA...Qkv laptopuser@laptop

プロジェクトメタデータのページを開き、SSH認証鍵のタブを開きます。


プロジェクトメタデータ - SSH認証鍵

画面下の方の「SSH認証鍵を追加」をクリック。


SSH認証鍵の追加

テキストボックスに上でコピーしたSSHの公開鍵をペーストします。(ssh-rsaから末尾のコメントまで全部ペーストします。)保存ボタンを押して、期待通りのユーザー名で登録されているかを確認します。(例の場合はユーザー名 test


追加されたSSH認証鍵

すると裏でGoogle Guest Agentがせっせとユーザーを作ってるはずなので、SSHコマンドで接続してみます。

SSHコマンドでのログイン
$ ssh -i ~/.ssh/gcp test@34.85.112.202
Linux instance-1 5.10.0-19-cloud-amd64 #1 SMP Debian 5.10.149-2 (2022-10-21) x86_64

(中略)
test@instance-1:~$

問題なく設定したユーザー名 test を使ってログインできました。

ちなみにドキュメントにもありますが、SSHボタンの場合に使われていた "userName""expireOn" といった書式を使ってLinuxユーザー名を指定したり、SSH公開鍵の有効期限を設定することもできます。

というわけでSSHコマンドでの接続は以下の通りです。gcloudコマンドでの接続とほぼ同じですね。

  1. SSH認証鍵を作成
  2. プロジェクトメタデータに登録
  3. Google Guest Agentがユーザーを作成し、SSH公開鍵をホームディレクトリに配置
  4. 作成したSSH認証鍵を使ってSSHコマンドで接続

外部IPがないVMへSSH接続

ここまでの例はすべてVMに外部IPアドレス(パブリックIPアドレス)がある場合でした。そのため、普通にインターネット越しに(ファイアウォールさえ適切に設定されていれば)どこからでもアクセスできる状態でした。

しかし、本題の「Google Cloudをガチガチの環境で使ってみる」を実現するには外部IPアドレスを付けずに、内部IPアドレスだけで運用するという考え方もありそうです。

というわけで、外部IPアドレスがないVMへの接続の様子もみてみます。

まずは外部IPアドレスがないVMを作ります。「インスタンスの作成」ページで、「詳細オプション - ネットワーキング - ネットワークインターフェース」とたどり、「外部IPv4アドレス」の項目をデフォルトの「エフェメラル」から「なし」へ変更します。(「プライマリ内部IP」の項目も「エフェメラル」となっているので、間違えないよう気をつけてください。)


外部IPアドレスがないVMの作成

新しくVM(instance-2)ができあがると、外部IPが空欄になっていることがわかるかと思います。


外部IPアドレスがないVM

この状態でSSHボタンを押すと、普通にログインできます。

外部IPがないVMへのログイン
$ w
 11:04:33 up 3 min,  1 user,  load average: 0.02, 0.05, 0.01
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
user     pts/0    35.235.240.241   11:04    0.00s  0.00s  0.00s w

SSHボタンで接続のセクションを読まれていれば、接続元のIPアドレスからIAP経由でログインしてるとわかるかと思います。つまりIAPを経由すると外部IPがないVMへもログインできるのです。

では、IAPからの接続をファイアウォールでブロックするとどうなるでしょう?SSHボタンで接続のセクションで試した時は、IAPは経由しないものの、GoogleのIPアドレス範囲にあるSSHのプロキシらしきものを通して接続できていました。今回はどうでしょう?


IAPをブロックして、外部IPがないVMへSSHボタンで接続

上記のようにエラーになってしまいました。Cloud Identity-Aware Proxy を介した接続に失敗しましたと表示されていることから、外部IPがないVMへの接続にはIAP経由が必須のようです。

では、gcloudコマンドでの接続はどうでしょう?(先にIAPをブロックするファイアウォールを削除するか、無効にしておきます。)

gcloudコマンドで外部IPのないVMへ接続
laptop$ gcloud compute ssh instance-2
External IP address was not found; defaulting to using IAP tunneling.
WARNING:

To increase the performance of the tunnel, consider installing NumPy. For instructions,
please see https://cloud.google.com/iap/docs/using-tcp-forwarding#increasing_the_tcp_upload_bandwidth

Linux instance-2 5.10.0-19-cloud-amd64 #1 SMP Debian 5.10.149-2 (2022-10-21) x86_64
(中略)
laptopuser@instance-2:~$ w
 11:26:27 up 25 min,  1 user,  load average: 0.00, 0.01, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
laptopus pts/0    35.235.242.49    11:25    1.00s  0.00s  0.00s w
laptopuser@instance-2:~$

上記gcloudコマンドの出力にExternal IP address was not found; defaulting to using IAP tunneling.とあるように、gcloudコマンドはVMに外部IPがないことに気づいて、自動的にIAPを経由して接続しています。(明示的に指定する場合は --tunnel-through-iap というオプションが使えます。)

なお、gcloudコマンドによるIAPを経由した接続と、それを利用したSSHコマンドでの接続の詳細については、以前ブログ記事(「外部アドレス無しインスタンスへのアクセス」のセクション)にまとめましたので参考にしてください。

というわけで、外部IPアドレスがないVMの場合、IAPを経由すると接続できることが分かりました。

SSH接続のまとめ

ここまでSSHボタン、gcloudコマンド、SSHコマンドの3つの方法による接続をみてきました。

SSHボタンの場合は接続元が(IAPのIPアドレス範囲も含め)GoogleのIPアドレス範囲からになりますが、gcloudコマンド/SSHコマンドの場合は普通に実行しているホストが接続元になることが確認できました。

また認証については、利用者が各自で任意のユーザー名を指定でき、SSH認証鍵を後からでも指定できる点は特徴的かなと思います。(ついでに、SSHボタンを使う場合はSSH認証鍵すら動的に生成され、有効期限付きで設定されている事が分かりました。)

(たとえば、Amazon EC2Azure VMでは、Linuxユーザー名が固定もしくは1つだけ設定され、SSH認証鍵も起動時に指定する形式です。)

また、IAPを使う場合はIAPのアドレス範囲を許可するため、本記事の「ユーザーが認証情報を盗まれた場合」を前提とすると、(IAPを経由すれば)どこからでもアクセスできることになります。

(もちろん、接続ユーザーの権限(「IAPで保護されたトンネルユーザー」)は確認するので、Googleアカウントの認証を厳格にすることによって安全に運用できます。)

アクセス制限 IAPの利用
外部IPあり ファイアウォール 任意
外部IPなし 認証(APIアクセス時) 必須

(SSH鍵認証等のOSによるアクセス制限は共通なので表から割愛してます。)

シリアルコンソール接続

さて、ここまではSSHによる接続だけを扱ってきましたが、Compute Engineではシリアルコンソールへも接続できます。

Cloud Console上で接続

まず、VMのリストから当該VMをクリックして詳細を表示し、「ログ」セクションにある「シリアルポート1(コンソール)」のリンクをクリックすることで、シリアルコンソールへの出力を見ることができます。


シリアルコンソール出力へのリンク


シリアルコンソール出力の例

OSのログには残らないUEFIブートのログを確認できると思います。

また、シリアルコンソール経由でOSへのログインも可能です。ただ、デフォルトでは無効化されているので、初めに有効化します。

同じくVMのリストから当該VMをクリックして詳細を表示し、上部にある「編集」ボタンをクリックします。そして「基本情報」のすぐ下に「シリアルポートへの接続を有効にする」というチェックボックスがあるので、チェックして保存します。


実行中のVMでシリアルコンソールへのアクセスを有効化

また、VM作成時にシリアルコンソールを有効化するには、「詳細オプション - 管理」の中にある「メタデータ」に、キーとしてserial-port-enable、値としてTRUEを設定します。


VM作成時にシリアルコンソールへのアクセスを有効化

シリアルコンソールを有効にすると、VMの詳細ページのトップにある「シリアルコンソールに接続」というボタンが有効になります。


シリアルコンソールに接続ボタン

ボタンをクリックすると初めにSSHキーをシリアルコンソールリレーに転送しています。としばらく出て、その後インタラクティブシリアルコンソールへの接続を確立しています…と少し出た後シリアルコンソールにつながります。

OSの設定にもよりますが、Debian/Ubuntu/RHEL等のデフォルトのCompute Engineイメージの場合、一度Enterを押すことでログインプロンプトが出てくると思います。


シリアルコンソールのログインプロンプト

ただし、上で説明したSSH接続の例からわかるように、通常Compute EngineへのSSH接続にはローカルパスワードを使っておらず実際に設定もされていないので、ログインプロンプトが出てもログインできません。そこで、まずはSSHでログインしてローカルパスワードを設定しておきます。

ローカルパスワードの設定
taro@instance-1:~$ sudo passwd $(whoami)
New password:
Retype new password:
passwd: password updated successfully
taro@instance-1:~$

passwdコマンドだけだと権限の問題で自分のパスワードを設定できなかったので、sudoを使ってroot権限で設定してます。)

ここで設定したパスワードを使うと無事シリアルコンソール経由でログインできました。


シリアルコンソールでログイン

なお、シリアルコンソールへの接続時の認証は、SSHボタンの場合と同じように、エフェメラルなSSH認証鍵が作成されVMのメタデータに登録されることでおこなわれています。

ただし一点違うところは、最初にSSHキーをシリアルコンソールリレーに転送しています。と出ていたように、作成されたSSH認証鍵はVMへの接続に使われるのではなく、(Google管理の)シリアルコンソールリレーへの接続に使われるという点です。


シリアルコンソールリレーへのSSHアクセス


さて、ドキュメントによると、gcloudコマンドやSSHコマンドでも接続できるとのことなので、それぞれ試してみます。

gcloudコマンドで接続

gcloudコマンドではconnect-to-serial-portを使います。Cloud Console上での接続と同じように、ログインプロンプトが出て普通にログインできました。

gcloudコマンドで接続
$ gcloud compute connect-to-serial-port instance-1
Updating project ssh metadata...⠏Updated [https://www.googleapis.com/compute/v1/projects/advent-calendar-2022-370404].
Updating project ssh metadata...done.
serialport: Connected to advent-calendar-2022-370404.asia-northeast1-b.instance-1 port 1 (session ID: 308ee1fa47a9a0950433470ddb192b3cf34eefb8ee5caac473e3fae442f2fca1, active connections: 1).

instance-1 login: taro
Password:
Linux instance-1 5.10.0-19-cloud-amd64 #1 SMP Debian 5.10.149-2 (2022-10-21) x86_64

(中略)
taro@instance-1:~$

ちなみにシリアルコンソールからの切断は~.です。(ところで、一般にシリアルコンソールからの切断は昔から~.ですよね。何が起源なんですかね?)

さて、詳細の確認のために--verbosity=debugオプションを付けて実行してみると、以下のようにssh-serialport.googleapis.comというホストに対してadvent-calendar-2022-370404.asia-northeast1-b.instance-1.laptopuser.port=1というユーザー名で接続していることが分かります。

gcloud compute connect-to-searil-portが実行してるもの
DEBUG: Executing command: ['/usr/bin/ssh', '-t', '-p', '9600',
  '-i', '/home/laptopuser/.ssh/google_compute_engine',
  '-o', 'CheckHostIP=no',
  '-o', 'ControlPath=none',
  '-o', 'HashKnownHosts=no',
  '-o', 'IdentitiesOnly=yes',
  '-o', 'StrictHostKeyChecking=yes',
  '-o', 'UserKnownHostsFile=/home/laptopuser/.ssh/google_compute_known_hosts'
  'advent-calendar-2022-370404.asia-northeast1-b.instance-1.laptopuser.port=1@ssh-serialport.googleapis.com']

ユーザー名は以下のようなフォーマットになっています。

(プロジェクトID).(ゾーン).(VM名).(Linuxユーザー名).(オプション)

例:advent-calendar-2022-370404.asia-northeast1-b.instance-1.laptopuser.port=1

また、認証の仕組みはSSH接続の場合と同じように、プロジェクトのメタデータに登録されているSSH公開鍵です。つまり、シリアルコンソールリレー(ssh-serialport.googleapis.com)への接続の認証に、ローカルで作成し(プロジェクトのメタデータに登録され)たSSH認証鍵が使われている、ということです。

SSHコマンドで接続

最後に上のgcloudコマンドが実行してるものと一緒ですが、SSHコマンドでも接続してみます。

SSHコマンドでシリアルコンソールに接続
$ ssh -i ~/.ssh/google_compute_engine -p 9600 \

serialport: Connected to advent-calendar-2022-370404.asia-northeast1-b.instance-1 port 1 (session ID: b0676165711e26c70f8b59f44053401b52f053b9c7b6aaf3c62734656b85c259, active connections: 1).
(中略)
instance-1 login: taro
Password:
Linux instance-1 5.10.0-19-cloud-amd64 #1 SMP Debian 5.10.149-2 (2022-10-21) x86_64
(中略)
taro@instance-1:~$ w
 02:28:32 up  2:34,  1 user,  load average: 0.00, 0.00, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
taro     ttyS0    -                02:28    0.00s  0.04s  0.00s w
taro@instance-1:~$

認証の仕組みもgcloudコマンドの場合と同じく、メタデータに登録されたSSH公開鍵によるものです。(つまり事前にインスタンスまたはプロジェクトのメタデータにSSH公開鍵を登録しておく必要があります。)

シリアルコンソール接続のまとめ

ここまでシリアルコンソールに接続する方法を見てきましたが、SSHの接続先がVMではなくシリアルコンソールリレーになったということ以外は、通常のSSH接続と同じ接続方法、認証方法であることが分かったかと思います。

ただし、接続先がVMではないというのが大きな違いになります。それは、VPCのファイアウォールが使えない、という点です。

ドキュメントにも以下の通り明示的に書かれていますが、シリアルコンソールリレー(ssh-serialport.googleapis.com)へのアクセスはVPCのファイアウォールでは制限できないため、どこからでもアクセスできます。


シリアルコンソール接続使用時の注意

また、ここまで見てきたように、シリアルコンソールリレーへの接続の認証はSSH認証鍵に依存しているため、SSH認証鍵が奪取された場合は接続を制御できません。(そして本記事では認証情報は奪取される前提です。)

したがって、シリアルコンソールの使用は開発環境などでの一時的な利用にとどめ、本番環境での利用は組織のポリシーで無効にするのがよいと思います。

そのような使い方を想定した場合、VMを停止したり再起動したりせずとも、VMの設定だけでシリアルコンソール接続を簡単に有効化できるのはメリットだと思いました。(gcloudコマンド1つで有効化もできます。)

シリアルコンソール接続を有効化
$ gcloud compute instances add-metadata instance-1 \
      --metadata=serial-port-enable=true
Updated [https://www.googleapis.com/compute/v1/projects/advent-calendar-2022-370404/zones/asia-northeast1-b/instances/instance-1].

その他のアクセス手段

というわけで、ここまで確認してきたSSHでの接続とシリアルコンソール接続さえ気にしていれば問題ないでしょうか?Compute Engineへのアクセス手段にはあと少し残っています。

ロードバランサー

Compute Engineへのアクセス手段と呼ぶのは少し違うかもしれませんが、ロードバランサーのバックエンドとしてCompute Engineを設定することで、通常のSSH接続とは異なる経路でアクセスできるようになるのは間違いありません。

ここでは色々あるロードバランサーのうち、外部TCPプロキシロードバランサ外部TCPネットワークロードバランサーを試してみます。

外部TCPプロキシロードバランサー

外部TCPプロキシロードバランサーはプロキシ型のロードバランサーで、グローバルに1つのエニーキャストIPアドレスで、複数リージョンのバックエンドへの負荷分散をするのに使えます。


TCPプロキシ

プロキシ型のロードバランサーなので、クライアントからのTCPセッションはロードバランサーでいったん終端され、ロードバランサーからバックエンドへは新しいTCPセッションが作られます。

TCPプロキシ経由でSSH
$ ssh -i ~/.ssh/google_compute_engine 34.98.82.111
Linux instance-1 5.10.0-19-cloud-amd64 #1 SMP Debian 5.10.149-2 (2022-10-21) x86_64
(中略)
laptopuser@instance-1:~$ w
 07:22:37 up  7:28,  1 user,  load average: 0.02, 0.02, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
laptopus pts/0    130.211.3.141    07:22    5.00s  0.00s  0.00s w
laptopuser@instance-1:~$

接続元の130.211.3.141TCPプロキシ(や他のプロキシ型ロードバランサー)がバックエンドへ接続する際に使うIPアドレスです。

外部TCP/UDPネットワークロードバランサー

外部TCP/UDPネットワークロードバランサーはパススルー型のロードバランサーで、任意のTCP/UDPトラフィックを負荷分散するのに使えます。


ネットワークロードバランサー

パススルー型のロードバランサーなのでクライアントのIPアドレスはそのままでバックエンドまで到達します。

ネットワークロードバランサー経由でSSH
$ ssh -i ~/.ssh/google_compute_engine 35.200.13.108
Linux instance-1 5.10.0-19-cloud-amd64 #1 SMP Debian 5.10.149-2 (2022-10-21) x86_64
(中略)
laptopuser@instance-1:~$ w
 07:15:39 up  7:21,  1 user,  load average: 0.00, 0.00, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
laptopus pts/0    20.243.185.154   07:15    0.00s  0.00s  0.00s w
laptopuser@instance-1:~$

接続元の20.243.185.154はSSHコマンドを実行しているホストのIPアドレスです。

プロトコル転送

プロトコル転送(Protocol Forwarding)はロードバランサーに似ていますが、ロードバランサーの一部である転送ルール(Forwarding Rule)の宛先として、直接Compute Engine VMを指定するものです。

プロトコル転送の仕組みを使うと、転送ルールに設定された外部IPアドレスへ来たトラフィックが直接VMへ届けられます。つまり、VMの外部IPアドレスとは別の外部IPアドレス経由でVMへ到達できることになります。これは、VMに外部IPアドレスがない場合でも同様です。

つまりプロトコル転送の仕組みは、通常のVMの(内部/外部)IPアドレスとは別の入り口(IPアドレス)を作ることと同義なのです。

論より証拠、設定してみましょう。(Cloud Consoleでの設定はサポートされていないので、gcloudコマンドを使います。)

プロトコル転送の設定とプロトコル転送経由のアクセス
$ gcloud compute target-instances create protocol-forwarding-1 \
      --instance=instance-1
Created [https://www.googleapis.com/compute/v1/projects/advent-calendar-2022-370404/zones/asia-northeast1-b/targetInstances/protocol-forwarding-1].
NAME                   ZONE               INSTANCE    NAT_POLICY
protocol-forwarding-1  asia-northeast1-b  instance-1  NO_NAT

$ gcloud compute forwarding-rules create forwarding-rule-1 \
      --target-instance=protocol-forwarding-1 \
      --ip-protocol=TCP \
      --ports=22
Created [https://www.googleapis.com/compute/v1/projects/advent-calendar-2022-370404/regions/asia-northeast1/forwardingRules/forwarding-rule-1].

$ gcloud compute forwarding-rules describe forwarding-rule-1 \
      --format="value(IPAddress)"
35.200.70.113

$ ssh -i ~/.ssh/google_compute_engine 35.200.70.113
Linux instance-1 5.10.0-19-cloud-amd64 #1 SMP Debian 5.10.149-2 (2022-10-21) x86_64

(中略)
laptopuser@instance-1:~$ w
 06:31:01 up  6:36,  1 user,  load average: 0.00, 0.00, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
laptopus pts/1    20.243.185.154   05:58    0.00s  0.00s  0.00s w
laptopuser@instance-1:~$

上の方で見たようにinstance-1の外部IPアドレスは34.85.112.202ですが、新しく作られた転送ルールのIPアドレス35.200.70.113でもSSH接続できています。

接続元はgcloudコマンドでSSH接続のセクションでの結果と同じように、gcloudコマンドを実行したホストになっています。

その他のアクセス手段のまとめ

以上のように、ロードバランサーやプロトコル転送を使うことで、VMの外部IPアドレスとは異なるIPアドレスでも接続できるようになります。

とはいえVMへのアクセス制御の観点では接続元や認証方法は重要ですが、通常アクセス先のIPアドレスは重要じゃない、いずれの場合でも追加で考慮しなければならない点はなさそうです。(ただし、プロキシ型ロードバランサーの場合は接続元も変わるので、その点だけ考慮が必要です。)

一方、アクセス経路の制限という観点では考慮する必要があり、もし外部ロードバランサーやプロトコル転送を利用する予定がなければ、組織ポリシーでプロトコル転送の利用を制限することもできます。

また、IAMでロードバランサーを作成する権限を制限することで、不用意にロードバランサーやプロトコル転送を設定され、予期せぬ経路でアクセスされることを防ぐこともできます。

アクセス制限

ここまで必要以上に丁寧にCompute Engineへのアクセス方法を確認してきましたが、最後にその理解を前提にどのようにアクセス制限をしたらよいかを考えてみたいと思います。

まずCompute Engineへのアクセス方法ですが、ここまでに見てきた通り5つの経路がありました。

  1. クライアントからGoogleのIP範囲を経由したアクセス
  2. クライアントからGoogleのIP範囲+IAPを経由したアクセス
  3. クライアントから外部IPへの直接アクセス
  4. シリアルコンソールを使ったアクセス
  5. 転送ルール(Forwarding Rule)を使ったアクセス

まず「(自分たちのコントロール下にある)特定のIPアドレス範囲からのみのアクセスに制限したい」というのが要件だとすると、このうち 1.2. はGoogle Cloudのユーザーすべてが共有/利用するIPアドレス範囲なので利用には適さないと思います。

とくにIAPを用いた 2.外部IPがないVMにアクセスする手段として魅力的ですが、上記の理由によりIPアドレスベースのアクセス制限をするのには向きません。

3. のクライアントからの直接接続に関しては普通にアクセス元のIPアドレスをベースに、VPCファイアウォールでアクセス制限するのが良いでしょう。これまでVPCにおけるファイアウォールはファイアウォールルールという仕組みを使ってきましたが、最近ではファイアウォールポリシーという新しい仕組みも使えるようになり、より管理がしやすくなっています。

また、ファイアウォールポリシーの類型として階層型ファイアウォールポリシーという仕組みもあります。ファイアウォールルールやファイアウォールポリシーはどちらもVPCの単位で設定するものですが、階層型ファイアウォールポリシーでは、組織(Organization)やフォルダの単位でファイアウォールを設定することで、多くのVPCに一律でアクセス制限を設定できます。内容が少し古くなってしまっていますが、以前階層型ファイアウォールポリシーについてブログ記事にまとめましたので参照いただけると幸いです。

なお、本記事では触れませんでしたが「アクセス元」としてはインターネット経由だけでなく、オンプレミス等の閉域網(Cloud Interconnectによる専用線接続やCloud VPNによるインターネットVPN接続)経由でのアクセスも考慮しておきましょう。インターネットからの接続(パブリックIPアドレスからのアクセス)は階層型ファイアウォールポリシーなどで一律不許可にし、オンプレミスで使っているプライベートIPアドレスからのアクセスだけ個別に許可する、というのは一番シンプルな設定の1つと言えるかと思います。

次に 4. のシリアルコンソールですが、上にもある通りIPアドレスベースのアクセス制限ができないので、本番環境や常時利用は避け、開発環境などでの一時的な利用に留めておくのがオススメです。また、もし不要であれば意図しない利用を防ぐためにも、組織のポリシーによる無効化を検討してみてください。

最後に 5. の転送ルール/ロードバランサー経由でのアクセスは、これまでの制限の話とは少し違って、アクセス元の違いではなく、アクセス経路の違いになります。ですので、ここまでで適切にアクセス元による制限ができていれば気にする必要はありません。しかし予期せぬIPアドレス経由で予期せぬポートにアクセスされる可能性を排除したいのであれば、同じく組織ポリシーで制限できます。

終わりに

Compute Engineへのアクセスなんて一番基本的な内容なんだからあんまり書くことなくて短い記事になっちゃったらどうしよう?と思いながら書き始めたんですが、思いのほか普段自分が気にせず使ってるけど仕組みを理解してないところが多くて、そこを深堀りして行ったら長い記事になってしまいました。

そもそもCompute Engineへのアクセス制限をするだけなら、必ずしもこういった細かい仕組みとかを理解する必要はなかったかもしれないですが、やはりそこを理解しないで「こうやればいいんだよ」だけをやってるとそこはかとない不安を拭えないと思うので、ぜひ本記事を参考にしつつ自信を持って安全なCompute Engineの環境を構築していただけると嬉しいです。

次のGoogle Cloud Japan Advent Calendar 2022の記事はFirebase update summary 2022です。ぜひ合わせてご覧ください。

Google Cloud Japan

Discussion