HeadscaleにGUIをつける

2023年3月23日

Headscaleサーバを動かすの続きである。

先の記事にも書いたように、現在Headscale用のウェブGUIには二種類あるようだが、その一つは、Dockerリポジトリは無いようなので、もうひとつの方を試してみることにする。

https://github.com/gurucomputing/headscale-ui/blob/master/documentation/configuration.mdを参考にする。

なお、latestは使用しない。これを使ってしまうと、バージョンが変更された場合に動作しなくなる可能性が高いからだ。

まず、先のdocker-compose.ymlを以下のように変更する。

version: '3.5'
services:
  headscale:
    container_name: headscale
    image: headscale/headscale:0.20.0
    volumes:
      - ./config:/etc/headscale/
      - ./data:/var/lib/headscale
    ports:
      # metrics test /metrics
      - 127.0.0.1:9091:9090
    command: headscale serve
    restart: unless-stopped
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.headscale.rule=Host(`hs.example.com`) && PathPrefix(`/`)"
      - "traefik.http.routers.headscale.entrypoints=websecure"
      - "traefik.http.routers.headscale.tls.certresolver=myresolver"
      - "traefik.http.services.headscale.loadbalancer.server.port=80"
  hsui:
    image: ghcr.io/gurucomputing/headscale-ui:2023.01.30-beta-1
    container_name: hsui
    restart: unless-stopped
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.hsui.rule=Host(`hs.example.com`) && PathPrefix(`/web`)"
      - "traefik.http.routers.hsui.entrypoints=websecure"
      - "traefik.http.routers.hsui.tls.certresolver=myresolver"
      - "traefik.http.services.hsui.loadbalancer.server.port=80"

networks:
  default:
    external:
      name: traefik-network

これでdocker-composeを動作させ、https://hs.example.com/webにアクセスする。つまり、http://hs.example.comは、本来のheadscaleによる外部からの接続受付場所になるが、https://hs.example.com/webから下が、このウェブGUIの担当になる。

すると、以下のような表示がされる。

本来のheadscaleに接続するためには、そのURLとAPIキーを指定しないといけない。

APIを作成する。端末にて以下を行う。APIキーは作成時に取得しないと二度と取得できない(別のものを作成するしかない)が、ウェブUIに設定すればいつでも見れるのであまり気にする必要はない。

# docker exec headscale headscale apikeys create
OptHmxr0pQ.ewketuKkb2Gn***************************

これらを入力して「Test Server Settings」すると、以下のように接続状態になるはずだ。

引き続き、別のタブをクリックすると、以下のような表示になる。つまり、前回記事で行った成果が反映されている。

なお、あらたなデバイスを追加するには、例えば、Linuxでは以下のような表示がされ、指定されたURLを投入すれば登録されるのだが。。。

そうではなく、このGUIからも登録ができる。ただしこの場合は、キーそのものだけではなく、「nodekey:」も含めないといけない。

ユーザ認証

さて、この画面には、ログインが無いのだが、どうやってユーザ認証するのだろうか?

どうも、以下の仕組みになっているらしい。

  • ユーザはクッキーによって認識される
  • そのクッキーにおいて、正しいURLとAPIキーが入力されたときに、正常なアクセスができる

最初に投入するAPIキーは、直接的にheadscaleコマンドを叩いて作らねばならず、管理者しかできないため、不審者が使うことはできなくなる。

※「Headscale URL」として任意のURLを指定され、他のHeadscaleに流用されてしまうじゃないかと思われるかもしれないが、どうもそういうことができるわけではないらしい(未確認)。

ともあれ、この仕組みにおいては、普通にログインするのと同じで、むしろパスワードよりも強力なAPIキーが必要になるため、おそらくは、このURLが公開されていても問題無いだろう。

また、Rollover API Keyのボタンは、既に設定されているAPI Keyを無効にし、新たなAPIキーを作成してそれを設定するものらしい。

この仕組みにより、例えば同じAPIキーを二つのブラウザに使用して接続し、その一方でRolloverすると、他方の接続は無効になる。