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/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)
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/README.md b/README.md
index 7bb7018f..596c2580 100644
--- a/README.md
+++ b/README.md
@@ -447,6 +447,15 @@ make build
Tjerk Woudsma
+
+
+
+
+ Yang Bin
+
+ |
+
+
@@ -454,8 +463,6 @@ make build
Zakhar Bessarab
|
-
-
@@ -463,6 +470,13 @@ make build
ZiYuan
|
+
+
+
+
+ bravechamp
+
+ |
@@ -484,6 +498,8 @@ make build
lion24
|
+
+
@@ -498,8 +514,6 @@ make build
Wakeful-Cloud
|
-
-
diff --git a/app.go b/app.go
index f1426bbb..b87fb33c 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,11 +66,6 @@ const (
registerCacheExpiration = time.Minute * 15
registerCacheCleanup = time.Minute * 20
- errUnsupportedDatabase = Error("unsupported DB")
- errUnsupportedLetsEncryptChallengeType = Error(
- "unknown value for Lets Encrypt challenge type",
- )
-
DisabledClientAuth = "disabled"
RelaxedClientAuth = "relaxed"
EnforcedClientAuth = "enforced"
@@ -124,7 +127,6 @@ type DERPConfig struct {
ServerRegionID int
ServerRegionCode string
ServerRegionName string
- STUNEnabled bool
STUNAddr string
URLs []url.URL
Paths []string
@@ -409,8 +411,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().
@@ -502,10 +502,13 @@ func (h *Headscale) Serve() error {
h.DERPMap = GetDERPMap(h.cfg.DERP)
if h.cfg.DERP.ServerEnabled {
- h.DERPMap.Regions[h.DERPServer.region.RegionID] = &h.DERPServer.region
- if h.cfg.DERP.STUNEnabled {
- go h.ServeSTUN()
+ // 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
+ go h.ServeSTUN()
}
if h.cfg.DERP.AutoUpdate {
diff --git a/cmd/headscale/cli/utils.go b/cmd/headscale/cli/utils.go
index dc7a4e9f..768a9713 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")
@@ -121,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")
@@ -149,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 2075e69a..dee25cb3 100644
--- a/config-example.yaml
+++ b/config-example.yaml
@@ -69,11 +69,11 @@ 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
+ # 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: false
- 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/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 {
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
}
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/)):
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
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"
diff --git a/oidc.go b/oidc.go
index 29ce351f..598a208d 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"
@@ -129,6 +130,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
@@ -229,7 +234,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{
|