Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove support for non-noise clients (pre-1.32) #1611

Merged
merged 10 commits into from
Nov 23, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
remove 2019 private key
Signed-off-by: Kristoffer Dalby <[email protected]>
  • Loading branch information
kradalby committed Nov 21, 2023
commit 58c57048d8c33a1cd4d2da5456807ae260323f35
15 changes: 7 additions & 8 deletions config-example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,12 @@ grpc_listen_addr: 127.0.0.1:50443
# are doing.
grpc_allow_insecure: false

# Private key used to encrypt the traffic between headscale
# and Tailscale clients.
# The private key file will be autogenerated if it's missing.
#
private_key_path: /var/lib/headscale/private.key

# The Noise section includes specific configuration for the
# TS2021 Noise protocol
noise:
# The Noise private key is used to encrypt the
# traffic between headscale and Tailscale clients when
# using the new Noise-based protocol. It must be different
# from the legacy private key.
# using the new Noise-based protocol.
private_key_path: /var/lib/headscale/noise_private.key

# List of IP prefixes to allocate tailaddresses from.
Expand Down Expand Up @@ -95,6 +88,12 @@ derp:
# For more details on how this works, check this great article: https://tailscale.com/blog/how-tailscale-works/
stun_listen_addr: "0.0.0.0:3478"

# Private key used to encrypt the traffic between headscale DERP
# and Tailscale clients.
# The private key file will be autogenerated if it's missing.
#
private_key_path: /var/lib/headscale/derp_server_private.key

