mirror of
https://github.com/juanfont/headscale.git
synced 2024-11-29 18:33:05 +00:00
Add back privatekey, but automatically generate it if it does not exist
This commit is contained in:
parent
32006f3a20
commit
34f4109fbd
4 changed files with 73 additions and 16 deletions
2
api.go
2
api.go
|
@ -34,7 +34,7 @@ func (h *Headscale) KeyHandler(ctx *gin.Context) {
|
|||
ctx.Data(
|
||||
http.StatusOK,
|
||||
"text/plain; charset=utf-8",
|
||||
[]byte(MachinePublicKeyStripPrefix(*h.publicKey)),
|
||||
[]byte(MachinePublicKeyStripPrefix(h.privateKey.Public())),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
67
app.go
67
app.go
|
@ -47,11 +47,12 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
AuthPrefix = "Bearer "
|
||||
Postgres = "postgres"
|
||||
Sqlite = "sqlite3"
|
||||
updateInterval = 5000
|
||||
HTTPReadTimeout = 30 * time.Second
|
||||
AuthPrefix = "Bearer "
|
||||
Postgres = "postgres"
|
||||
Sqlite = "sqlite3"
|
||||
updateInterval = 5000
|
||||
HTTPReadTimeout = 30 * time.Second
|
||||
privateKeyFileMode = 0o600
|
||||
|
||||
requestedExpiryCacheExpiration = time.Minute * 5
|
||||
requestedExpiryCacheCleanupInterval = time.Minute * 10
|
||||
|
@ -68,6 +69,7 @@ type Config struct {
|
|||
Addr string
|
||||
EphemeralNodeInactivityTimeout time.Duration
|
||||
IPPrefix netaddr.IPPrefix
|
||||
PrivateKeyPath string
|
||||
BaseDomain string
|
||||
|
||||
DERP DERPConfig
|
||||
|
@ -128,7 +130,6 @@ type Headscale struct {
|
|||
dbString string
|
||||
dbType string
|
||||
dbDebug bool
|
||||
publicKey *key.MachinePublic
|
||||
privateKey *key.MachinePrivate
|
||||
|
||||
DERPMap *tailcfg.DERPMap
|
||||
|
@ -147,8 +148,10 @@ type Headscale struct {
|
|||
|
||||
// NewHeadscale returns the Headscale app.
|
||||
func NewHeadscale(cfg Config) (*Headscale, error) {
|
||||
privKey := key.NewMachine()
|
||||
pubKey := privKey.Public()
|
||||
privKey, err := readOrCreatePrivateKey(cfg.PrivateKeyPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read or create private key: %w", err)
|
||||
}
|
||||
|
||||
var dbString string
|
||||
switch cfg.DBtype {
|
||||
|
@ -176,13 +179,12 @@ func NewHeadscale(cfg Config) (*Headscale, error) {
|
|||
cfg: cfg,
|
||||
dbType: cfg.DBtype,
|
||||
dbString: dbString,
|
||||
privateKey: &privKey,
|
||||
publicKey: &pubKey,
|
||||
privateKey: privKey,
|
||||
aclRules: tailcfg.FilterAllowAll, // default allowall
|
||||
requestedExpiryCache: requestedExpiryCache,
|
||||
}
|
||||
|
||||
err := app.initDB()
|
||||
err = app.initDB()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -694,3 +696,46 @@ func stdoutHandler(ctx *gin.Context) {
|
|||
Bytes("body", body).
|
||||
Msg("Request did not match")
|
||||
}
|
||||
|
||||
func readOrCreatePrivateKey(path string) (*key.MachinePrivate, error) {
|
||||
privateKey, err := os.ReadFile(path)
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
log.Info().Str("path", path).Msg("No private key file at path, creating...")
|
||||
|
||||
machineKey := key.NewMachine()
|
||||
|
||||
machineKeyStr, err := machineKey.MarshalText()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"failed to convert private key to string for saving: %w",
|
||||
err,
|
||||
)
|
||||
}
|
||||
err = os.WriteFile(path, machineKeyStr, privateKeyFileMode)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"failed to save private key to disk: %w",
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
return &machineKey, nil
|
||||
} else if err != nil {
|
||||
return nil, fmt.Errorf("failed to read private key file: %w", err)
|
||||
}
|
||||
|
||||
privateKeyEnsurePrefix := PrivateKeyEnsurePrefix(string(privateKey))
|
||||
|
||||
var machineKey key.MachinePrivate
|
||||
if err = machineKey.UnmarshalText([]byte(privateKeyEnsurePrefix)); 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)
|
||||
}
|
||||
|
||||
return &machineKey, nil
|
||||
}
|
||||
|
|
|
@ -222,10 +222,11 @@ func getHeadscaleConfig() headscale.Config {
|
|||
derpConfig := GetDERPConfig()
|
||||
|
||||
return headscale.Config{
|
||||
ServerURL: viper.GetString("server_url"),
|
||||
Addr: viper.GetString("listen_addr"),
|
||||
IPPrefix: netaddr.MustParseIPPrefix(viper.GetString("ip_prefix")),
|
||||
BaseDomain: baseDomain,
|
||||
ServerURL: viper.GetString("server_url"),
|
||||
Addr: viper.GetString("listen_addr"),
|
||||
IPPrefix: netaddr.MustParseIPPrefix(viper.GetString("ip_prefix")),
|
||||
PrivateKeyPath: absPath(viper.GetString("private_key_path")),
|
||||
BaseDomain: baseDomain,
|
||||
|
||||
DERP: derpConfig,
|
||||
|
||||
|
|
11
utils.go
11
utils.go
|
@ -46,6 +46,9 @@ const (
|
|||
// This prefix is used in the control protocol, so cannot be
|
||||
// changed.
|
||||
discoPublicHexPrefix = "discokey:"
|
||||
|
||||
// privateKey prefix.
|
||||
privateHexPrefix = "privkey:"
|
||||
)
|
||||
|
||||
func MachinePublicKeyStripPrefix(machineKey key.MachinePublic) string {
|
||||
|
@ -84,6 +87,14 @@ func DiscoPublicKeyEnsurePrefix(discoKey string) string {
|
|||
return discoKey
|
||||
}
|
||||
|
||||
func PrivateKeyEnsurePrefix(privateKey string) string {
|
||||
if !strings.HasPrefix(privateKey, privateHexPrefix) {
|
||||
return privateHexPrefix + privateKey
|
||||
}
|
||||
|
||||
return privateKey
|
||||
}
|
||||
|
||||
// Error is used to compare errors as per https://dave.cheney.net/2016/04/07/constant-errors
|
||||
type Error string
|
||||
|
||||
|
|
Loading…
Reference in a new issue