🤘

フルマネージドなプロキシサービス Secure Web Proxy を試す

2023/06/21に公開

はじめまして。クラウドエース株式会社で Google Cloud 認定トレーナーをしている廣瀬 隆博です。弊社には廣瀬が複数名おりますので、絵文字がメロイックサイン(🤘)になっている人だと覚えていただけると幸いです。

さて、今回は Google Cloud において 2023 年 5 月 22 日に一般公開された Secure Web Proxy についてご紹介していきます。このサービスは文字通り Web Proxy であり、Web サイトへのアクセスを中継してくれます。同じような働きをするオープンソースソフトウェアでは Squid が有名ですね。

概要

そもそも、Web Proxy はどのような時に使用するのでしょうか。Web Proxy では、Web サイトへのアクセスを中継する際に許可・拒否を制御することができます。つまり、業務に必要な Web サイト のみアクセスを許可することや、業務に不要な Web サイトへのアクセスを拒否することができます。また、中継した情報をログに記録することができますので、いつ・誰が・どこへアクセスしたのか監査することができるようになります。

似たような仕組みとして、外部 IP アドレスを持たないサーバーインスタンス等がインターネットへアクセスする場合は Cloud NAT を用いることがあります。しかし、Cloud NAT では上記のようなアクセス制御はできません。つまり、インターネットへアクセスしたいだけなら Cloud NAT、アクセス制御を実装したければ Web Proxy といった使い分けになります。

今回ご紹介する Secure Web Proxy はフルマネージドサービスですので、冗長性の考慮やセキュリティパッチの適用といった煩雑な運用作業から解放されます。 管理者が本来注力したいアクセス制御やログの監査に集中することができますので、Web Proxy の運用に手間を感じている場合は是非とも導入を検討していただければと思います。

[公式ドキュメント] Secure Web Proxy overview

事前準備

それでは、Secure Web Proxy を動かすための事前準備から初めていきましょう。今回は新しいプロジェクトを用意して検証しています。

[Google Cloud Console] 新しいプロジェクト

権限付与

公式ドキュメントでは roles/compute.networkAdminroles/certificatemanager.editor を付与していますが、今回は検証用ですので roles/owner で対応します。ちゃんと稼働させる環境を構築する際には、厳格な権限付与をお勧めします。

[Google Cloud Console] IAM

権限付与

API 有効化

今回の検証では以下の API が必要となりましたので、始める前に有効化しておくとスムーズですね。今回の本題ではないので詳細は割愛しますが、対象のAPIを見つけて有効化してください。

  • Compute Engine API
  • Network Services API
  • Certificate Manager API
  • Network Security API

[Google Cloud Console] API ライブラリ

API 有効化

ネットワーク作成

プロジェクトを作成した際に自動生成される default ネットワークは既定 Firewall ルールいくつかが動作しており、検証には不向きです。今回は新たに検証用ネットワーク secure-web-proxy-test を作成します。その際に、プロキシをテストするための VM が稼働するサブネット vm-subnetasia-northeast1 に作成しておきます。

ネットワークの作成後は、Secure Web Proxy が動作するプロキシ サブネット proxy-subnet を追加します。後から追加する理由は、VPC 作成画面ではサブネットの目的を指定することができないためです。また、サブネットのサイズは /23 以上が推奨されるようなので、今回は /16 としました。

プロキシ サブネット

ネットワーク作成手順の詳細は割愛しますが、必要に応じて以下の公式ドキュメントをご参照ください。

[公式ドキュメント] IPv4 サブネットのみを持つカスタムモードの VPC ネットワークを作成する

[Google Cloud Console] VPC ネットワーク

サブネット作成後画面

SSL 証明書の作成と登録

Secure Web Proxy の作成には、SSL 証明書が必要です。Google Cloud には Cloud Shell と呼ばれる コマンド操作用の Linux 環境があり、証明書を作成するために必要な OpenSSL が導入されています。コンソールの右上にある Cloud Shell のアクティブ化ボタンを押せばすぐにこの環境が起動し、1コマンドで自己証明書を作成することができます。