# List of externally available DERP maps encoded in JSON
urls:
- https://controlplane.tailscale.com/derpmap/default
Expand Down
30 changes: 10 additions & 20 deletions hscontrol/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ type Headscale struct {
dbString string
dbType string
dbDebug bool
privateKey2019 *key.MachinePrivate
noisePrivateKey *key.MachinePrivate

DERPMap *tailcfg.DERPMap
Expand All @@ -101,21 +100,11 @@ func NewHeadscale(cfg *types.Config) (*Headscale, error) {
runtime.SetBlockProfileRate(1)
}

privateKey, err := readOrCreatePrivateKey(cfg.PrivateKeyPath)
if err != nil {
return nil, fmt.Errorf("failed to read or create private key: %w", err)
}

// TS2021 requires to have a different key from the legacy protocol.
noisePrivateKey, err := readOrCreatePrivateKey(cfg.NoisePrivateKeyPath)
if err != nil {
return nil, fmt.Errorf("failed to read or create Noise protocol private key: %w", err)
}

if privateKey.Equal(*noisePrivateKey) {
return nil, fmt.Errorf("private key and noise private key are the same: %w", err)
}

var dbString string
switch cfg.DBtype {
case db.Postgres:
Expand Down Expand Up @@ -156,7 +145,6 @@ func NewHeadscale(cfg *types.Config) (*Headscale, error) {
cfg: cfg,
dbType: cfg.DBtype,
dbString: dbString,
privateKey2019: privateKey,
noisePrivateKey: noisePrivateKey,
registrationCache: registrationCache,
pollNetMapStreamWG: sync.WaitGroup{},
Expand Down Expand Up @@ -199,10 +187,18 @@ func NewHeadscale(cfg *types.Config) (*Headscale, error) {
}

if cfg.DERP.ServerEnabled {
// TODO(kradalby): replace this key with a dedicated DERP key.
derpServerKey, err := readOrCreatePrivateKey(cfg.DERP.ServerPrivateKeyPath)
if err != nil {
return nil, fmt.Errorf("failed to read or create DERP server private key: %w", err)
}

if derpServerKey.Equal(*noisePrivateKey) {
return nil, fmt.Errorf("DERP server private key and noise private key are the same: %w", err)
}

embeddedDERPServer, err := derpServer.NewDERPServer(
cfg.ServerURL,
key.NodePrivate(*privateKey),
key.NodePrivate(*derpServerKey),
&cfg.DERP,
)
if err != nil {
Expand Down Expand Up @@ -913,12 +909,6 @@ func readOrCreatePrivateKey(path string) (*key.MachinePrivate, error) {

var machineKey key.MachinePrivate
if err = machineKey.UnmarshalText([]byte(trimmedPrivateKey)); err != nil {
log.Info().
Str("path", path).
Msg("This might be due to a legacy (headscale pre-0.12) private key. " +
"If the key is in WireGuard format, delete the key and restart headscale. " +
"A new key will automatically be generated. All Tailscale clients will have to be restarted")

return nil, fmt.Errorf("failed to parse private key: %w", err)
}

Expand Down
10 changes: 4 additions & 6 deletions hscontrol/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@ import (
"tailscale.com/types/key"
)

// handleRegister is the common logic for registering a client in the legacy and Noise protocols
//
// When using Noise, the machineKey is Zero.
// handleRegister is the logic for registering a client.
func (h *Headscale) handleRegister(
writer http.ResponseWriter,
req *http.Request,
Expand Down Expand Up @@ -210,7 +208,6 @@ func (h *Headscale) handleRegister(
}

// handleAuthKey contains the logic to manage auth key client registration
// It is used both by the legacy and the new Noise protocol.
// When using Noise, the machineKey is Zero.
//
// TODO: check if any locks are needed around IP allocation.
Expand Down Expand Up @@ -414,8 +411,9 @@ func (h *Headscale) handleAuthKey(
Msg("Successfully authenticated via AuthKey")
}

// handleNewNode exposes for both legacy and Noise the functionality to get a URL
// for authorizing the node. This url is then showed to the user by the local Tailscale client.
// handleNewNode returns the authorisation URL to the client based on what type
// of registration headscale is configured with.
// This url is then showed to the user by the local Tailscale client.
func (h *Headscale) handleNewNode(
writer http.ResponseWriter,
registerRequest tailcfg.RegisterRequest,
Expand Down
24 changes: 1 addition & 23 deletions hscontrol/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"html/template"
"net/http"
"strconv"
"strings"
"time"

"github.com/gorilla/mux"
Expand Down Expand Up @@ -63,26 +62,6 @@ func (h *Headscale) KeyHandler(
// New Tailscale clients send a 'v' parameter to indicate the CurrentCapabilityVersion
capVer, err := parseCabailityVersion(req)
if err != nil {
if errors.Is(err, ErrNoCapabilityVersion) {
log.Debug().
Str("handler", "/key").
Msg("New legacy client")
// Old clients don't send a 'v' parameter, so we send the legacy public key
writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
writer.WriteHeader(http.StatusOK)
_, err := writer.Write(
[]byte(strings.TrimPrefix(h.privateKey2019.Public().String(), "mkey:")),
)
if err != nil {
log.Error().
Caller().
Err(err).
Msg("Failed to write response")
}

return
}

log.Error().
Caller().
Err(err).
Expand Down Expand Up @@ -120,8 +99,7 @@ func (h *Headscale) KeyHandler(
// TS2021 (Tailscale v2 protocol) requires to have a different key
if capVer >= NoiseCapabilityVersion {
resp := tailcfg.OverTLSPublicKeyResponse{
LegacyPublicKey: h.privateKey2019.Public(),
PublicKey: h.noisePrivateKey.Public(),
PublicKey: h.noisePrivateKey.Public(),
}
writer.Header().Set("Content-Type", "application/json")
writer.WriteHeader(http.StatusOK)
Expand Down
8 changes: 2 additions & 6 deletions hscontrol/mapper/mapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import (
"tailscale.com/smallzstd"
"tailscale.com/tailcfg"
"tailscale.com/types/dnstype"
"tailscale.com/types/key"
)

const (
Expand All @@ -48,8 +47,7 @@ var debugDumpMapResponsePath = envknob.String("HEADSCALE_DEBUG_DUMP_MAPRESPONSE_
// - Create a "minifier" that removes info not needed for the node

type Mapper struct {
privateKey2019 *key.MachinePrivate
capVer tailcfg.CapabilityVersion
capVer tailcfg.CapabilityVersion

// Configuration
// TODO(kradalby): figure out if this is the format we want this in
Expand All @@ -72,7 +70,6 @@ type Mapper struct {
func NewMapper(
node *types.Node,
peers types.Nodes,
privateKey *key.MachinePrivate,
capVer tailcfg.CapabilityVersion,
derpMap *tailcfg.DERPMap,
baseDomain string,
Expand All @@ -88,8 +85,7 @@ func NewMapper(
uid, _ := util.GenerateRandomStringDNSSafe(mapperIDLength)

return &Mapper{
privateKey2019: privateKey,
capVer: capVer,
capVer: capVer,

derpMap: derpMap,
baseDomain: baseDomain,
Expand Down
1 change: 0 additions & 1 deletion hscontrol/mapper/mapper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,6 @@ func Test_fullMapResponse(t *testing.T) {
mappy := NewMapper(
tt.node,
tt.peers,
nil,
0,
tt.derpMap,
tt.baseDomain,
Expand Down
6 changes: 2 additions & 4 deletions hscontrol/poll.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ func logPollFunc(
}
}

// handlePoll is the common code for the legacy and Noise protocols to
// managed the poll loop.
// handlePoll ensures the node gets the appropriate updates from either
// polling or immediate responses.
//
//nolint:gocyclo
func (h *Headscale) handlePoll(
Expand Down Expand Up @@ -155,7 +155,6 @@ func (h *Headscale) handlePoll(
mapp := mapper.NewMapper(
node,
peers,
h.privateKey2019,
capVer,
h.DERPMap,
h.cfg.BaseDomain,
Expand Down Expand Up @@ -384,7 +383,6 @@ func (h *Headscale) handleLiteRequest(
// TODO(kradalby): It might not be acceptable to send
// an empty peer list here.
types.Nodes{},
h.privateKey2019,
capVer,
h.DERPMap,
h.cfg.BaseDomain,
Expand Down
1 change: 0 additions & 1 deletion hscontrol/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ func (s *Suite) ResetDB(c *check.C) {
c.Fatal(err)
}
cfg := types.Config{
PrivateKeyPath: tmpDir + "/private.key",
NoisePrivateKeyPath: tmpDir + "/noise_private.key",
DBtype: "sqlite3",
DBpath: tmpDir + "/headscale_test.db",
Expand Down
43 changes: 21 additions & 22 deletions hscontrol/types/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ type Config struct {
EphemeralNodeInactivityTimeout time.Duration
NodeUpdateCheckInterval time.Duration
IPPrefixes []netip.Prefix
PrivateKeyPath string
NoisePrivateKeyPath string
BaseDomain string
Log LogConfig
Expand Down Expand Up @@ -108,15 +107,16 @@ type OIDCConfig struct {
}

type DERPConfig struct {
ServerEnabled bool
ServerRegionID int
ServerRegionCode string
ServerRegionName string
STUNAddr string
URLs []url.URL
Paths []string
AutoUpdate bool
UpdateFrequency time.Duration
ServerEnabled bool
ServerRegionID int
ServerRegionCode string
ServerRegionName string
ServerPrivateKeyPath string
STUNAddr string
URLs []url.URL
Paths []string
AutoUpdate bool
UpdateFrequency time.Duration
}

type LogTailConfig struct {
Expand Down Expand Up @@ -286,6 +286,7 @@ func GetDERPConfig() DERPConfig {
serverRegionCode := viper.GetString("derp.server.region_code")
serverRegionName := viper.GetString("derp.server.region_name")
stunAddr := viper.GetString("derp.server.stun_listen_addr")
privateKeyPath := util.AbsolutePathFromConfigPath(viper.GetString("derp.server.private_key_path"))

if serverEnabled && stunAddr == "" {
log.Fatal().
Expand Down Expand Up @@ -313,15 +314,16 @@ func GetDERPConfig() DERPConfig {
updateFrequency := viper.GetDuration("derp.update_frequency")

return DERPConfig{
ServerEnabled: serverEnabled,
ServerRegionID: serverRegionID,
ServerRegionCode: serverRegionCode,
ServerRegionName: serverRegionName,
STUNAddr: stunAddr,
URLs: urls,
Paths: paths,
AutoUpdate: autoUpdate,
UpdateFrequency: updateFrequency,
ServerEnabled: serverEnabled,
ServerRegionID: serverRegionID,
ServerRegionCode: serverRegionCode,
ServerRegionName: serverRegionName,
ServerPrivateKeyPath: privateKeyPath,
STUNAddr: stunAddr,
URLs: urls,
Paths: paths,
AutoUpdate: autoUpdate,
UpdateFrequency: updateFrequency,
}
}

Expand Down Expand Up @@ -582,9 +584,6 @@ func GetHeadscaleConfig() (*Config, error) {
DisableUpdateCheck: viper.GetBool("disable_check_updates"),

IPPrefixes: prefixes,
PrivateKeyPath: util.AbsolutePathFromConfigPath(
viper.GetString("private_key_path"),
),
NoisePrivateKeyPath: util.AbsolutePathFromConfigPath(
viper.GetString("noise.private_key_path"),
),
Expand Down