From b8aad5451daa24c8eeac9ab52c92b42542078675 Mon Sep 17 00:00:00 2001 From: Juan Font Alonso Date: Tue, 15 Mar 2022 13:22:25 +0100 Subject: [PATCH 01/14] Make STUN run by default when embedded DERP is enabled This commit also allows to set an external STUN server, while running the embedded DERP server (without embedded STUN) --- app.go | 5 +++++ cmd/headscale/cli/utils.go | 3 +++ config-example.yaml | 7 +++++-- derp_server.go | 18 ++++++++---------- 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/app.go b/app.go index f1426bbb..177c3ee1 100644 --- a/app.go +++ b/app.go @@ -62,6 +62,7 @@ const ( errUnsupportedLetsEncryptChallengeType = Error( "unknown value for Lets Encrypt challenge type", ) + errSTUNAddressNotSet = Error("STUN address not set") DisabledClientAuth = "disabled" RelaxedClientAuth = "relaxed" @@ -502,6 +503,10 @@ func (h *Headscale) Serve() error { h.DERPMap = GetDERPMap(h.cfg.DERP) if h.cfg.DERP.ServerEnabled { + if h.cfg.DERP.STUNAddr == "" { // When embedded DERP is enabled we always need a STUN server address, embedded or external + return errSTUNAddressNotSet + } + h.DERPMap.Regions[h.DERPServer.region.RegionID] = &h.DERPServer.region if h.cfg.DERP.STUNEnabled { go h.ServeSTUN() diff --git a/cmd/headscale/cli/utils.go b/cmd/headscale/cli/utils.go index dc7a4e9f..eb26a835 100644 --- a/cmd/headscale/cli/utils.go +++ b/cmd/headscale/cli/utils.go @@ -55,6 +55,9 @@ func LoadConfig(path string) error { viper.SetDefault("dns_config", nil) + viper.SetDefault("derp.server.enabled", false) + viper.SetDefault("derp.server.stun.enabled", true) + viper.SetDefault("unix_socket", "/var/run/headscale.sock") viper.SetDefault("unix_socket_permission", "0o770") diff --git a/config-example.yaml b/config-example.yaml index 2075e69a..31d7a8aa 100644 --- a/config-example.yaml +++ b/config-example.yaml @@ -69,10 +69,13 @@ derp: region_code: "headscale" region_name: "Headscale Embedded DERP" - # If enabled, also listens in UDP at the configured address for STUN connections to help on NAT traversal + # Enabled by default when embedded DERP is enabled. Listens in UDP at the configured address for STUN connections + # to help on NAT traversal. + # If DERP is enabled, but STUN is disabled you still need to input an external STUN server in the listen_addr field. + # # For more details on how this works, check this great article: https://tailscale.com/blog/how-tailscale-works/ stun: - enabled: false + enabled: true listen_addr: "0.0.0.0:3478" # List of externally available DERP maps encoded in JSON diff --git a/derp_server.go b/derp_server.go index 11e3eb14..6580419e 100644 --- a/derp_server.go +++ b/derp_server.go @@ -77,17 +77,15 @@ func (h *Headscale) generateRegionLocalDERP() (tailcfg.DERPRegion, error) { }, } - if h.cfg.DERP.STUNEnabled { - _, portStr, err := net.SplitHostPort(h.cfg.DERP.STUNAddr) - if err != nil { - return tailcfg.DERPRegion{}, err - } - port, err := strconv.Atoi(portStr) - if err != nil { - return tailcfg.DERPRegion{}, err - } - localDERPregion.Nodes[0].STUNPort = port + _, portSTUNStr, err := net.SplitHostPort(h.cfg.DERP.STUNAddr) + if err != nil { + return tailcfg.DERPRegion{}, err } + portSTUN, err := strconv.Atoi(portSTUNStr) + if err != nil { + return tailcfg.DERPRegion{}, err + } + localDERPregion.Nodes[0].STUNPort = portSTUN return localDERPregion, nil } From 0bfa5302a7d70d30066df5d2408cf720a17e8399 Mon Sep 17 00:00:00 2001 From: bravechamp <48980452+bravechamp@users.noreply.github.com> Date: Tue, 15 Mar 2022 16:05:56 +0300 Subject: [PATCH 02/14] Fix API access By allowing API keys to be validated --- app.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/app.go b/app.go index f1426bbb..1809f95c 100644 --- a/app.go +++ b/app.go @@ -409,8 +409,6 @@ func (h *Headscale) httpAuthenticationMiddleware(ctx *gin.Context) { return } - ctx.AbortWithStatus(http.StatusUnauthorized) - valid, err := h.ValidateAPIKey(strings.TrimPrefix(authHeader, AuthPrefix)) if err != nil { log.Error(). From 98ac88d5ef5d94fca6da47600d031f10e6833d62 Mon Sep 17 00:00:00 2001 From: Juan Font Date: Wed, 16 Mar 2022 18:45:34 +0100 Subject: [PATCH 03/14] Changed comment position Co-authored-by: Kristoffer Dalby --- app.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app.go b/app.go index 0e10b3fb..aad41a20 100644 --- a/app.go +++ b/app.go @@ -501,7 +501,8 @@ func (h *Headscale) Serve() error { h.DERPMap = GetDERPMap(h.cfg.DERP) if h.cfg.DERP.ServerEnabled { - if h.cfg.DERP.STUNAddr == "" { // When embedded DERP is enabled we always need a STUN server address, embedded or external + // When embedded DERP is enabled we always need a STUN server address, embedded or external + if h.cfg.DERP.STUNAddr == "" { return errSTUNAddressNotSet } From 8f5875efe4267ad859fae5e1afc21581856dc6af Mon Sep 17 00:00:00 2001 From: Juan Font Alonso Date: Wed, 16 Mar 2022 19:46:59 +0100 Subject: [PATCH 04/14] Reorg errors --- app.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/app.go b/app.go index aad41a20..9f270108 100644 --- a/app.go +++ b/app.go @@ -47,6 +47,14 @@ import ( "tailscale.com/types/key" ) +const ( + errSTUNAddressNotSet = Error("STUN address not set") + errUnsupportedDatabase = Error("unsupported DB") + errUnsupportedLetsEncryptChallengeType = Error( + "unknown value for Lets Encrypt challenge type", + ) +) + const ( AuthPrefix = "Bearer " Postgres = "postgres" @@ -58,12 +66,6 @@ const ( registerCacheExpiration = time.Minute * 15 registerCacheCleanup = time.Minute * 20 - errUnsupportedDatabase = Error("unsupported DB") - errUnsupportedLetsEncryptChallengeType = Error( - "unknown value for Lets Encrypt challenge type", - ) - errSTUNAddressNotSet = Error("STUN address not set") - DisabledClientAuth = "disabled" RelaxedClientAuth = "relaxed" EnforcedClientAuth = "enforced" From 537ecb8db0abdb5112c77626d1dc9e379dad4f5d Mon Sep 17 00:00:00 2001 From: Yang Bin Date: Thu, 17 Mar 2022 09:25:42 +0800 Subject: [PATCH 05/14] =?UTF-8?q?docs:=20fixed=20`/metrics`=20endpoint=20`?= =?UTF-8?q?8080=20=E2=86=92=209090`,=20reference=20`config-example.yaml`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/running-headscale-container.md | 3 ++- docs/running-headscale-linux.md | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/running-headscale-container.md b/docs/running-headscale-container.md index d39f4d49..36e63de9 100644 --- a/docs/running-headscale-container.md +++ b/docs/running-headscale-container.md @@ -55,6 +55,7 @@ docker run \ --rm \ --volume $(pwd)/config:/etc/headscale/ \ --publish 127.0.0.1:8080:8080 \ + --publish 127.0.0.1:9090:9090 \ headscale/headscale: \ headscale serve @@ -80,7 +81,7 @@ docker ps Verify `headscale` is available: ```shell -curl http://127.0.0.1:8080/metrics +curl http://127.0.0.1:9090/metrics ``` 6. Create a namespace ([tailnet](https://tailscale.com/kb/1136/tailnet/)): diff --git a/docs/running-headscale-linux.md b/docs/running-headscale-linux.md index 09e43dc7..1e9d11c4 100644 --- a/docs/running-headscale-linux.md +++ b/docs/running-headscale-linux.md @@ -67,7 +67,7 @@ To run `headscale` in the background, please follow the steps in the [SystemD se Verify `headscale` is available: ```shell -curl http://127.0.0.1:8080/metrics +curl http://127.0.0.1:9090/metrics ``` 8. Create a namespace ([tailnet](https://tailscale.com/kb/1136/tailnet/)): From ade9552736e6d4271f46bebacaa65144c464e1d5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 17 Mar 2022 06:38:00 +0000 Subject: [PATCH 06/14] docs(README): update contributors --- README.md | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7bb7018f..596c2580 100644 --- a/README.md +++ b/README.md @@ -447,6 +447,15 @@ make build Tjerk Woudsma + + + Yang +
+ Yang Bin +
+ + + Zakhar @@ -454,8 +463,6 @@ make build Zakhar Bessarab - - ZiYuan/ @@ -463,6 +470,13 @@ make build ZiYuan + + + bravechamp/ +
+ bravechamp +
+ derelm/ @@ -484,6 +498,8 @@ make build lion24 + + pernila/ @@ -498,8 +514,6 @@ make build Wakeful-Cloud - - zy/ From b781446e860254558e189eb6ad1536da385ffd57 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Thu, 17 Mar 2022 17:43:11 +0000 Subject: [PATCH 07/14] Upgrade to go 1.18 --- .github/workflows/build.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/test-integration.yml | 2 +- .github/workflows/test.yml | 2 +- Dockerfile | 2 +- Dockerfile.alpine | 2 +- Dockerfile.debug | 2 +- go.mod | 4 ++-- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 37423c38..46fcd375 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -31,7 +31,7 @@ jobs: if: steps.changed-files.outputs.any_changed == 'true' uses: actions/setup-go@v2 with: - go-version: "1.17.7" + go-version: "1.18.0" - name: Install dependencies if: steps.changed-files.outputs.any_changed == 'true' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8999f7bf..140ea0b0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,7 +18,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v2 with: - go-version: 1.17.7 + go-version: 1.18.0 - name: Install dependencies run: | diff --git a/.github/workflows/test-integration.yml b/.github/workflows/test-integration.yml index b8fd85a6..c5910233 100644 --- a/.github/workflows/test-integration.yml +++ b/.github/workflows/test-integration.yml @@ -25,7 +25,7 @@ jobs: if: steps.changed-files.outputs.any_changed == 'true' uses: actions/setup-go@v2 with: - go-version: "1.17.7" + go-version: "1.18.0" - name: Run Integration tests if: steps.changed-files.outputs.any_changed == 'true' diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 663220be..a3306768 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,7 +25,7 @@ jobs: if: steps.changed-files.outputs.any_changed == 'true' uses: actions/setup-go@v2 with: - go-version: "1.17.7" + go-version: "1.18.0" - name: Install dependencies if: steps.changed-files.outputs.any_changed == 'true' diff --git a/Dockerfile b/Dockerfile index 3ab9c1d1..8d53f6d9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Builder image -FROM docker.io/golang:1.17.8-bullseye AS build +FROM docker.io/golang:1.18.0-bullseye AS build ENV GOPATH /go WORKDIR /go/src/headscale diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 1f0d6353..45fa171d 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,5 +1,5 @@ # Builder image -FROM docker.io/golang:1.17.8-alpine AS build +FROM docker.io/golang:1.18.0-alpine AS build ENV GOPATH /go WORKDIR /go/src/headscale diff --git a/Dockerfile.debug b/Dockerfile.debug index e73c0647..91fe2893 100644 --- a/Dockerfile.debug +++ b/Dockerfile.debug @@ -1,5 +1,5 @@ # Builder image -FROM docker.io/golang:1.17.8-bullseye AS build +FROM docker.io/golang:1.18.0-bullseye AS build ENV GOPATH /go WORKDIR /go/src/headscale diff --git a/go.mod b/go.mod index 1ec291c3..e072eb26 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,10 @@ module github.com/juanfont/headscale -go 1.17 +go 1.18 require ( github.com/AlecAivazis/survey/v2 v2.3.2 + github.com/ccding/go-stun/stun v0.0.0-20200514191101-4dc67bcdb029 github.com/coreos/go-oidc/v3 v3.1.0 github.com/efekarakus/termcolor v1.0.1 github.com/fatih/set v0.2.1 @@ -49,7 +50,6 @@ require ( github.com/akutz/memconn v0.1.0 // indirect github.com/atomicgo/cursor v0.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/ccding/go-stun/stun v0.0.0-20200514191101-4dc67bcdb029 // indirect github.com/cenkalti/backoff/v4 v4.1.2 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/containerd/continuity v0.2.2 // indirect From 61ebb713f298564db76c43ef14046ed5d0b597ab Mon Sep 17 00:00:00 2001 From: Adrien Raffin-Caboisse Date: Fri, 18 Mar 2022 09:32:07 +0100 Subject: [PATCH 08/14] fix(oidc): Reset expiry for reauthentication The previous code resetted the expiry time to be expired. So the machine was never reauthenticated --- oidc.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/oidc.go b/oidc.go index 29ce351f..65e2807f 100644 --- a/oidc.go +++ b/oidc.go @@ -10,6 +10,7 @@ import ( "html/template" "net/http" "strings" + "time" "github.com/coreos/go-oidc/v3/oidc" "github.com/gin-gonic/gin" @@ -229,7 +230,7 @@ func (h *Headscale) OIDCCallback(ctx *gin.Context) { Str("machine", machine.Name). Msg("machine already registered, reauthenticating") - h.RefreshMachine(machine, *machine.Expiry) + h.RefreshMachine(machine, time.Time{}) var content bytes.Buffer if err := oidcCallbackTemplate.Execute(&content, oidcCallbackTemplateConfig{ From 882c0c34c11596e2442a4fb4ab2034323d437215 Mon Sep 17 00:00:00 2001 From: Adrien Raffin-Caboisse Date: Fri, 18 Mar 2022 09:34:18 +0100 Subject: [PATCH 09/14] chore(changelog): update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ce0c35b..6c943940 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ - Fix a limitation in the ACLs that prevented users to write rules with `*` as source [#374](https://github.com/juanfont/headscale/issues/374) - Reduce the overhead of marshal/unmarshal for Hostinfo, routes and endpoints by using specific types in Machine [#371](https://github.com/juanfont/headscale/pull/371) - Apply normalization function to FQDN on hostnames when hosts registers and retrieve informations [#363](https://github.com/juanfont/headscale/issues/363) +- Fix a bug that prevented the use of `tailscale logout` with OIDC [#508](https://github.com/juanfont/headscale/issues/508) ## 0.14.0 (2022-02-24) From 2e04abf4bb1f75d81726f04dc8ab5fc39ed4d183 Mon Sep 17 00:00:00 2001 From: Adrien Raffin-Caboisse Date: Fri, 18 Mar 2022 09:40:12 +0100 Subject: [PATCH 10/14] feat(oidc): add debug log --- oidc.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/oidc.go b/oidc.go index 29ce351f..e9f9d302 100644 --- a/oidc.go +++ b/oidc.go @@ -129,6 +129,10 @@ func (h *Headscale) OIDCCallback(ctx *gin.Context) { oauth2Token, err := h.oauth2Config.Exchange(context.Background(), code) if err != nil { + log.Error(). + Err(err). + Caller(). + Msg("Could not exchange code for token") ctx.String(http.StatusBadRequest, "Could not exchange code for token") return From 2e6687209bd3334f96e1d105375085966beda808 Mon Sep 17 00:00:00 2001 From: Juan Font Alonso Date: Fri, 18 Mar 2022 12:58:00 +0100 Subject: [PATCH 11/14] Make STUN server mandatory if DERP embedded is enabled --- cmd/headscale/cli/utils.go | 8 +++++--- config-example.yaml | 10 ++++------ integration_test/etc_embedded_derp/config.yaml | 5 ++--- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/cmd/headscale/cli/utils.go b/cmd/headscale/cli/utils.go index eb26a835..768a9713 100644 --- a/cmd/headscale/cli/utils.go +++ b/cmd/headscale/cli/utils.go @@ -124,8 +124,11 @@ func GetDERPConfig() headscale.DERPConfig { serverRegionID := viper.GetInt("derp.server.region_id") serverRegionCode := viper.GetString("derp.server.region_code") serverRegionName := viper.GetString("derp.server.region_name") - stunEnabled := viper.GetBool("derp.server.stun.enabled") - stunAddr := viper.GetString("derp.server.stun.listen_addr") + stunAddr := viper.GetString("derp.server.stun_listen_addr") + + if serverEnabled && stunAddr == "" { + log.Fatal().Msg("derp.server.stun_listen_addr must be set if derp.server.enabled is true") + } urlStrs := viper.GetStringSlice("derp.urls") @@ -152,7 +155,6 @@ func GetDERPConfig() headscale.DERPConfig { ServerRegionID: serverRegionID, ServerRegionCode: serverRegionCode, ServerRegionName: serverRegionName, - STUNEnabled: stunEnabled, STUNAddr: stunAddr, URLs: urls, Paths: paths, diff --git a/config-example.yaml b/config-example.yaml index 31d7a8aa..430b82c5 100644 --- a/config-example.yaml +++ b/config-example.yaml @@ -69,14 +69,12 @@ derp: region_code: "headscale" region_name: "Headscale Embedded DERP" - # Enabled by default when embedded DERP is enabled. Listens in UDP at the configured address for STUN connections - # to help on NAT traversal. - # If DERP is enabled, but STUN is disabled you still need to input an external STUN server in the listen_addr field. + + # Listens in UDP at the configured address for STUN connections to help on NAT traversal. + # When the embedded DERP server is enabled stun_listen_addr MUST be defined. # # For more details on how this works, check this great article: https://tailscale.com/blog/how-tailscale-works/ - stun: - enabled: true - listen_addr: "0.0.0.0:3478" + stun_listen_addr: "0.0.0.0:3478" # List of externally available DERP maps encoded in JSON urls: diff --git a/integration_test/etc_embedded_derp/config.yaml b/integration_test/etc_embedded_derp/config.yaml index 1531d347..a8b57af5 100644 --- a/integration_test/etc_embedded_derp/config.yaml +++ b/integration_test/etc_embedded_derp/config.yaml @@ -24,6 +24,5 @@ derp: region_id: 999 region_code: "headscale" region_name: "Headscale Embedded DERP" - stun: - enabled: true - listen_addr: "0.0.0.0:3478" + + stun_listen_addr: "0.0.0.0:3478" From d5ce7d752315cf31520052b67c182f25872a3ec1 Mon Sep 17 00:00:00 2001 From: Juan Font Alonso Date: Fri, 18 Mar 2022 13:09:57 +0100 Subject: [PATCH 12/14] Prettier --- config-example.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/config-example.yaml b/config-example.yaml index 430b82c5..dee25cb3 100644 --- a/config-example.yaml +++ b/config-example.yaml @@ -69,7 +69,6 @@ derp: region_code: "headscale" region_name: "Headscale Embedded DERP" - # Listens in UDP at the configured address for STUN connections to help on NAT traversal. # When the embedded DERP server is enabled stun_listen_addr MUST be defined. # From db9ba17920ca3eeea306b8f82fc121403e4f3c29 Mon Sep 17 00:00:00 2001 From: Juan Font Alonso Date: Fri, 18 Mar 2022 13:10:35 +0100 Subject: [PATCH 13/14] Added missing file --- app.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/app.go b/app.go index 9f270108..b87fb33c 100644 --- a/app.go +++ b/app.go @@ -127,7 +127,6 @@ type DERPConfig struct { ServerRegionID int ServerRegionCode string ServerRegionName string - STUNEnabled bool STUNAddr string URLs []url.URL Paths []string @@ -503,15 +502,13 @@ func (h *Headscale) Serve() error { h.DERPMap = GetDERPMap(h.cfg.DERP) if h.cfg.DERP.ServerEnabled { - // When embedded DERP is enabled we always need a STUN server address, embedded or external + // When embedded DERP is enabled we always need a STUN server if h.cfg.DERP.STUNAddr == "" { return errSTUNAddressNotSet } h.DERPMap.Regions[h.DERPServer.region.RegionID] = &h.DERPServer.region - if h.cfg.DERP.STUNEnabled { - go h.ServeSTUN() - } + go h.ServeSTUN() } if h.cfg.DERP.AutoUpdate { From 1eafe960b85eac57e1ad4331b15499a97b2f3adb Mon Sep 17 00:00:00 2001 From: Aofei Sheng Date: Sat, 19 Mar 2022 01:18:20 +0800 Subject: [PATCH 14/14] fix: possible panic in `Headscale.scheduledDERPMapUpdateWorker` There is a possible nil pointer dereference panic in the `Headscale.scheduledDERPMapUpdateWorker`. Such as when the embedded DERP server is disabled. --- derp.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/derp.go b/derp.go index 7a9b2367..7abce683 100644 --- a/derp.go +++ b/derp.go @@ -148,7 +148,9 @@ func (h *Headscale) scheduledDERPMapUpdateWorker(cancelChan <-chan struct{}) { case <-ticker.C: log.Info().Msg("Fetching DERPMap updates") h.DERPMap = GetDERPMap(h.cfg.DERP) - h.DERPMap.Regions[h.DERPServer.region.RegionID] = &h.DERPServer.region + if h.cfg.DERP.ServerEnabled { + h.DERPMap.Regions[h.DERPServer.region.RegionID] = &h.DERPServer.region + } namespaces, err := h.ListNamespaces() if err != nil {