Cloud Shell

今回は以下の要件で自己証明書を作成しました。

  • 秘密鍵名 : key.pem
  • 証明書名 : cert.pem
  • 有効期限 : 36500 日(およそ 100 年)
  • ホスト名 : myswp.example.com
openssl req -x509 -newkey rsa:2048 \
  -keyout ./key.pem \
  -out ./cert.pem -days 36500 \
  -subj '/CN=myswp.example.com' -nodes -addext \
  "subjectAltName=DNS:myswp.example.com"

このコマンドによって Cloud Shell 上に秘密鍵と証明書が作成されました。これを Certificate Manager に登録する必要があります。現在は GUI で登録する機能が提供されていませんので、Cloud Shell から以下のコマンドで登録します。

gcloud certificate-manager certificates create secure-web-proxy-cert \
   --certificate-file=./cert.pem \
   --private-key-file=./key.pem \
   --location=asia-northeast1

登録した結果は GUI から確認することができます。この証明書は、後ほど Secure Web Proxy を作成する際に指定します。

なお、今回は検証ということもあって自己証明書、いわゆるオレオレ証明書を使用しています。これによって発生する事象は後ほどご紹介いたします。

[Google Cloud Console] 証明書マネージャ

自己証明書

TLS インスペクション

昨今の Web 通信はほとんど暗号化されています。これは通信秘匿の観点からとても良いことですね。しかし、暗号化されていることによって Web Proxy から通信先の URL を確認することができず、より高度なアクセス制御はできません。ではどのように対策すれば良いでしょうか?一度通信を復号してしまえば良いですね。これは TLS インスペクションと呼ばれる仕組みですが、この仕組みについて解説すると長くなってしまうので詳細は割愛します。

Secure Web Proxy にも TLS インスペクション機能は存在するのですが、手順が少し煩雑なこともあり、今回は実装しません。TLS インスペクションを使わない場合、ドメイン名のみ制御することが可能です。後ほど Secure Web Proxy の動作を確認しますので、その際に TLS インスペクションの使いどころも確認しましょう。

[公式ドキュメント] TLS inspection overview

Web Proxy 構築

では、本番の Web Proxy 構築に入りましょう。しかし、いきなり Secure Web Proxy を作成することはできません。作成時に ポリシーを指定する必要があるので、まずはポリシーから作成します。

[Google Cloud Console] セキュア ウェブプロキシ

ポリシー作成

ポリシーの名前とリージョンを指定します。今回は swp-test-policy という名称で東京リージョンに作成しました。この画面ではルールも指定できますが、現在は何も指定していません。

ポリシー作成ボタン

ポリシー作成画面

Secure Web Proxy 作成

さて、いよいよ Secure Web Proxy の作成ですね。これまでに準備してきたものを以下のように指定しました。

  • 名前 : swp-test
  • リージョン : asia-northeast1 (東京)
  • ネットワーク : secure-web-proxy-test
  • サブネットワーク : vm-subnet
  • ウェブプロキシ IP アドレス : 10.0.0.2
  • ポート : 3128
  • 証明書 : secure-web-proxy-cert
  • 関連ポリシー : swp-test-policy

注意点として、ここではサブネットワークに vm-subnet を選択します。proxy-subnet は Secure Web Proxy が動作するための内部的なネットワークのため、選択肢にも出てきません。また、ウェブプロキシの IP アドレスとポートは、Secure Web Proxy を使用する際に指定する情報です。後ほどテストで出てきますので、その際に確認しましょう。

Secure Web Proxy 作成ボタン

Secure Web Proxy 作成画面

無事に Secure Web Proxy が稼働しました🎉

Secure Web Proxy 作成画面

テスト VM 作成

Secure Web Proxy が無事に稼働したので、動作を確認するための VM を作成しましょう。今回の本題ではないので、Cloud Shell からコマンドでサクッと作ってしまいます。注意点として、テスト VM は外部 IP アドレスを持たせてはいけません。これは、Secure Web Proxy を介さず外部 IP アドレスから直接インターネットへアクセスさせないためです。

