Skip to content

Commit 21544ad

Browse files
fix(headscale): Drop exit node in favor of opnsense, disable stun
1 parent 4c8eaef commit 21544ad

File tree

10 files changed

+37
-215
lines changed

10 files changed

+37
-215
lines changed

k8s/apps/network/headscale/acl.jsonc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
],
66
"group:internal": [
77
"eaglesemanation@",
8-
"laser532@"
8+
"laser532@",
99
],
1010
},
1111
"tagOwners": {
@@ -27,12 +27,14 @@
2727
"dst": [
2828
"tag:exit-node:*",
2929
"autogroup:internet:*",
30+
"${SVC_DNS_ADDR}:53",
31+
"${SVC_INGRESS_INTERNAL_ADDR}:80,443",
3032
],
3133
},
3234
{
3335
"action": "accept",
3436
"src": [
35-
"group:internal"
37+
"group:internal",
3638
],
3739
"dst": [
3840
"${LOCAL_CIDR}:*",

k8s/apps/network/headscale/config.yaml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ derp:
7070
server:
7171
# If enabled, runs the embedded DERP server and merges it into the rest of the DERP config
7272
# The Headscale server_url defined above MUST be using https, DERP requires TLS to be in place
73-
enabled: true
73+
enabled: false
7474

7575
# Region ID to use for the embedded DERP server.
7676
# The local DERP prevails if the region ID collides with other region ID coming from
@@ -81,6 +81,9 @@ derp:
8181
region_code: "headscale"
8282
region_name: "Headscale Embedded DERP"
8383

84+
# Only allow clients associated with this server access
85+
verify_clients: true
86+
8487
# Listens over UDP at the configured address for STUN connections - to help with NAT traversal.
8588
# When the embedded DERP server is enabled stun_listen_addr MUST be defined.
8689
#
@@ -122,7 +125,7 @@ derp:
122125
auto_update_enabled: true
123126

124127
# How often should we check for DERP updates?
125-
update_frequency: 24h
128+
update_frequency: 3h
126129

127130
# Disables the automatic check for headscale updates on startup
128131
disable_check_updates: true
@@ -263,6 +266,10 @@ dns:
263266
# `hostname.base_domain` (e.g., _myhost.example.com_).
264267
base_domain: ts.${CLUSTER_DOMAIN}
265268

269+
# Whether to use the local DNS settings of a node or override the local DNS
270+
# settings (default) and force the use of Headscale's DNS configuration.
271+
override_local_dns: true
272+
266273
# List of DNS servers to expose to clients.
267274
nameservers:
268275
global:

k8s/apps/network/headscale/deployment.k8s.yaml

Lines changed: 0 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -130,57 +130,3 @@ spec:
130130
emptyDir: {}
131131
- name: home-local
132132
emptyDir: {}
133-
---
134-
apiVersion: apps/v1
135-
kind: Deployment
136-
metadata:
137-
name: tailscale-exit-node
138-
namespace: headscale
139-
labels:
140-
app.kubernetes.io/name: tailscale
141-
app.kubernetes.io/instance: tailscale-exit-node
142-
spec:
143-
strategy:
144-
type: Recreate
145-
replicas: 1
146-
selector:
147-
matchLabels:
148-
app.kubernetes.io/name: tailscale
149-
app.kubernetes.io/instance: tailscale-exit-node
150-
template:
151-
metadata:
152-
labels:
153-
app.kubernetes.io/name: tailscale
154-
app.kubernetes.io/instance: tailscale-exit-node
155-
spec:
156-
serviceAccountName: tailscale-exit-node
157-
containers:
158-
- name: tailscale
159-
image: ghcr.io/tailscale/tailscale:v1.90.6
160-
env:
161-
- name: TS_USERSPACE
162-
value: "0"
163-
- name: TS_ROUTES
164-
value: "${LOCAL_CIDR}"
165-
- name: TS_EXTRA_ARGS
166-
value: "--advertise-tags=tag:exit-node --advertise-exit-node --login-server=https://headscale.${CLUSTER_DOMAIN}"
167-
- name: TS_KUBE_SECRET
168-
value: tailscale-exit-node-state
169-
- name: TS_HOSTNAME
170-
value: "emnt-k8s"
171-
- name: POD_NAME
172-
valueFrom:
173-
fieldRef:
174-
fieldPath: metadata.name
175-
- name: POD_UID
176-
valueFrom:
177-
fieldRef:
178-
fieldPath: metadata.uid
179-
envFrom:
180-
- secretRef:
181-
name: tailscale-exit-node
182-
securityContext:
183-
privileged: true
184-
resources:
185-
limits:
186-
squat.ai/tun: 1

k8s/apps/network/headscale/exit-node-sa.k8s.yaml

Lines changed: 0 additions & 36 deletions
This file was deleted.

k8s/apps/network/headscale/ingress.k8s.yaml

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -28,35 +28,3 @@ spec:
2828
name: headscale-ui
2929
port:
3030
name: web
31-
---
32-
# yaml-language-server: $schema=https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/traefik.io/ingressrouteudp_v1alpha1.json
33-
apiVersion: traefik.io/v1alpha1
34-
kind: IngressRouteUDP
35-
metadata:
36-
name: headscale-stun-external
37-
namespace: headscale
38-
annotations:
39-
kubernetes.io/ingress.class: ingress-external-traefik
40-
spec:
41-
entryPoints:
42-
- stun
43-
routes:
44-
- services:
45-
- name: headscale
46-
port: stun
47-
---
48-
# yaml-language-server: $schema=https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/traefik.io/ingressrouteudp_v1alpha1.json
49-
apiVersion: traefik.io/v1alpha1
50-
kind: IngressRouteUDP
51-
metadata:
52-
name: headscale-stun-internal
53-
namespace: headscale
54-
annotations:
55-
kubernetes.io/ingress.class: ingress-internal-traefik
56-
spec:
57-
entryPoints:
58-
- stun
59-
routes:
60-
- services:
61-
- name: headscale
62-
port: stun

k8s/apps/network/headscale/kustomization.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ resources:
77
- svc.k8s.yaml
88
- ingress.k8s.yaml
99
- secrets.sops.yaml
10-
- exit-node-sa.k8s.yaml
1110
configMapGenerator:
1211
- name: headscale-config
1312
namespace: headscale

k8s/apps/network/headscale/secrets.sops.yaml

Lines changed: 24 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -4,84 +4,40 @@ metadata:
44
name: headscale
55
namespace: headscale
66
stringData:
7-
oidc_secret_key: ENC[AES256_GCM,data:nvAvHL8ApRKT0B0qro40DtKLdTDECQvstRMahdCPah2moA21SXmu3GzMkK9y4V3Rj9mNr9AQ+U5oxGlT4lJFtIxqOsIZgQKRWIwJYTpr3XJeH4jlTpzMpbe3DaRwcIlqsrQEbI2WG/P1Jpn9y8n0Cl8QUZsdirDy8pIsHisQJUI=,iv:6Ctx3wPT8lY4q+B498Mm1j8IUn1+fNdrXhtfs/GQ7fo=,tag:WIeIZNZnDrTO7Hk1kXMbTQ==,type:str]
7+
oidc_secret_key: ENC[AES256_GCM,data:NAUzYjuxT2tXXlcz/QQNqwDGkjMLONV0GUnC8N5vdkuwAwSB44WpXQwrCYcY7jFWeO6N9bEaVIIYvZ4i4DeG8jeRLzG1RIi3kF7X91MtW6BTZZSrHpr41ZE6VXwkggO2brigZapgzKMDSVNqZTGR0x7KzmnIUaDpem5ZTL+5K9E=,iv:O6/ecOuKeiAtkEk7xZEHKpCzGcfanq3h9ukqJ/3B9Jc=,tag:NZuvGePEZSs7MroyZTSdDg==,type:str]
88
sops:
99
age:
1010
- recipient: age1exncnhces66v0uc67xm009v2d2237hgdxtaa8tdy0hvusexjry0qye4ad2
1111
enc: |
1212
-----BEGIN AGE ENCRYPTED FILE-----
13-
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBvZDRYRmVaUndZRmxkWmFN
14-
c3pKQXRrbEJGakIxWUdOUnQ5T3JPSEJERlNjCldLclFzbHUxR01VZDZLZkFtSHVU
15-
bVk2bEJLZ3JIdGpCdE9reTA4YU5Bc1kKLS0tIHpHZTZ0YkNsTnZ3ck9aY2J2dFQz
16-
a3lBZldOR09KNXFPMjl5bGd6VGY1cncKHolDJPBob+uY4I/1Mq81xDYtt3xQONsx
17-
cvzDXRbgDSPTOvhT0EUer7jIAuHGc9+pXwqetvzAjF7pRQ+ZyhI75w==
13+
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA0WnRGMGlvWE5xL0tYYXMv
14+
OHp6TXF2SjQ3U1Y3bXNCajg1NUV3UnI2QWxNCmZFT1JZR1g4ZS9qdXJ5NXVRRnQv
15+
bHJ6R2hTOGtjREQrMmtMelozb3hyM00KLS0tIG8wdDQraXJzQ2FudTEzd2dxM0hN
16+
bUhWK2xRM25OZWplTTVGbEYrcTNKWk0KhtaRTC3nfrGBTuGajEFCVesYaTFXlCfc
17+
GwajQ9DX6xsWOmqFuAL+ukJqnelzGDQWwbi9WnSCS6/Np5fu99JG5w==
1818
-----END AGE ENCRYPTED FILE-----
19-
lastmodified: "2025-07-09T10:02:55Z"
20-
mac: ENC[AES256_GCM,data:cNYE9KGbyHihY0UUCDsog/qxUWNmLgnCZqoyYFONUhd/Ch37AYo8kjLhj7kAwdKWai/I9ffTuZShR2Jr4CdtM+INI1UW/LT1GcHX25DP85DVZtaQhj6KbZyKyZvGr1RnWozYxrew7cX4IK6eRUYme55Ev/m0S4MycyNK8G74SCE=,iv:7Vsyj6SdPjb2zNwXs/CNa0E0MJdr+WdKj0/3j7RJbyY=,tag:BLv2/l3JVw6HqkXnnK/V5A==,type:str]
19+
lastmodified: "2025-11-15T02:21:17Z"
20+
mac: ENC[AES256_GCM,data:eCpuqQWaEL5IW/VaSPT5gfdDyi7Yl7RW/hgfHm3Tkxt9U/eBnTvixeFc0hRfnxn/uesmRU/FL8hRGt+orD7aqNaUwPltISurXFC33yv/S0QE8LOLIT19VmgM8dnJjmIoKd7M55Rg/R+GmbasX9AFrPFB8IK5vIKX5g/vKG/LbHQ=,iv:XGtjz0wNg57XKQViIpRYVzVjV/cwK5IGKe+1jmwkNec=,tag:DbqImEzwSSBs8mcYL1I4gQ==,type:str]
2121
pgp:
22-
- created_at: "2025-07-09T10:02:55Z"
22+
- created_at: "2025-11-15T02:21:17Z"
2323
enc: |-
2424
-----BEGIN PGP MESSAGE-----
2525
26-
hQIMAwVH6sRf6ijOAQ//RXIfb9z5MQLXJQIsGauBcP9JGmrZ+CMjeGLOiiW4xB92
27-
VUkVn+kHmUwiunyg4I+MRL6qwOpGUi76mhFPETLyh1z8ipvanoBbbGz72Y3Ikmyw
28-
lRUjaaC84Nv1WKMzDaJYPbJm12L7Bxp7S9Dg/8cZximzBETERRRa2jwfBhm0dPh1
29-
GHbleMXmtsWLPfx/s657nG8IywCEz9rLUdd/ajEbc2y6/gjhh+RqHT/m1TM3m9AF
30-
gDi+4kmh0gjzV5mMBq9zbOMCkLjqivi5Kl8dsswO9kik2yTFvxp7l3S1jCmDTXBH
31-
Te0UErjxHHCwi/XaBB2gCBG10EltJhCdvQZEeZmbsGjrGOQFcnJgolQPcqtXaFlY
32-
XHi+QBgs+EWQ/P1w/KOMmTABJH6Baez8w1VCpErxgBmtzxFngVDZUfDMaYGev8oD
33-
XzTOL6AamF/FUE67HfwLh86eJ/c+iPyceHc4UAnPAs6Y5yGgNylYLCaGiS8BVlOz
34-
xpKuGUQM99WHGrrFKB1qE/HUtUrUlS5ttdNi68nw5qFbZKHJ/P3x1HybamvW+ENr
35-
wpUu+IlzO6/UUM3gxMbnYlYitR1iBJR8ON9md8Snlxelw1ugvhCagbFSb66SWx+l
36-
MkfjpavN4gpNAIaKXZCi1meTkTjYZF9rlBU/gui+4NS4WJ0mKji2CXueZ3T9SzjS
37-
XgHLrjyiJ2rWyU1Gd4yZpp/ljzEfg3PvR4NQdPXAQEO6CVsfO9U/oe9rhqG0a7Rt
38-
7JLciAYAzDrK8weRDP8VSQVolcYHWcOvvsLrzO5HSH7d8/ELRMnP1NirNvF6DMk=
39-
=bM9d
26+
hQIMAwVH6sRf6ijOARAAhOOdkR0SZ/mRunrsVqlnfuq5Wk/1iG+iDCd2Wf9Ygt5+
27+
s0SdezLexKB5M1834eiHron6oNbqJOmhbnnTYRU8mgSygJgKC6wFrLdRibGxJCzg
28+
MHW1ah+uuMjUY5J4XfTdYrqLC6kIYbNon6TPqg8qLI1dAWjSgocM+g0i3XrXXktL
29+
U+r37hGNbxtV4bFF42t7LqO002Vk8g7OO6TastmY7D0jfIL+UhN5ayqS2eRo0pgW
30+
TWNke/N9sz2P7PJeSx7pyi+2YshCYLZFfmnIZJMZoOxSJyGLDmz6LTerC7yrYLjR
31+
KONMGo5T1ncQAtOPaF8RWozXSjHpwwX/ksQHzbywKnp/X7SHxe3wu4IxVbwD9PqI
32+
+YP4Ej7TCLpw2O44I3rvl4l5sia3lMIAyIqczvDxkFtEkCfVO2TEdNrNCnHLlXY6
33+
vyoS/n8XBLfEaVfyhk/hKFiH88be4ZH1j860hNkgd88+BxM9HC/om1thbLm2FatB
34+
YZ6/PS+2VAxsKvz6ILO1ly3+lUk0aQd+PsOPAktAwI6bQvci4cs7JxMHwCl6XPh0
35+
QBz56+eFFGUnqUFXmAPSn760PKCihhhtdLJpRgZs/IIEbzVnk4s7YrSvy79JAKFm
36+
cimXFzxE73jGlFabcTiWd5lzy8VGKPcq29U3MnEAQBOzlCF7cWHu1wEkzmUgk77S
37+
XgGbKwVT+MWdpTwVnzfEXqMJUGgS7B1VKe1A6mFy1PWf8fZsQCstYjjmbqq0lnuT
38+
3DkYaEVRn6PFeWuQSNYX/shTW/DLnM0Q+YduJDnxjODXezKjq6BFDfzOUkJA/JU=
39+
=R1O0
4040
-----END PGP MESSAGE-----
4141
fp: C5B9ADB07DBE5A2E
4242
encrypted_regex: ^(data|stringData|crowdsecLapiKey)$
43-
version: 3.10.2
44-
---
45-
apiVersion: v1
46-
kind: Secret
47-
metadata:
48-
name: tailscale-exit-node
49-
namespace: headscale
50-
stringData:
51-
TS_AUTHKEY: ENC[AES256_GCM,data:Ex0o0sk+Fe2FLVMoeY0Xxt2+E3kn4t9m889BkM8xgpKSgOLqP04FO1LFrlG+qPDA,iv:MEZm8Hde0rTtlITeFEuSFk+c/2p/W90B86HLP8gG+WM=,tag:9m7lP9A+qoK9LpBtJ6bO1Q==,type:str]
52-
sops:
53-
age:
54-
- recipient: age1exncnhces66v0uc67xm009v2d2237hgdxtaa8tdy0hvusexjry0qye4ad2
55-
enc: |
56-
-----BEGIN AGE ENCRYPTED FILE-----
57-
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBvZDRYRmVaUndZRmxkWmFN
58-
c3pKQXRrbEJGakIxWUdOUnQ5T3JPSEJERlNjCldLclFzbHUxR01VZDZLZkFtSHVU
59-
bVk2bEJLZ3JIdGpCdE9reTA4YU5Bc1kKLS0tIHpHZTZ0YkNsTnZ3ck9aY2J2dFQz
60-
a3lBZldOR09KNXFPMjl5bGd6VGY1cncKHolDJPBob+uY4I/1Mq81xDYtt3xQONsx
61-
cvzDXRbgDSPTOvhT0EUer7jIAuHGc9+pXwqetvzAjF7pRQ+ZyhI75w==
62-
-----END AGE ENCRYPTED FILE-----
63-
lastmodified: "2025-07-09T10:02:55Z"
64-
mac: ENC[AES256_GCM,data:cNYE9KGbyHihY0UUCDsog/qxUWNmLgnCZqoyYFONUhd/Ch37AYo8kjLhj7kAwdKWai/I9ffTuZShR2Jr4CdtM+INI1UW/LT1GcHX25DP85DVZtaQhj6KbZyKyZvGr1RnWozYxrew7cX4IK6eRUYme55Ev/m0S4MycyNK8G74SCE=,iv:7Vsyj6SdPjb2zNwXs/CNa0E0MJdr+WdKj0/3j7RJbyY=,tag:BLv2/l3JVw6HqkXnnK/V5A==,type:str]
65-
pgp:
66-
- created_at: "2025-07-09T10:02:55Z"
67-
enc: |-
68-
-----BEGIN PGP MESSAGE-----
69-
70-
hQIMAwVH6sRf6ijOAQ//RXIfb9z5MQLXJQIsGauBcP9JGmrZ+CMjeGLOiiW4xB92
71-
VUkVn+kHmUwiunyg4I+MRL6qwOpGUi76mhFPETLyh1z8ipvanoBbbGz72Y3Ikmyw
72-
lRUjaaC84Nv1WKMzDaJYPbJm12L7Bxp7S9Dg/8cZximzBETERRRa2jwfBhm0dPh1
73-
GHbleMXmtsWLPfx/s657nG8IywCEz9rLUdd/ajEbc2y6/gjhh+RqHT/m1TM3m9AF
74-
gDi+4kmh0gjzV5mMBq9zbOMCkLjqivi5Kl8dsswO9kik2yTFvxp7l3S1jCmDTXBH
75-
Te0UErjxHHCwi/XaBB2gCBG10EltJhCdvQZEeZmbsGjrGOQFcnJgolQPcqtXaFlY
76-
XHi+QBgs+EWQ/P1w/KOMmTABJH6Baez8w1VCpErxgBmtzxFngVDZUfDMaYGev8oD
77-
XzTOL6AamF/FUE67HfwLh86eJ/c+iPyceHc4UAnPAs6Y5yGgNylYLCaGiS8BVlOz
78-
xpKuGUQM99WHGrrFKB1qE/HUtUrUlS5ttdNi68nw5qFbZKHJ/P3x1HybamvW+ENr
79-
wpUu+IlzO6/UUM3gxMbnYlYitR1iBJR8ON9md8Snlxelw1ugvhCagbFSb66SWx+l
80-
MkfjpavN4gpNAIaKXZCi1meTkTjYZF9rlBU/gui+4NS4WJ0mKji2CXueZ3T9SzjS
81-
XgHLrjyiJ2rWyU1Gd4yZpp/ljzEfg3PvR4NQdPXAQEO6CVsfO9U/oe9rhqG0a7Rt
82-
7JLciAYAzDrK8weRDP8VSQVolcYHWcOvvsLrzO5HSH7d8/ELRMnP1NirNvF6DMk=
83-
=bM9d
84-
-----END PGP MESSAGE-----
85-
fp: C5B9ADB07DBE5A2E
86-
encrypted_regex: ^(data|stringData|crowdsecLapiKey)$
87-
version: 3.10.2
43+
version: 3.11.0

k8s/apps/network/headscale/svc.k8s.yaml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,6 @@ spec:
2121
- name: grpc
2222
port: 50443
2323
targetPort: 50443
24-
- name: stun
25-
port: 3478
26-
targetPort: 3478
27-
protocol: UDP
2824
---
2925
apiVersion: v1
3026
kind: Service

k8s/apps/network/ingress/helmrelease-external.k8s.yaml

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -165,14 +165,6 @@ spec:
165165
exposedPort: 993
166166
proxyProtocol:
167167
trustedIPs: [10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16]
168-
stun:
169-
protocol: UDP
170-
port: 3478
171-
expose:
172-
default: true
173-
exposedPort: 3478
174-
proxyProtocol:
175-
trustedIPs: [10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16]
176168
jvb:
177169
protocol: UDP
178170
port: 10000

k8s/apps/network/ingress/helmrelease-internal.k8s.yaml

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -134,14 +134,6 @@ spec:
134134
exposedPort: 993
135135
proxyProtocol:
136136
trustedIPs: [10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16]
137-
stun:
138-
protocol: UDP
139-
port: 3478
140-
expose:
141-
default: true
142-
exposedPort: 3478
143-
proxyProtocol:
144-
trustedIPs: [10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16]
145137
jvb:
146138
protocol: UDP
147139
port: 10000

0 commit comments

Comments
 (0)