tailscaleのオンプレ版headscaleをつかってみる

なんか面白そうなもの見つけたので我が家のVPNを取っ替えた。
その備忘録。

# 要約

- [tailscale](https://tailscale.com/)とは手軽にwireguardベースのサービスメッシュを構築できるサービスである
    - 主にその手軽さは各端末間の認証に関する取次を行う「コア」と
    - なんかものすごいNAT制御をしているクライアントにある
- [headscale](https://headscale.net/)とは、tailscaleを代替することを目指すOSSオンプレなtailscaleコア
- headscaleにはコアを管理する標準のUIがなくCLI操作が必要となる
- headscaleのクライアントには、tailscaleのクライアントを使用し、`--login-server`を指定する


https://github.com/juanfont/headscale/tree/main



# UIについて

headscaleに標準で付属しないが、現状３つほど選択肢がある様子

今回は[gurucomputing/headscale-ui](https://github.com/gurucomputing/headscale-ui)を使用しインストールする

https://headscale.net/web-ui/

![gif](https://github.com/gurucomputing/headscale-ui/raw/master/documentation/assets/headscale-ui-demo.gif)

# install
## helm

### 前提

headscale-uiとセットでインストール。ingressで/web下にuiを設置

我が家の前提（必須ではない）

- metallbなどのLB使用可能
- ingress-nginxなどのingress使用可能
- PVの動的プロビジョニングが使用可能
<br></br>

- アクセス
    外部ネット -> 光ルーター -> （ルーターから見える）ingress endpoint 

- ドメイン　→　すでに設定されていたDDNS

---

install 

最小限の設定。
`persistence.config.enabled: true`でないと起動できない。

~~~bash
NODEPORT=3xxxx
SERVER_URL=http://192.168.xxx.xxx:$NODEPORT

helm repo add gabe565 https://charts.gabe565.com
# オーバーライド作るか下のようにオプションで任意の設定をする
# helm install headscale gabe565/headscale -n headscale --create-namespace -f override.yaml

# 必要な環境であれば
kubectl apply -f - << EOF
apiVersion: v1
kind: PersistentVolume
metadata:
  name: mypv-headscale
spec:
  capacity:
    storage: 1Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  hostPath:
    path: /pv/storage

EOF

helm install --create-namespace -n headscale headscale gabe565/headscale \
  --set env.HEADSCALE_SERVER_URL="${SERVER_URL}" \
  --set persistence.config.enabled=true \
  --set persistence.config.accessMode=ReadWriteOnce \
  --set persistence.config.size=1Gi \
  --set service.main.type=NodePort \
  --set service.main.ports.http.nodePort="${NODEPORT}"
~~~


## override.yaml(我が家の一例)

helm作成者により解説されている、headscale-ui追加方法に従っている。

https://artifacthub.io/packages/helm/gabe565/headscale/0.2.2

<details>

<summary>override.yaml</summary>

~~~diff
diff --git a/values.yaml b/override.yaml
index 9daf510..ce77bd9 100644
--- a/values.yaml
+++ b/override.yaml
@@ -37,16 +37,30 @@ service:
       grpc:
         enabled: false
         port: 50443
+      ui:
+        enabled: true
+        port: 80
 
 ingress:
   # -- Enable and configure ingress settings for the chart under this key.
   # @default -- See [values.yaml](./values.yaml)
+  #classname: nginx
   main:
-    enabled: false
-    # hosts:
-    #   - host: chart-example.local
-    #     paths:
-    #       - path: /
+    enabled: true
+    className: nginx
+    hosts:
+       - host: mydomain.foobar.com
+         paths:
+           - path: /
+  ui:
+    enabled: true
+    className: nginx
+    hosts:
+      - host: mydomain.foobar.com
+        paths:
+          - path: /web
+            service:
+              port: 80
     # tls:
     #   - secretName: chart-example.local-tls
     #     hosts:
@@ -64,12 +78,12 @@ persistence:
   # -- Configure persistence settings for the chart under this key.
   # @default -- See [values.yaml](./values.yaml)
   config:
-    enabled: false
+    enabled: true
     mountPath: /etc/headscale
     retain: true
     # storageClass: ""
-    # accessMode: ReadWriteOnce
-    # size: 1Gi
+    accessMode: ReadWriteOnce
+    size: 1Gi
 
 # -- Enable and configure postgresql database subchart under this key.
 #    For more options see [postgresql chart documentation](https://github.com/bitnami/charts/tree/master/bitnami/postgresql)
@@ -98,3 +112,9 @@ serviceMonitor:
         interval: 30s
         scrapeTimeout: 10s
 
+additionalContainers:
+  ui:
+    image: ghcr.io/gurucomputing/headscale-ui:latest
+    ports:
+      - name: http
+        containerPort: 80

~~~

</details>

ingressを使用する場合、
ingressClassNameが正しく設定されないため、指定(もしくはingress-nginxインストール時に`--set controller.watchIngressWithoutClass=true`)

~~~bash
kubectl  patch ingress -n headscale  headscale --patch '{"spec":{"ingressClassName": "nginx"}}'
kubectl  patch ingress -n headscale  headscale-ui --patch '{"spec":{"ingressClassName": "nginx"}}'
~~~

## docker-compose

下記の手順に従う

https://github.com/gurucomputing/headscale-ui/blob/master/documentation/configuration.md



# headscaleコマンドの使用方法

公式の解説も私の解説も雑だが`-h`すればだいたいわかる。
また、クライアント側は、たくさんあるtailscaleの説明を参照。
subnetやexit-nodeの設定を`headscale route`で行う点について留意。

ざっくり、

- user　- 下の情報が紐づく
    - node - pcなどの端末
    - preauthkey - 登録のために事前作成するキー
- apikey - headscale-uiなどを利用する際に必要なAPIキー

がある。

nodeは個々にコマンドでマシン固有のIDを登録する他、preauthkeyで登録できる。

headscaleコマンドは下のようにpod内で実行する。

~~~bash
kubectl  exec -it -n headscale headscale-xxxxxxxxxx-xxxxx bash
~~~

## ユーザー作成

~~~bash
headscale  users create newuser
~~~

## preauthkeyの発行

~~~bash
# -u ユーザー
# --reusable 読んで字のごとく
# --expiration 読んで字のごとく(単位はgoのdurationか？)
headscale preauthkeys create  -u newuser --reusable --expiration　1w
~~~

## ノード登録（preauthkeyを使った方法）

クライアント側で操作する。（クライアントはtailscale公式の手順に従ってインストールする）

~~~bash
PREAUTHKEY="事前に作成下キー"
SERVER="mydomain.foobar.com"
sudo tailscale up --login-server ${SERVER} --auth-key ${PREAUTHKEY} --force-reauth
~~~

androidクライアントの場合右上の”…”を複数回タップしてログインサーバーを切り替えるオプションが使えるようにする。

https://github.com/tailscale/tailscale-android/pull/55

## これだけ？

これだけ

2重ルーターでも携帯網でもお構いなしにnodeに登録した端末同士フツーに接続できている

もちろんheadscaleコア自体のルーティングの設定やドメイン、認証の設定は必要だが圧倒的手軽さ…