gcloud compute instances create user-pc-01 \
    --project=<プロジェクト名> \
    --zone=asia-northeast1-a \
    --machine-type=e2-medium \
    --network-interface=private-network-ip=10.0.0.3,stack-type=IPV4_ONLY,subnet=vm-subnet,no-address \
    --provisioning-model=SPOT \
    --create-disk=auto-delete=yes,boot=yes,device-name=user-pc-01,image=projects/rocky-linux-cloud/global/images/rocky-linux-9-optimized-gcp-v20230615,mode=rw,size=20,type=projects/<プロジェクト名>/zones/asia-northeast1-a/diskTypes/pd-balanced \

また、IAP を用いて SSH 接続をしたいので、Firewall ルールを追加します。こちらもコマンドで作ってしまいましょう。IAP については弊社の別記事が参考になりますので、よろしければご覧ください。

IAP を使って外部 IP を持たない Compute Engine(WindowsVM)にリモートデスクトップ接続する方法

gcloud compute firewall-rules create allow-iap-ssh \
    --project=<プロジェクト名> \
    --direction=INGRESS \
    --priority=1000 \
    --network=secure-web-proxy-test \
    --action=ALLOW \
    --rules=tcp:22 \
    --source-ranges=35.235.240.0/20 \
    --target-service-accounts=<サービスアカウント名>

動作検証

動作検証の準備が整いましたので、適宜設定を変更しながら Secure Web Proxy の挙動を確認します。

テスト VM への SSH 接続

テスト VM へ SSH 接続するには、Cloud Shell から gloud compute ssh コマンドを使用します。

gcloud compute ssh user-pc-01 --zone=asia-northeast1-a
External IP address was not found; defaulting to using IAP tunneling.
(略)
[hirose_takahiro@user-pc-01 ~]$

ルール無しでの動作

まず初めに、テスト用 VM が直接インターネットへアクセスできないことを確認します。curl コマンドに --max-time <秒数> を指定すると、タイムアウトまでの秒数を指定することができるので活用しましょう。接続先は本ブログ https://zenn.dev とします。

[hirose_takahiro@user-pc-01 ~]$ curl --max-time 2 https://zenn.dev
curl: (28) Connection timed out after 2001 milliseconds
[hirose_takahiro@user-pc-01 ~]$ 

上記のようにタイムアウトしました。次に、Secure Web Proxy を介してインターネットへアクセスしてみましょう。curl コマンドに -x <Secure Web ProxyのIPアドレス:ポート番号> を追加することで、Web Proxy を指定して curl コマンドを実行することができます。

[hirose_takahiro@user-pc-01 ~]$ curl -x https://10.0.0.2:3128 https://zenn.dev
curl: (60) SSL certificate problem: self-signed certificate
More details here: https://curl.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
[hirose_takahiro@user-pc-01 ~]$ 

エラーが発生しました。これは、「指定した Web Proxy はオレオレ証明書だから信頼できないよ」といった趣旨のエラーですね。今回は検証ということもあり、このエラーを無視するために --proxy-insecure オプションを追加します。

[hirose_takahiro@user-pc-01 ~]$ curl -x https://10.0.0.2:3128 https://zenn.dev --proxy-insecure
curl: (56) Received HTTP code 403 from proxy after CONNECT
[hirose_takahiro@user-pc-01 ~]$ 

Secure Web Proxy が 403 を返しました。これは閲覧禁止を示すエラーコードですね。つまり、ルールに引っかからない場合はアクセスを拒否するという、いわゆる暗黙の拒否ルールが存在するようです。

接続許可ルールを追加

上記を裏付けるために、接続許可ルールを追加しましょう。セッションの一致欄に host() == 'zenn.dev' と指定します。優先度は重複しても良いので、とりあえず 1000 としました。

ルール追加ボタン

ルール作成画面

ルール作成結果

ルールありでの動作

