LoginSignup
22
10
お題は不問!Qiita Engineer Festa 2023で記事投稿!

Google Cloud Workstationsの環境にリバースプロキシ経由でアクセスする

Last updated at Posted at 2023-07-13

はじめに

Goを使いちょっとしたリバースプロキシを書くことで、遠隔にあるGoogle Cloud Workstationsに立てたサーバーに対し、ローカルPCからhttp://localhost:{port}でアクセスできたので、その方法を紹介します。

Google Cloud Workstations とは

Google Cloudが提供するフルマネージドな開発環境として使えるサービスです。

2023年5月に正式リリースされました。

特徴としては

  • ローカルPCにソースコードを置くことなく、ブラウザやIDEからアクセスできるセキュアな開発環境を提供する。
  • コンテナ定義として開発環境の設定を記述しておけるので、エンジニアは一貫した開発環境を利用できる。

などがあります。

Google Cloud Workstations の制約

一方、フルマネージドになるがゆえの制約もあります。ポートへのアクセスの仕方がその一つです。

例えば、http://localhost:3000で待ち受けるサーバーを、Workstation上で立ち上げていた場合、Workstationの外からアクセスするには、次のURLでアクセスする必要があります。
https://3000-workstation1.cluster-xxx.cloudworkstations.dev

https://{port}-{workstation}.{cluster}.cloudworkstations.dev
というフォーマットです。

すでにhttp://localhost:3000で接続しにいくクライアントがある場合、この変換が必要になるのは使いづらいため、URLを変えずにすむ方法はないかと調査しました。

Goでリバースプロキシを書く

リバースプロキシをローカルPC側に立てておき、そこがよしなに変換してくれれば対応できそうです。

自分が比較的よく書くGoでは、リバースプロキシを立てるための機能が標準パッケージで提供されています。
そのため、ローカルのポートで待ち受けて任意のURLに転送するプロキシを簡単に書けます。

また、Google Cloud Workstationsのドキュメントに、WorkstationへHTTPリクエストを送る方法が書かれています。

具体的には、以下のメソッドを使って、Workstationへのアクセストークンを取得し、それをAuthorizationヘッダーにセットします。
projects.locations.workstationClusters.workstationConfigs.workstations.generateAccessToken
アクセストークンはブラウザ上の"Try this method"から取得することもできます。
dfba74f8-1837-26f2-2726-9ef649ef5709-2.png

以上の2点を組み合わせると、サンプルレベルではありますが50行程度で、localhost:{port}を待ち受けてWorkstation側へ転送するリバースプロキシを書くことができました。
転送するポートが複数ある場合でも、listenProxyをgoroutineで複数立てておけば対応できます。

package main

import (
	"fmt"
	"net/http"
	"net/http/httputil"
	"net/url"
)

func main() {
	// 3000番ポートでリバースプロキシを起動
	if err := listenProxy(3000); err != nil {
		panic(err)
	}
}

func listenProxy(port uint) error {
	target, err := url.Parse(fmt.Sprintf(workstationURLFormat(), port))
	if err != nil {
		return err
	}
	bearer := fmt.Sprintf("Bearer %s", generateWorkstationToken())

	proxy := &httputil.ReverseProxy{
		Rewrite: func(r *httputil.ProxyRequest) {
			r.SetXForwarded()
			r.SetURL(target)
			r.Out.Header.Set("Authorization", bearer)
		},
	}

	return http.ListenAndServe(fmt.Sprintf(":%d", port), proxy)
}

func workstationURLFormat() string {
	// サンプルのため転送先のURLはハードコード
	return "https://%d-workstation1.cluster-xxxxxxx.cloudworkstations.dev/"
}

func generateWorkstationToken() string {
	// WorkstationのアクセストークンはTTLがあるので、実際は自動で生成したり更新する機構が必要。
	// see: https://cloud.google.com/workstations/docs/authentication?hl=ja#http
	return "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.xxxxxxxxxxxxxxxxxxxxxxxxx"
}

まとめ

実運用に向けた検証はこれからですが、リバースプロキシを介すことでこれまでと変わらないアクセスを実現できそうなことはわかりました。
このようなユースケースが必要となる場面は少ないかもしれませんが、同じような課題に困っている方への参考になれば幸いです。

参考資料

22
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
10