これで zenn.dev への接続は許可されたはずなので試しましょう。なお、ここからは --head オプションを用いることでヘッダのみ表示されるようにします。これは、アクセスが成功した場合に大量の文字が帰ってくることを防ぐ目的ですね。

[hirose_takahiro@user-pc-01 ~]$ curl -x https://10.0.0.2:3128 https://zenn.dev --proxy-insecure --head
HTTP/1.1 200 OK
(略)

遂に接続 OK の 200 が返ってきました。ルールに従ったアクセスは許可されることが確認できましたね。念のために、google.com にはアクセスできないことを確認しておきましょう。

[hirose_takahiro@user-pc-01 ~]$ curl -x https://10.0.0.2:3128 https://google.com --proxy-insecure --head
HTTP/1.1 403 Forbidden
(略)

想定通り google.com にはアクセスできないですね。これで、ホワイトリスト形式で動作させることができるようになりました。

ブラックリスト形式を試す

ホワイトリスト形式では接続を許可する対象が多すぎて使いづらい場合もあります。ここでは、暗黙の拒否ルールが効かないように優先度を最も低く設定した全通信許可ルールを追加します。演算子 .matches を用いることで正規表現が使用できるので、host().matches('.*') を許可することで実現できるはずですね。

ルール追加画面

ルール追加結果

では、さきほどは接続できなかった google.com に再接続してみましょう。

[hirose_takahiro@user-pc-01 ~]$ curl -x https://10.0.0.2:3128 https://google.com --proxy-insecure --head
HTTP/1.1 200 OK
(略)

うまく繋がりました。これであらゆるサイトに接続できるようになったのですが、ブラックリスト形式として扱うために拒否の動作を確認しておきましょう。zenn.dev へのアクセス許可設定を拒否に変更してみます。名前が allow から始まるのに拒否ルールであることは違和感しかありませんが、後から名前を変えられないので今回は気にしないでいきましょう。

ルール変更画面

ルール変更結果

[hirose_takahiro@user-pc-01 ~]$ curl -x https://10.0.0.2:3128 https://zenn.dev --proxy-insecure --head
HTTP/1.1 403 Forbidden
(略)

無事に zenn.dev への接続が拒否されました。これで、ホワイトリスト形式・ブラックリスト形式ともに実現可能ですね。

TLS インスペクションによって実現できること

今回の検証では、zenn.devgoogle.com といったドメイン名に対するアクセスを制御しました。TLS インスペクションを用いると、ドメイン名だけではなく URL に対するアクセスが制御できるようになります。例えば zenn.dev/cloud_ace/ だけアクセスを許可するといった形ですね。もしそういった制御が必要となった場合は TLS インスペクションの導入を検討しましょう。

まとめ

今回は Secure Web Proxy の動作を試してみました。動かしてみるとシンプルで使いやすいですね。とはいえ、以下のようなハマりどころがあり、本記事を完成させるまでに意外と四苦八苦しました。

  • VPC 作成時にプロキシ用サブネットを同時作成することはできない
  • 先にポリシーを作成しておかないと Secure Web Proxy が作成できない
  • 自己証明書では Secure Web Proxy 使用時にエラーが出る

特に自己証明書について、セキュリティの観点から本稼働させるシステムでは証明書に関するエラーを許容することはできません。一般的な端末に登録済みの認証局から証明書を発行してもらうか、もし自己証明書を使用する場合はルート証明書を利用者の環境へ登録する必要があります。他にも、今回は検証しなかった TLS インスペクションを使用したい場合は追加の考慮が必要となります。

このように書くと考慮点の多く使いづらい印象を与えるかもしれませんが、これらの多くは Secure Web Proxy 独自の考慮ではなく、Web Proxy で一般的に考慮すべき内容です。今回のように「まずは動かしてみる」ことで設計ポイントが理解できるようになりますので、本記事がこれから Secure Web Proxy を使い始める皆さまの助けとなれば幸いです。

クラウドエース株式会社 Google Cloud 認定トレーナーの廣瀬 隆博がお届けしました。
また次の記事でお会いしましょう。

Discussion