2023-06-06 08:23:39 +00:00
package types
2022-06-03 07:05:41 +00:00
import (
2022-06-03 07:26:36 +00:00
"errors"
"fmt"
2022-06-03 07:05:41 +00:00
"io/fs"
2022-09-04 09:32:29 +00:00
"net/netip"
2022-06-03 07:05:41 +00:00
"net/url"
2023-01-10 11:46:42 +00:00
"os"
2022-06-03 07:26:36 +00:00
"strings"
2022-06-03 07:05:41 +00:00
"time"
2022-06-03 07:26:36 +00:00
"github.com/coreos/go-oidc/v3/oidc"
2024-07-22 06:56:00 +00:00
"github.com/juanfont/headscale/hscontrol/util"
2023-01-31 11:40:38 +00:00
"github.com/prometheus/common/model"
2022-06-03 08:37:45 +00:00
"github.com/rs/zerolog"
2022-06-03 07:26:36 +00:00
"github.com/rs/zerolog/log"
"github.com/spf13/viper"
2022-09-01 22:04:04 +00:00
"go4.org/netipx"
2023-05-06 09:30:15 +00:00
"tailscale.com/net/tsaddr"
2022-06-03 07:05:41 +00:00
"tailscale.com/tailcfg"
2022-06-03 07:26:36 +00:00
"tailscale.com/types/dnstype"
2024-08-19 09:41:05 +00:00
"tailscale.com/util/set"
2022-06-03 07:05:41 +00:00
)
2022-07-11 18:33:24 +00:00
const (
2023-01-31 11:40:38 +00:00
defaultOIDCExpiryTime = 180 * 24 * time . Hour // 180 Days
maxDuration time . Duration = 1 << 63 - 1
2022-07-11 18:33:24 +00:00
)
2023-01-31 11:40:38 +00:00
var errOidcMutuallyExclusive = errors . New (
"oidc_client_secret and oidc_client_secret_path are mutually exclusive" ,
)
2023-01-10 11:46:42 +00:00
2024-04-17 05:03:06 +00:00
type IPAllocationStrategy string
const (
IPAllocationStrategySequential IPAllocationStrategy = "sequential"
IPAllocationStrategyRandom IPAllocationStrategy = "random"
)
2024-07-18 05:38:25 +00:00
type PolicyMode string
const (
PolicyModeDB = "database"
PolicyModeFile = "file"
)
2022-06-03 07:05:41 +00:00
// Config contains the initial Headscale configuration.
type Config struct {
ServerURL string
Addr string
MetricsAddr string
GRPCAddr string
GRPCAllowInsecure bool
EphemeralNodeInactivityTimeout time . Duration
2024-02-18 18:31:29 +00:00
PrefixV4 * netip . Prefix
PrefixV6 * netip . Prefix
2024-04-17 05:03:06 +00:00
IPAllocation IPAllocationStrategy
2022-08-13 09:14:38 +00:00
NoisePrivateKeyPath string
2022-06-03 07:05:41 +00:00
BaseDomain string
2022-09-11 19:37:23 +00:00
Log LogConfig
2022-06-03 08:37:45 +00:00
DisableUpdateCheck bool
2022-06-03 07:05:41 +00:00
2024-02-09 06:27:00 +00:00
Database DatabaseConfig
2022-06-03 07:05:41 +00:00
2024-02-09 06:27:00 +00:00
DERP DERPConfig
2022-06-03 07:05:41 +00:00
2022-06-03 08:14:14 +00:00
TLS TLSConfig
2022-06-03 07:05:41 +00:00
ACMEURL string
ACMEEmail string
Redo OIDC configuration (#2020)
expand user, add claims to user
This commit expands the user table with additional fields that
can be retrieved from OIDC providers (and other places) and
uses this data in various tailscale response objects if it is
available.
This is the beginning of implementing
https://docs.google.com/document/d/1X85PMxIaVWDF6T_UPji3OeeUqVBcGj_uHRM5CI-AwlY/edit
trying to make OIDC more coherant and maintainable in addition
to giving the user a better experience and integration with a
provider.
remove usernames in magic dns, normalisation of emails
this commit removes the option to have usernames as part of MagicDNS
domains and headscale will now align with Tailscale, where there is a
root domain, and the machine name.
In addition, the various normalisation functions for dns names has been
made lighter not caring about username and special character that wont
occur.
Email are no longer normalised as part of the policy processing.
untagle oidc and regcache, use typed cache
This commits stops reusing the registration cache for oidc
purposes and switches the cache to be types and not use any
allowing the removal of a bunch of casting.
try to make reauth/register branches clearer in oidc
Currently there was a function that did a bunch of stuff,
finding the machine key, trying to find the node, reauthing
the node, returning some status, and it was called validate
which was very confusing.
This commit tries to split this into what to do if the node
exists, if it needs to register etc.
Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
2024-10-02 12:50:17 +00:00
DNSConfig * tailcfg . DNSConfig
2022-06-03 07:05:41 +00:00
UnixSocket string
UnixSocketPermission fs . FileMode
OIDC OIDCConfig
2022-06-09 19:20:11 +00:00
LogTail LogTailConfig
RandomizeClientPort bool
2022-06-03 07:05:41 +00:00
CLI CLIConfig
2024-07-18 05:38:25 +00:00
Policy PolicyConfig
2024-02-23 09:59:24 +00:00
Tuning Tuning
2022-06-03 07:05:41 +00:00
}
2024-08-19 09:41:05 +00:00
type DNSConfig struct {
Redo OIDC configuration (#2020)
expand user, add claims to user
This commit expands the user table with additional fields that
can be retrieved from OIDC providers (and other places) and
uses this data in various tailscale response objects if it is
available.
This is the beginning of implementing
https://docs.google.com/document/d/1X85PMxIaVWDF6T_UPji3OeeUqVBcGj_uHRM5CI-AwlY/edit
trying to make OIDC more coherant and maintainable in addition
to giving the user a better experience and integration with a
provider.
remove usernames in magic dns, normalisation of emails
this commit removes the option to have usernames as part of MagicDNS
domains and headscale will now align with Tailscale, where there is a
root domain, and the machine name.
In addition, the various normalisation functions for dns names has been
made lighter not caring about username and special character that wont
occur.
Email are no longer normalised as part of the policy processing.
untagle oidc and regcache, use typed cache
This commits stops reusing the registration cache for oidc
purposes and switches the cache to be types and not use any
allowing the removal of a bunch of casting.
try to make reauth/register branches clearer in oidc
Currently there was a function that did a bunch of stuff,
finding the machine key, trying to find the node, reauthing
the node, returning some status, and it was called validate
which was very confusing.
This commit tries to split this into what to do if the node
exists, if it needs to register etc.
Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
2024-10-02 12:50:17 +00:00
MagicDNS bool ` mapstructure:"magic_dns" `
BaseDomain string ` mapstructure:"base_domain" `
Nameservers Nameservers
SearchDomains [ ] string ` mapstructure:"search_domains" `
ExtraRecords [ ] tailcfg . DNSRecord ` mapstructure:"extra_records" `
2024-08-19 09:41:05 +00:00
}
type Nameservers struct {
Global [ ] string
Split map [ string ] [ ] string
}
2024-02-09 06:27:00 +00:00
type SqliteConfig struct {
2024-06-23 20:06:59 +00:00
Path string
WriteAheadLog bool
2024-02-09 06:27:00 +00:00
}
type PostgresConfig struct {
2024-02-09 16:34:28 +00:00
Host string
Port int
Name string
User string
Pass string
Ssl string
MaxOpenConnections int
MaxIdleConnections int
ConnMaxIdleTimeSecs int
2024-02-09 06:27:00 +00:00
}
2024-08-19 09:47:52 +00:00
type GormConfig struct {
Debug bool
SlowThreshold time . Duration
SkipErrRecordNotFound bool
ParameterizedQueries bool
PrepareStmt bool
}
2024-02-09 06:27:00 +00:00
type DatabaseConfig struct {
// Type sets the database type, either "sqlite3" or "postgres"
Type string
Debug bool
2024-08-19 09:47:52 +00:00
// Type sets the gorm configuration
Gorm GormConfig
2024-02-09 06:27:00 +00:00
Sqlite SqliteConfig
Postgres PostgresConfig
}
2022-06-03 08:14:14 +00:00
type TLSConfig struct {
2022-11-19 10:33:15 +00:00
CertPath string
KeyPath string
2022-06-03 08:14:14 +00:00
LetsEncrypt LetsEncryptConfig
}
type LetsEncryptConfig struct {
Listen string
Hostname string
CacheDir string
ChallengeType string
}
2022-06-03 07:05:41 +00:00
type OIDCConfig struct {
2022-09-26 07:57:28 +00:00
OnlyStartIfOIDCIsAvailable bool
Issuer string
ClientID string
ClientSecret string
Scope [ ] string
ExtraParams map [ string ] string
AllowedDomains [ ] string
AllowedUsers [ ] string
2022-12-07 00:08:01 +00:00
AllowedGroups [ ] string
2024-10-17 12:22:44 +00:00
StripEmaildomain bool
2023-01-31 11:40:38 +00:00
Expiry time . Duration
UseExpiryFromToken bool
2024-10-04 10:24:35 +00:00
MapLegacyUsers bool
2022-06-03 07:05:41 +00:00
}
type DERPConfig struct {
2024-01-16 15:04:03 +00:00
ServerEnabled bool
AutomaticallyAddEmbeddedDerpRegion bool
ServerRegionID int
ServerRegionCode string
ServerRegionName string
ServerPrivateKeyPath string
STUNAddr string
URLs [ ] url . URL
Paths [ ] string
2024-10-17 11:34:20 +00:00
DERPMap * tailcfg . DERPMap
2024-01-16 15:04:03 +00:00
AutoUpdate bool
UpdateFrequency time . Duration
IPv4 string
IPv6 string
2022-06-03 07:05:41 +00:00
}
type LogTailConfig struct {
Enabled bool
}
type CLIConfig struct {
Address string
APIKey string
Timeout time . Duration
Insecure bool
}
2024-07-18 05:38:25 +00:00
type PolicyConfig struct {
Path string
Mode PolicyMode
2022-06-03 07:05:41 +00:00
}
2022-06-03 07:26:36 +00:00
2022-09-11 19:37:23 +00:00
type LogConfig struct {
Format string
Level zerolog . Level
}
2024-02-23 09:59:24 +00:00
type Tuning struct {
2024-05-24 08:15:34 +00:00
NotifierSendTimeout time . Duration
2024-02-23 09:59:24 +00:00
BatchChangeDelay time . Duration
NodeMapSessionBufferedChanSize int
}
2024-09-07 07:23:58 +00:00
// LoadConfig prepares and loads the Headscale configuration into Viper.
// This means it sets the default values, reads the configuration file and
// environment variables, and handles deprecated configuration options.
// It has to be called before LoadServerConfig and LoadCLIConfig.
// The configuration is not validated and the caller should check for errors
// using a validation function.
2022-06-07 14:24:35 +00:00
func LoadConfig ( path string , isFile bool ) error {
if isFile {
viper . SetConfigFile ( path )
2022-06-03 07:26:36 +00:00
} else {
2022-06-07 14:24:35 +00:00
viper . SetConfigName ( "config" )
if path == "" {
viper . AddConfigPath ( "/etc/headscale/" )
viper . AddConfigPath ( "$HOME/.headscale" )
viper . AddConfigPath ( "." )
} else {
// For testing
viper . AddConfigPath ( path )
}
2022-06-03 07:26:36 +00:00
}
2024-08-19 09:41:05 +00:00
envPrefix := "headscale"
viper . SetEnvPrefix ( envPrefix )
2022-06-03 07:26:36 +00:00
viper . SetEnvKeyReplacer ( strings . NewReplacer ( "." , "_" ) )
viper . AutomaticEnv ( )
2024-07-18 05:38:25 +00:00
viper . SetDefault ( "policy.mode" , "file" )
2022-06-03 07:26:36 +00:00
viper . SetDefault ( "tls_letsencrypt_cache_dir" , "/var/www/.cache" )
2023-06-06 09:12:36 +00:00
viper . SetDefault ( "tls_letsencrypt_challenge_type" , HTTP01ChallengeType )
2022-06-03 07:26:36 +00:00
2022-09-11 19:37:23 +00:00
viper . SetDefault ( "log.level" , "info" )
viper . SetDefault ( "log.format" , TextLogFormat )
2022-06-03 07:26:36 +00:00
2024-08-19 09:41:05 +00:00
viper . SetDefault ( "dns.magic_dns" , true )
viper . SetDefault ( "dns.base_domain" , "" )
viper . SetDefault ( "dns.nameservers.global" , [ ] string { } )
viper . SetDefault ( "dns.nameservers.split" , map [ string ] string { } )
viper . SetDefault ( "dns.search_domains" , [ ] string { } )
viper . SetDefault ( "dns.extra_records" , [ ] tailcfg . DNSRecord { } )
2022-06-03 07:26:36 +00:00
viper . SetDefault ( "derp.server.enabled" , false )
viper . SetDefault ( "derp.server.stun.enabled" , true )
2024-01-16 15:04:03 +00:00
viper . SetDefault ( "derp.server.automatically_add_embedded_derp_region" , true )
2022-06-03 07:26:36 +00:00
2023-05-10 14:32:15 +00:00
viper . SetDefault ( "unix_socket" , "/var/run/headscale/headscale.sock" )
2022-06-03 07:26:36 +00:00
viper . SetDefault ( "unix_socket_permission" , "0o770" )
viper . SetDefault ( "grpc_listen_addr" , ":50443" )
viper . SetDefault ( "grpc_allow_insecure" , false )
viper . SetDefault ( "cli.timeout" , "5s" )
viper . SetDefault ( "cli.insecure" , false )
2024-02-09 06:27:00 +00:00
viper . SetDefault ( "database.postgres.ssl" , false )
2024-02-09 16:34:28 +00:00
viper . SetDefault ( "database.postgres.max_open_conns" , 10 )
viper . SetDefault ( "database.postgres.max_idle_conns" , 10 )
viper . SetDefault ( "database.postgres.conn_max_idle_time_secs" , 3600 )
2022-12-07 08:37:45 +00:00
2024-06-23 20:06:59 +00:00
viper . SetDefault ( "database.sqlite.write_ahead_log" , true )
2022-06-03 07:26:36 +00:00
viper . SetDefault ( "oidc.scope" , [ ] string { oidc . ScopeOpenID , "profile" , "email" } )
2024-10-17 12:22:44 +00:00
viper . SetDefault ( "oidc.strip_email_domain" , true )
2022-09-26 07:57:28 +00:00
viper . SetDefault ( "oidc.only_start_if_oidc_is_available" , true )
2023-01-31 11:40:38 +00:00
viper . SetDefault ( "oidc.expiry" , "180d" )
viper . SetDefault ( "oidc.use_expiry_from_token" , false )
2024-10-04 10:24:35 +00:00
viper . SetDefault ( "oidc.map_legacy_users" , true )
2022-06-03 07:26:36 +00:00
viper . SetDefault ( "logtail.enabled" , false )
2022-06-09 19:20:11 +00:00
viper . SetDefault ( "randomize_client_port" , false )
2022-06-03 07:26:36 +00:00
2022-06-12 13:12:53 +00:00
viper . SetDefault ( "ephemeral_node_inactivity_timeout" , "120s" )
2024-05-24 08:15:34 +00:00
viper . SetDefault ( "tuning.notifier_send_timeout" , "800ms" )
2024-02-23 09:59:24 +00:00
viper . SetDefault ( "tuning.batch_change_delay" , "800ms" )
viper . SetDefault ( "tuning.node_mapsession_buffered_chan_size" , 30 )
2024-04-17 09:09:22 +00:00
viper . SetDefault ( "prefixes.allocation" , string ( IPAllocationStrategySequential ) )
2024-04-17 05:03:06 +00:00
2022-06-03 07:26:36 +00:00
if err := viper . ReadInConfig ( ) ; err != nil {
return fmt . Errorf ( "fatal error reading config file: %w" , err )
}
2024-09-07 07:23:58 +00:00
return nil
}
func validateServerConfig ( ) error {
2024-08-19 09:41:05 +00:00
depr := deprecator {
warns : make ( set . Set [ string ] ) ,
fatals : make ( set . Set [ string ] ) ,
}
2024-07-18 05:38:25 +00:00
// Register aliases for backward compatibility
// Has to be called _after_ viper.ReadInConfig()
// https://github.com/spf13/viper/issues/560
// Alias the old ACL Policy path with the new configuration option.
2024-08-19 11:03:01 +00:00
depr . fatalIfNewKeyIsNotUsed ( "policy.path" , "acl_policy_path" )
2024-08-19 09:41:05 +00:00
// Move dns_config -> dns
depr . warn ( "dns_config.override_local_dns" )
depr . fatalIfNewKeyIsNotUsed ( "dns.magic_dns" , "dns_config.magic_dns" )
depr . fatalIfNewKeyIsNotUsed ( "dns.base_domain" , "dns_config.base_domain" )
depr . fatalIfNewKeyIsNotUsed ( "dns.nameservers.global" , "dns_config.nameservers" )
depr . fatalIfNewKeyIsNotUsed ( "dns.nameservers.split" , "dns_config.restricted_nameservers" )
depr . fatalIfNewKeyIsNotUsed ( "dns.search_domains" , "dns_config.domains" )
depr . fatalIfNewKeyIsNotUsed ( "dns.extra_records" , "dns_config.extra_records" )
depr . warn ( "dns_config.use_username_in_magic_dns" )
depr . warn ( "dns.use_username_in_magic_dns" )
2024-10-17 12:22:44 +00:00
// TODO(kradalby): Reintroduce when strip_email_domain is removed
// after #2170 is cleaned up
// depr.fatal("oidc.strip_email_domain")
Redo OIDC configuration (#2020)
expand user, add claims to user
This commit expands the user table with additional fields that
can be retrieved from OIDC providers (and other places) and
uses this data in various tailscale response objects if it is
available.
This is the beginning of implementing
https://docs.google.com/document/d/1X85PMxIaVWDF6T_UPji3OeeUqVBcGj_uHRM5CI-AwlY/edit
trying to make OIDC more coherant and maintainable in addition
to giving the user a better experience and integration with a
provider.
remove usernames in magic dns, normalisation of emails
this commit removes the option to have usernames as part of MagicDNS
domains and headscale will now align with Tailscale, where there is a
root domain, and the machine name.
In addition, the various normalisation functions for dns names has been
made lighter not caring about username and special character that wont
occur.
Email are no longer normalised as part of the policy processing.
untagle oidc and regcache, use typed cache
This commits stops reusing the registration cache for oidc
purposes and switches the cache to be types and not use any
allowing the removal of a bunch of casting.
try to make reauth/register branches clearer in oidc
Currently there was a function that did a bunch of stuff,
finding the machine key, trying to find the node, reauthing
the node, returning some status, and it was called validate
which was very confusing.
This commit tries to split this into what to do if the node
exists, if it needs to register etc.
Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
2024-10-02 12:50:17 +00:00
depr . fatal ( "dns.use_username_in_musername_in_magic_dns" )
depr . fatal ( "dns_config.use_username_in_musername_in_magic_dns" )
2024-08-19 09:41:05 +00:00
depr . Log ( )
2024-07-18 05:38:25 +00:00
Redo OIDC configuration (#2020)
expand user, add claims to user
This commit expands the user table with additional fields that
can be retrieved from OIDC providers (and other places) and
uses this data in various tailscale response objects if it is
available.
This is the beginning of implementing
https://docs.google.com/document/d/1X85PMxIaVWDF6T_UPji3OeeUqVBcGj_uHRM5CI-AwlY/edit
trying to make OIDC more coherant and maintainable in addition
to giving the user a better experience and integration with a
provider.
remove usernames in magic dns, normalisation of emails
this commit removes the option to have usernames as part of MagicDNS
domains and headscale will now align with Tailscale, where there is a
root domain, and the machine name.
In addition, the various normalisation functions for dns names has been
made lighter not caring about username and special character that wont
occur.
Email are no longer normalised as part of the policy processing.
untagle oidc and regcache, use typed cache
This commits stops reusing the registration cache for oidc
purposes and switches the cache to be types and not use any
allowing the removal of a bunch of casting.
try to make reauth/register branches clearer in oidc
Currently there was a function that did a bunch of stuff,
finding the machine key, trying to find the node, reauthing
the node, returning some status, and it was called validate
which was very confusing.
This commit tries to split this into what to do if the node
exists, if it needs to register etc.
Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
2024-10-02 12:50:17 +00:00
for _ , removed := range [ ] string {
2024-10-17 12:22:44 +00:00
// TODO(kradalby): Reintroduce when strip_email_domain is removed
// after #2170 is cleaned up
// "oidc.strip_email_domain",
Redo OIDC configuration (#2020)
expand user, add claims to user
This commit expands the user table with additional fields that
can be retrieved from OIDC providers (and other places) and
uses this data in various tailscale response objects if it is
available.
This is the beginning of implementing
https://docs.google.com/document/d/1X85PMxIaVWDF6T_UPji3OeeUqVBcGj_uHRM5CI-AwlY/edit
trying to make OIDC more coherant and maintainable in addition
to giving the user a better experience and integration with a
provider.
remove usernames in magic dns, normalisation of emails
this commit removes the option to have usernames as part of MagicDNS
domains and headscale will now align with Tailscale, where there is a
root domain, and the machine name.
In addition, the various normalisation functions for dns names has been
made lighter not caring about username and special character that wont
occur.
Email are no longer normalised as part of the policy processing.
untagle oidc and regcache, use typed cache
This commits stops reusing the registration cache for oidc
purposes and switches the cache to be types and not use any
allowing the removal of a bunch of casting.
try to make reauth/register branches clearer in oidc
Currently there was a function that did a bunch of stuff,
finding the machine key, trying to find the node, reauthing
the node, returning some status, and it was called validate
which was very confusing.
This commit tries to split this into what to do if the node
exists, if it needs to register etc.
Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
2024-10-02 12:50:17 +00:00
"dns_config.use_username_in_musername_in_magic_dns" ,
} {
if viper . IsSet ( removed ) {
log . Fatal ( ) .
Msgf ( "Fatal config error: %s has been removed. Please remove it from your config file" , removed )
}
}
2022-06-03 07:26:36 +00:00
// Collect any validation errors and return them all at once
var errorText string
if ( viper . GetString ( "tls_letsencrypt_hostname" ) != "" ) &&
( ( viper . GetString ( "tls_cert_path" ) != "" ) || ( viper . GetString ( "tls_key_path" ) != "" ) ) {
errorText += "Fatal config error: set either tls_letsencrypt_hostname or tls_cert_path/tls_key_path, not both\n"
}
2022-08-21 08:42:23 +00:00
if ! viper . IsSet ( "noise" ) || viper . GetString ( "noise.private_key_path" ) == "" {
errorText += "Fatal config error: headscale now requires a new `noise.private_key_path` field in the config file for the Tailscale v2 protocol\n"
2022-08-14 10:35:14 +00:00
}
2022-06-03 07:26:36 +00:00
if ( viper . GetString ( "tls_letsencrypt_hostname" ) != "" ) &&
2023-06-06 09:12:36 +00:00
( viper . GetString ( "tls_letsencrypt_challenge_type" ) == TLSALPN01ChallengeType ) &&
2022-06-03 07:26:36 +00:00
( ! strings . HasSuffix ( viper . GetString ( "listen_addr" ) , ":443" ) ) {
// this is only a warning because there could be something sitting in front of headscale that redirects the traffic (e.g. an iptables rule)
log . Warn ( ) .
Msg ( "Warning: when using tls_letsencrypt_hostname with TLS-ALPN-01 as challenge type, headscale must be reachable on port 443, i.e. listen_addr should probably end in :443" )
}
2023-06-06 09:12:36 +00:00
if ( viper . GetString ( "tls_letsencrypt_challenge_type" ) != HTTP01ChallengeType ) &&
( viper . GetString ( "tls_letsencrypt_challenge_type" ) != TLSALPN01ChallengeType ) {
2022-06-03 07:26:36 +00:00
errorText += "Fatal config error: the only supported values for tls_letsencrypt_challenge_type are HTTP-01 and TLS-ALPN-01\n"
}
if ! strings . HasPrefix ( viper . GetString ( "server_url" ) , "http://" ) &&
! strings . HasPrefix ( viper . GetString ( "server_url" ) , "https://" ) {
errorText += "Fatal config error: server_url must start with https:// or http://\n"
}
2022-06-12 13:12:43 +00:00
// Minimum inactivity time out is keepalive timeout (60s) plus a few seconds
// to avoid races
minInactivityTimeout , _ := time . ParseDuration ( "65s" )
if viper . GetDuration ( "ephemeral_node_inactivity_timeout" ) <= minInactivityTimeout {
errorText += fmt . Sprintf (
"Fatal config error: ephemeral_node_inactivity_timeout (%s) is set too low, must be more than %s" ,
viper . GetString ( "ephemeral_node_inactivity_timeout" ) ,
minInactivityTimeout ,
)
}
2022-06-03 07:26:36 +00:00
if errorText != "" {
2024-02-09 16:34:28 +00:00
// nolint
2022-06-03 07:26:36 +00:00
return errors . New ( strings . TrimSuffix ( errorText , "\n" ) )
}
2024-09-07 07:23:58 +00:00
return nil
2022-06-03 07:26:36 +00:00
}
2024-09-07 07:23:58 +00:00
func tlsConfig ( ) TLSConfig {
2022-06-03 08:14:14 +00:00
return TLSConfig {
LetsEncrypt : LetsEncryptConfig {
Hostname : viper . GetString ( "tls_letsencrypt_hostname" ) ,
Listen : viper . GetString ( "tls_letsencrypt_listen" ) ,
2023-05-11 07:09:18 +00:00
CacheDir : util . AbsolutePathFromConfigPath (
2022-06-03 08:14:14 +00:00
viper . GetString ( "tls_letsencrypt_cache_dir" ) ,
) ,
ChallengeType : viper . GetString ( "tls_letsencrypt_challenge_type" ) ,
} ,
2023-05-11 07:09:18 +00:00
CertPath : util . AbsolutePathFromConfigPath (
2022-06-03 08:14:14 +00:00
viper . GetString ( "tls_cert_path" ) ,
) ,
2023-05-11 07:09:18 +00:00
KeyPath : util . AbsolutePathFromConfigPath (
2022-06-03 08:14:14 +00:00
viper . GetString ( "tls_key_path" ) ,
) ,
}
}
2024-09-07 07:23:58 +00:00
func derpConfig ( ) DERPConfig {
2022-06-03 07:26:36 +00:00
serverEnabled := viper . GetBool ( "derp.server.enabled" )
serverRegionID := viper . GetInt ( "derp.server.region_id" )
serverRegionCode := viper . GetString ( "derp.server.region_code" )
serverRegionName := viper . GetString ( "derp.server.region_name" )
stunAddr := viper . GetString ( "derp.server.stun_listen_addr" )
2024-01-16 15:04:03 +00:00
privateKeyPath := util . AbsolutePathFromConfigPath (
viper . GetString ( "derp.server.private_key_path" ) ,
)
ipv4 := viper . GetString ( "derp.server.ipv4" )
ipv6 := viper . GetString ( "derp.server.ipv6" )
automaticallyAddEmbeddedDerpRegion := viper . GetBool (
"derp.server.automatically_add_embedded_derp_region" ,
)
2022-06-03 07:26:36 +00:00
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" )
urls := make ( [ ] url . URL , len ( urlStrs ) )
for index , urlStr := range urlStrs {
urlAddr , err := url . Parse ( urlStr )
if err != nil {
log . Error ( ) .
Str ( "url" , urlStr ) .
Err ( err ) .
Msg ( "Failed to parse url, ignoring..." )
}
urls [ index ] = * urlAddr
}
paths := viper . GetStringSlice ( "derp.paths" )
2024-01-16 15:04:03 +00:00
if serverEnabled && ! automaticallyAddEmbeddedDerpRegion && len ( paths ) == 0 {
log . Fatal ( ) .
Msg ( "Disabling derp.server.automatically_add_embedded_derp_region requires to configure the derp server in derp.paths" )
}
2022-06-03 07:26:36 +00:00
autoUpdate := viper . GetBool ( "derp.auto_update_enabled" )
updateFrequency := viper . GetDuration ( "derp.update_frequency" )
return DERPConfig {
2024-01-16 15:04:03 +00:00
ServerEnabled : serverEnabled ,
ServerRegionID : serverRegionID ,
ServerRegionCode : serverRegionCode ,
ServerRegionName : serverRegionName ,
ServerPrivateKeyPath : privateKeyPath ,
STUNAddr : stunAddr ,
URLs : urls ,
Paths : paths ,
AutoUpdate : autoUpdate ,
UpdateFrequency : updateFrequency ,
IPv4 : ipv4 ,
IPv6 : ipv6 ,
AutomaticallyAddEmbeddedDerpRegion : automaticallyAddEmbeddedDerpRegion ,
2022-06-03 07:26:36 +00:00
}
}
2024-09-07 07:23:58 +00:00
func logtailConfig ( ) LogTailConfig {
2022-06-03 07:26:36 +00:00
enabled := viper . GetBool ( "logtail.enabled" )
return LogTailConfig {
Enabled : enabled ,
}
}
2024-09-07 07:23:58 +00:00
func policyConfig ( ) PolicyConfig {
2024-07-18 05:38:25 +00:00
policyPath := viper . GetString ( "policy.path" )
policyMode := viper . GetString ( "policy.mode" )
2022-06-03 07:26:36 +00:00
2024-07-18 05:38:25 +00:00
return PolicyConfig {
Path : policyPath ,
Mode : PolicyMode ( policyMode ) ,
2022-06-03 07:26:36 +00:00
}
}
2024-09-07 07:23:58 +00:00
func logConfig ( ) LogConfig {
2022-09-11 19:37:23 +00:00
logLevelStr := viper . GetString ( "log.level" )
logLevel , err := zerolog . ParseLevel ( logLevelStr )
if err != nil {
logLevel = zerolog . DebugLevel
}
logFormatOpt := viper . GetString ( "log.format" )
var logFormat string
switch logFormatOpt {
2024-09-07 07:23:58 +00:00
case JSONLogFormat :
2022-09-11 19:37:23 +00:00
logFormat = JSONLogFormat
2024-09-07 07:23:58 +00:00
case TextLogFormat :
2022-09-11 19:37:23 +00:00
logFormat = TextLogFormat
case "" :
logFormat = TextLogFormat
default :
log . Error ( ) .
Str ( "func" , "GetLogConfig" ) .
Msgf ( "Could not parse log format: %s. Valid choices are 'json' or 'text'" , logFormatOpt )
}
return LogConfig {
Format : logFormat ,
Level : logLevel ,
}
}
2024-09-07 07:23:58 +00:00
func databaseConfig ( ) DatabaseConfig {
2024-02-09 06:27:00 +00:00
debug := viper . GetBool ( "database.debug" )
type_ := viper . GetString ( "database.type" )
2024-08-19 09:47:52 +00:00
skipErrRecordNotFound := viper . GetBool ( "database.gorm.skip_err_record_not_found" )
slowThreshold := viper . GetDuration ( "database.gorm.slow_threshold" ) * time . Millisecond
parameterizedQueries := viper . GetBool ( "database.gorm.parameterized_queries" )
prepareStmt := viper . GetBool ( "database.gorm.prepare_stmt" )
2024-02-09 06:27:00 +00:00
switch type_ {
case DatabaseSqlite , DatabasePostgres :
break
case "sqlite" :
type_ = "sqlite3"
default :
2024-02-09 16:34:28 +00:00
log . Fatal ( ) .
Msgf ( "invalid database type %q, must be sqlite, sqlite3 or postgres" , type_ )
2024-02-09 06:27:00 +00:00
}
return DatabaseConfig {
Type : type_ ,
Debug : debug ,
2024-08-19 09:47:52 +00:00
Gorm : GormConfig {
Debug : debug ,
SkipErrRecordNotFound : skipErrRecordNotFound ,
SlowThreshold : slowThreshold ,
ParameterizedQueries : parameterizedQueries ,
PrepareStmt : prepareStmt ,
} ,
2024-02-09 06:27:00 +00:00
Sqlite : SqliteConfig {
2024-02-09 16:34:28 +00:00
Path : util . AbsolutePathFromConfigPath (
viper . GetString ( "database.sqlite.path" ) ,
) ,
2024-06-23 20:06:59 +00:00
WriteAheadLog : viper . GetBool ( "database.sqlite.write_ahead_log" ) ,
2024-02-09 06:27:00 +00:00
} ,
Postgres : PostgresConfig {
2024-02-09 16:34:28 +00:00
Host : viper . GetString ( "database.postgres.host" ) ,
Port : viper . GetInt ( "database.postgres.port" ) ,
Name : viper . GetString ( "database.postgres.name" ) ,
User : viper . GetString ( "database.postgres.user" ) ,
Pass : viper . GetString ( "database.postgres.pass" ) ,
Ssl : viper . GetString ( "database.postgres.ssl" ) ,
MaxOpenConnections : viper . GetInt ( "database.postgres.max_open_conns" ) ,
MaxIdleConnections : viper . GetInt ( "database.postgres.max_idle_conns" ) ,
ConnMaxIdleTimeSecs : viper . GetInt (
"database.postgres.conn_max_idle_time_secs" ,
) ,
2024-02-09 06:27:00 +00:00
} ,
}
}
2024-09-07 07:23:58 +00:00
func dns ( ) ( DNSConfig , error ) {
2024-08-19 09:41:05 +00:00
var dns DNSConfig
2022-06-03 07:26:36 +00:00
2024-08-19 09:41:05 +00:00
// TODO: Use this instead of manually getting settings when
// UnmarshalKey is compatible with Environment Variables.
// err := viper.UnmarshalKey("dns", &dns)
// if err != nil {
// return DNSConfig{}, fmt.Errorf("unmarshaling dns config: %w", err)
// }
2022-10-31 15:26:18 +00:00
2024-08-19 09:41:05 +00:00
dns . MagicDNS = viper . GetBool ( "dns.magic_dns" )
dns . BaseDomain = viper . GetString ( "dns.base_domain" )
dns . Nameservers . Global = viper . GetStringSlice ( "dns.nameservers.global" )
dns . Nameservers . Split = viper . GetStringMapStringSlice ( "dns.nameservers.split" )
dns . SearchDomains = viper . GetStringSlice ( "dns.search_domains" )
2022-06-03 07:26:36 +00:00
2024-08-19 09:41:05 +00:00
if viper . IsSet ( "dns.extra_records" ) {
var extraRecords [ ] tailcfg . DNSRecord
2022-11-07 20:10:06 +00:00
2024-08-19 09:41:05 +00:00
err := viper . UnmarshalKey ( "dns.extra_records" , & extraRecords )
if err != nil {
return DNSConfig { } , fmt . Errorf ( "unmarshaling dns extra records: %w" , err )
}
dns . ExtraRecords = extraRecords
}
2022-06-03 07:26:36 +00:00
2024-08-19 09:41:05 +00:00
return dns , nil
}
2022-06-03 07:26:36 +00:00
2024-09-07 07:23:58 +00:00
// globalResolvers returns the global DNS resolvers
2024-08-19 09:41:05 +00:00
// defined in the config file.
// If a nameserver is a valid IP, it will be used as a regular resolver.
// If a nameserver is a valid URL, it will be used as a DoH resolver.
// If a nameserver is neither a valid URL nor a valid IP, it will be ignored.
2024-09-07 07:23:58 +00:00
func ( d * DNSConfig ) globalResolvers ( ) [ ] * dnstype . Resolver {
2024-08-19 09:41:05 +00:00
var resolvers [ ] * dnstype . Resolver
for _ , nsStr := range d . Nameservers . Global {
warn := ""
if _ , err := netip . ParseAddr ( nsStr ) ; err == nil {
resolvers = append ( resolvers , & dnstype . Resolver {
Addr : nsStr ,
} )
continue
} else {
warn = fmt . Sprintf ( "Invalid global nameserver %q. Parsing error: %s ignoring" , nsStr , err )
}
2022-10-31 15:26:18 +00:00
2024-08-19 09:41:05 +00:00
if _ , err := url . Parse ( nsStr ) ; err == nil {
resolvers = append ( resolvers , & dnstype . Resolver {
Addr : nsStr ,
} )
2024-08-23 15:17:37 +00:00
continue
2024-08-19 09:41:05 +00:00
} else {
warn = fmt . Sprintf ( "Invalid global nameserver %q. Parsing error: %s ignoring" , nsStr , err )
2022-06-03 07:26:36 +00:00
}
2024-08-19 09:41:05 +00:00
if warn != "" {
log . Warn ( ) . Msg ( warn )
2022-06-03 07:26:36 +00:00
}
2024-08-19 09:41:05 +00:00
}
return resolvers
}
2022-06-03 07:26:36 +00:00
2024-09-07 07:23:58 +00:00
// splitResolvers returns a map of domain to DNS resolvers.
2024-08-19 09:41:05 +00:00
// If a nameserver is a valid IP, it will be used as a regular resolver.
// If a nameserver is a valid URL, it will be used as a DoH resolver.
// If a nameserver is neither a valid URL nor a valid IP, it will be ignored.
2024-09-07 07:23:58 +00:00
func ( d * DNSConfig ) splitResolvers ( ) map [ string ] [ ] * dnstype . Resolver {
2024-08-19 09:41:05 +00:00
routes := make ( map [ string ] [ ] * dnstype . Resolver )
for domain , nameservers := range d . Nameservers . Split {
var resolvers [ ] * dnstype . Resolver
for _ , nsStr := range nameservers {
warn := ""
if _ , err := netip . ParseAddr ( nsStr ) ; err == nil {
resolvers = append ( resolvers , & dnstype . Resolver {
Addr : nsStr ,
} )
2022-12-02 01:03:26 +00:00
2024-08-19 09:41:05 +00:00
continue
} else {
warn = fmt . Sprintf ( "Invalid split dns nameserver %q. Parsing error: %s ignoring" , nsStr , err )
2022-12-02 01:03:26 +00:00
}
2024-08-19 09:41:05 +00:00
if _ , err := url . Parse ( nsStr ) ; err == nil {
resolvers = append ( resolvers , & dnstype . Resolver {
Addr : nsStr ,
} )
2024-08-23 15:17:37 +00:00
continue
2024-08-19 09:41:05 +00:00
} else {
warn = fmt . Sprintf ( "Invalid split dns nameserver %q. Parsing error: %s ignoring" , nsStr , err )
}
2022-12-02 01:03:26 +00:00
2024-08-19 09:41:05 +00:00
if warn != "" {
log . Warn ( ) . Msg ( warn )
}
2022-10-31 14:59:50 +00:00
}
2024-08-19 09:41:05 +00:00
routes [ domain ] = resolvers
}
2022-10-31 14:59:50 +00:00
2024-08-19 09:41:05 +00:00
return routes
}
2022-06-03 07:26:36 +00:00
2024-09-07 07:23:58 +00:00
func dnsToTailcfgDNS ( dns DNSConfig ) * tailcfg . DNSConfig {
2024-08-19 09:41:05 +00:00
cfg := tailcfg . DNSConfig { }
2024-06-26 11:44:40 +00:00
2024-08-19 09:41:05 +00:00
if dns . BaseDomain == "" && dns . MagicDNS {
log . Fatal ( ) . Msg ( "dns.base_domain must be set when using MagicDNS (dns.magic_dns)" )
}
2023-08-31 16:37:18 +00:00
2024-08-19 09:41:05 +00:00
cfg . Proxied = dns . MagicDNS
cfg . ExtraRecords = dns . ExtraRecords
2024-09-07 07:23:58 +00:00
cfg . Resolvers = dns . globalResolvers ( )
2024-08-19 09:41:05 +00:00
2024-09-07 07:23:58 +00:00
routes := dns . splitResolvers ( )
2024-08-19 09:41:05 +00:00
cfg . Routes = routes
if dns . BaseDomain != "" {
cfg . Domains = [ ] string { dns . BaseDomain }
2022-06-03 07:26:36 +00:00
}
2024-08-19 09:41:05 +00:00
cfg . Domains = append ( cfg . Domains , dns . SearchDomains ... )
2022-06-03 07:26:36 +00:00
2024-08-19 09:41:05 +00:00
return & cfg
2022-06-03 07:26:36 +00:00
}
2024-09-07 07:23:58 +00:00
func prefixV4 ( ) ( * netip . Prefix , error ) {
2024-02-18 18:31:29 +00:00
prefixV4Str := viper . GetString ( "prefixes.v4" )
2024-04-17 05:03:06 +00:00
if prefixV4Str == "" {
return nil , nil
2024-02-18 18:31:29 +00:00
}
2024-04-17 05:03:06 +00:00
prefixV4 , err := netip . ParsePrefix ( prefixV4Str )
2024-02-18 18:31:29 +00:00
if err != nil {
2024-04-17 05:03:06 +00:00
return nil , fmt . Errorf ( "parsing IPv4 prefix from config: %w" , err )
2024-02-18 18:31:29 +00:00
}
builder := netipx . IPSetBuilder { }
builder . AddPrefix ( tsaddr . CGNATRange ( ) )
ipSet , _ := builder . IPSet ( )
if ! ipSet . ContainsPrefix ( prefixV4 ) {
log . Warn ( ) .
Msgf ( "Prefix %s is not in the %s range. This is an unsupported configuration." ,
prefixV4Str , tsaddr . CGNATRange ( ) )
}
2024-04-17 05:03:06 +00:00
return & prefixV4 , nil
}
2024-09-07 07:23:58 +00:00
func prefixV6 ( ) ( * netip . Prefix , error ) {
2024-04-17 05:03:06 +00:00
prefixV6Str := viper . GetString ( "prefixes.v6" )
if prefixV6Str == "" {
return nil , nil
}
prefixV6 , err := netip . ParsePrefix ( prefixV6Str )
if err != nil {
return nil , fmt . Errorf ( "parsing IPv6 prefix from config: %w" , err )
}
builder := netipx . IPSetBuilder { }
builder . AddPrefix ( tsaddr . TailscaleULARange ( ) )
ipSet , _ := builder . IPSet ( )
2024-02-18 18:31:29 +00:00
if ! ipSet . ContainsPrefix ( prefixV6 ) {
log . Warn ( ) .
Msgf ( "Prefix %s is not in the %s range. This is an unsupported configuration." ,
prefixV6Str , tsaddr . TailscaleULARange ( ) )
}
2024-04-17 05:03:06 +00:00
return & prefixV6 , nil
2024-02-18 18:31:29 +00:00
}
2024-09-07 07:23:58 +00:00
// LoadCLIConfig returns the needed configuration for the CLI client
// of Headscale to connect to a Headscale server.
func LoadCLIConfig ( ) ( * Config , error ) {
2024-09-11 08:43:22 +00:00
logConfig := logConfig ( )
zerolog . SetGlobalLevel ( logConfig . Level )
2024-09-07 07:23:58 +00:00
return & Config {
DisableUpdateCheck : viper . GetBool ( "disable_check_updates" ) ,
UnixSocket : viper . GetString ( "unix_socket" ) ,
CLI : CLIConfig {
Address : viper . GetString ( "cli.address" ) ,
APIKey : viper . GetString ( "cli.api_key" ) ,
Timeout : viper . GetDuration ( "cli.timeout" ) ,
Insecure : viper . GetBool ( "cli.insecure" ) ,
} ,
2024-09-11 08:43:22 +00:00
Log : logConfig ,
2024-09-07 07:23:58 +00:00
} , nil
}
// LoadServerConfig returns the full Headscale configuration to
// host a Headscale server. This is called as part of `headscale serve`.
func LoadServerConfig ( ) ( * Config , error ) {
if err := validateServerConfig ( ) ; err != nil {
return nil , err
2022-11-18 17:02:34 +00:00
}
2024-09-07 07:23:58 +00:00
logConfig := logConfig ( )
2024-05-16 00:40:30 +00:00
zerolog . SetGlobalLevel ( logConfig . Level )
2024-09-07 07:23:58 +00:00
prefix4 , err := prefixV4 ( )
2024-04-17 05:03:06 +00:00
if err != nil {
return nil , err
}
2024-09-07 07:23:58 +00:00
prefix6 , err := prefixV6 ( )
2024-02-18 18:31:29 +00:00
if err != nil {
return nil , err
}
2024-04-30 09:11:29 +00:00
if prefix4 == nil && prefix6 == nil {
return nil , fmt . Errorf ( "no IPv4 or IPv6 prefix configured, minimum one prefix is required" )
}
2024-04-17 05:03:06 +00:00
allocStr := viper . GetString ( "prefixes.allocation" )
var alloc IPAllocationStrategy
switch allocStr {
case string ( IPAllocationStrategySequential ) :
alloc = IPAllocationStrategySequential
case string ( IPAllocationStrategyRandom ) :
alloc = IPAllocationStrategyRandom
default :
Redo OIDC configuration (#2020)
expand user, add claims to user
This commit expands the user table with additional fields that
can be retrieved from OIDC providers (and other places) and
uses this data in various tailscale response objects if it is
available.
This is the beginning of implementing
https://docs.google.com/document/d/1X85PMxIaVWDF6T_UPji3OeeUqVBcGj_uHRM5CI-AwlY/edit
trying to make OIDC more coherant and maintainable in addition
to giving the user a better experience and integration with a
provider.
remove usernames in magic dns, normalisation of emails
this commit removes the option to have usernames as part of MagicDNS
domains and headscale will now align with Tailscale, where there is a
root domain, and the machine name.
In addition, the various normalisation functions for dns names has been
made lighter not caring about username and special character that wont
occur.
Email are no longer normalised as part of the policy processing.
untagle oidc and regcache, use typed cache
This commits stops reusing the registration cache for oidc
purposes and switches the cache to be types and not use any
allowing the removal of a bunch of casting.
try to make reauth/register branches clearer in oidc
Currently there was a function that did a bunch of stuff,
finding the machine key, trying to find the node, reauthing
the node, returning some status, and it was called validate
which was very confusing.
This commit tries to split this into what to do if the node
exists, if it needs to register etc.
Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
2024-10-02 12:50:17 +00:00
return nil , fmt . Errorf (
"config error, prefixes.allocation is set to %s, which is not a valid strategy, allowed options: %s, %s" ,
allocStr ,
IPAllocationStrategySequential ,
IPAllocationStrategyRandom ,
)
2024-04-17 05:03:06 +00:00
}
2024-09-07 07:23:58 +00:00
dnsConfig , err := dns ( )
2024-08-19 09:41:05 +00:00
if err != nil {
return nil , err
}
2024-09-07 07:23:58 +00:00
derpConfig := derpConfig ( )
logTailConfig := logtailConfig ( )
2022-06-09 19:20:11 +00:00
randomizeClientPort := viper . GetBool ( "randomize_client_port" )
2022-06-03 07:26:36 +00:00
2023-01-10 11:46:42 +00:00
oidcClientSecret := viper . GetString ( "oidc.client_secret" )
oidcClientSecretPath := viper . GetString ( "oidc.client_secret_path" )
if oidcClientSecretPath != "" && oidcClientSecret != "" {
return nil , errOidcMutuallyExclusive
}
if oidcClientSecretPath != "" {
secretBytes , err := os . ReadFile ( os . ExpandEnv ( oidcClientSecretPath ) )
if err != nil {
return nil , err
}
2024-01-25 08:53:34 +00:00
oidcClientSecret = strings . TrimSpace ( string ( secretBytes ) )
2023-01-10 11:46:42 +00:00
}
2024-08-19 09:41:05 +00:00
serverURL := viper . GetString ( "server_url" )
// BaseDomain cannot be the same as the server URL.
// This is because Tailscale takes over the domain in BaseDomain,
// causing the headscale server and DERP to be unreachable.
// For Tailscale upstream, the following is true:
// - DERP run on their own domains
// - Control plane runs on login.tailscale.com/controlplane.tailscale.com
// - MagicDNS (BaseDomain) for users is on a *.ts.net domain per tailnet (e.g. tail-scale.ts.net)
Redo OIDC configuration (#2020)
expand user, add claims to user
This commit expands the user table with additional fields that
can be retrieved from OIDC providers (and other places) and
uses this data in various tailscale response objects if it is
available.
This is the beginning of implementing
https://docs.google.com/document/d/1X85PMxIaVWDF6T_UPji3OeeUqVBcGj_uHRM5CI-AwlY/edit
trying to make OIDC more coherant and maintainable in addition
to giving the user a better experience and integration with a
provider.
remove usernames in magic dns, normalisation of emails
this commit removes the option to have usernames as part of MagicDNS
domains and headscale will now align with Tailscale, where there is a
root domain, and the machine name.
In addition, the various normalisation functions for dns names has been
made lighter not caring about username and special character that wont
occur.
Email are no longer normalised as part of the policy processing.
untagle oidc and regcache, use typed cache
This commits stops reusing the registration cache for oidc
purposes and switches the cache to be types and not use any
allowing the removal of a bunch of casting.
try to make reauth/register branches clearer in oidc
Currently there was a function that did a bunch of stuff,
finding the machine key, trying to find the node, reauthing
the node, returning some status, and it was called validate
which was very confusing.
This commit tries to split this into what to do if the node
exists, if it needs to register etc.
Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
2024-10-02 12:50:17 +00:00
if dnsConfig . BaseDomain != "" &&
strings . Contains ( serverURL , dnsConfig . BaseDomain ) {
return nil , errors . New (
"server_url cannot contain the base_domain, this will cause the headscale server and embedded DERP to become unreachable from the Tailscale node." ,
)
2024-08-19 09:41:05 +00:00
}
2022-06-05 15:47:12 +00:00
return & Config {
2024-08-19 09:41:05 +00:00
ServerURL : serverURL ,
2022-06-03 08:37:45 +00:00
Addr : viper . GetString ( "listen_addr" ) ,
MetricsAddr : viper . GetString ( "metrics_listen_addr" ) ,
GRPCAddr : viper . GetString ( "grpc_listen_addr" ) ,
GRPCAllowInsecure : viper . GetBool ( "grpc_allow_insecure" ) ,
2024-09-07 07:23:58 +00:00
DisableUpdateCheck : false ,
2022-06-03 07:26:36 +00:00
2024-04-17 05:03:06 +00:00
PrefixV4 : prefix4 ,
PrefixV6 : prefix6 ,
IPAllocation : IPAllocationStrategy ( alloc ) ,
2024-02-18 18:31:29 +00:00
2023-05-11 07:09:18 +00:00
NoisePrivateKeyPath : util . AbsolutePathFromConfigPath (
2022-08-21 08:42:23 +00:00
viper . GetString ( "noise.private_key_path" ) ,
2022-08-13 09:14:38 +00:00
) ,
2024-08-19 09:41:05 +00:00
BaseDomain : dnsConfig . BaseDomain ,
2022-06-03 07:26:36 +00:00
DERP : derpConfig ,
EphemeralNodeInactivityTimeout : viper . GetDuration (
"ephemeral_node_inactivity_timeout" ,
) ,
2024-09-07 07:23:58 +00:00
Database : databaseConfig ( ) ,
2022-06-03 07:26:36 +00:00
2024-09-07 07:23:58 +00:00
TLS : tlsConfig ( ) ,
2022-06-03 07:26:36 +00:00
Redo OIDC configuration (#2020)
expand user, add claims to user
This commit expands the user table with additional fields that
can be retrieved from OIDC providers (and other places) and
uses this data in various tailscale response objects if it is
available.
This is the beginning of implementing
https://docs.google.com/document/d/1X85PMxIaVWDF6T_UPji3OeeUqVBcGj_uHRM5CI-AwlY/edit
trying to make OIDC more coherant and maintainable in addition
to giving the user a better experience and integration with a
provider.
remove usernames in magic dns, normalisation of emails
this commit removes the option to have usernames as part of MagicDNS
domains and headscale will now align with Tailscale, where there is a
root domain, and the machine name.
In addition, the various normalisation functions for dns names has been
made lighter not caring about username and special character that wont
occur.
Email are no longer normalised as part of the policy processing.
untagle oidc and regcache, use typed cache
This commits stops reusing the registration cache for oidc
purposes and switches the cache to be types and not use any
allowing the removal of a bunch of casting.
try to make reauth/register branches clearer in oidc
Currently there was a function that did a bunch of stuff,
finding the machine key, trying to find the node, reauthing
the node, returning some status, and it was called validate
which was very confusing.
This commit tries to split this into what to do if the node
exists, if it needs to register etc.
Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
2024-10-02 12:50:17 +00:00
DNSConfig : dnsToTailcfgDNS ( dnsConfig ) ,
2022-06-03 07:26:36 +00:00
ACMEEmail : viper . GetString ( "acme_email" ) ,
ACMEURL : viper . GetString ( "acme_url" ) ,
UnixSocket : viper . GetString ( "unix_socket" ) ,
2023-05-11 07:09:18 +00:00
UnixSocketPermission : util . GetFileMode ( "unix_socket_permission" ) ,
2022-06-03 07:26:36 +00:00
OIDC : OIDCConfig {
2022-09-26 07:57:28 +00:00
OnlyStartIfOIDCIsAvailable : viper . GetBool (
"oidc.only_start_if_oidc_is_available" ,
) ,
Redo OIDC configuration (#2020)
expand user, add claims to user
This commit expands the user table with additional fields that
can be retrieved from OIDC providers (and other places) and
uses this data in various tailscale response objects if it is
available.
This is the beginning of implementing
https://docs.google.com/document/d/1X85PMxIaVWDF6T_UPji3OeeUqVBcGj_uHRM5CI-AwlY/edit
trying to make OIDC more coherant and maintainable in addition
to giving the user a better experience and integration with a
provider.
remove usernames in magic dns, normalisation of emails
this commit removes the option to have usernames as part of MagicDNS
domains and headscale will now align with Tailscale, where there is a
root domain, and the machine name.
In addition, the various normalisation functions for dns names has been
made lighter not caring about username and special character that wont
occur.
Email are no longer normalised as part of the policy processing.
untagle oidc and regcache, use typed cache
This commits stops reusing the registration cache for oidc
purposes and switches the cache to be types and not use any
allowing the removal of a bunch of casting.
try to make reauth/register branches clearer in oidc
Currently there was a function that did a bunch of stuff,
finding the machine key, trying to find the node, reauthing
the node, returning some status, and it was called validate
which was very confusing.
This commit tries to split this into what to do if the node
exists, if it needs to register etc.
Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
2024-10-02 12:50:17 +00:00
Issuer : viper . GetString ( "oidc.issuer" ) ,
ClientID : viper . GetString ( "oidc.client_id" ) ,
ClientSecret : oidcClientSecret ,
Scope : viper . GetStringSlice ( "oidc.scope" ) ,
ExtraParams : viper . GetStringMapString ( "oidc.extra_params" ) ,
AllowedDomains : viper . GetStringSlice ( "oidc.allowed_domains" ) ,
AllowedUsers : viper . GetStringSlice ( "oidc.allowed_users" ) ,
AllowedGroups : viper . GetStringSlice ( "oidc.allowed_groups" ) ,
2023-01-31 11:40:38 +00:00
Expiry : func ( ) time . Duration {
// if set to 0, we assume no expiry
if value := viper . GetString ( "oidc.expiry" ) ; value == "0" {
return maxDuration
} else {
expiry , err := model . ParseDuration ( value )
if err != nil {
log . Warn ( ) . Msg ( "failed to parse oidc.expiry, defaulting back to 180 days" )
return defaultOIDCExpiryTime
}
return time . Duration ( expiry )
}
} ( ) ,
UseExpiryFromToken : viper . GetBool ( "oidc.use_expiry_from_token" ) ,
2024-10-18 12:59:27 +00:00
// TODO(kradalby): Remove when strip_email_domain is removed
// after #2170 is cleaned up
StripEmaildomain : viper . GetBool ( "oidc.strip_email_domain" ) ,
MapLegacyUsers : viper . GetBool ( "oidc.map_legacy_users" ) ,
2022-06-03 07:26:36 +00:00
} ,
2024-05-16 00:40:30 +00:00
LogTail : logTailConfig ,
2022-06-09 19:20:11 +00:00
RandomizeClientPort : randomizeClientPort ,
2022-06-03 07:26:36 +00:00
2024-09-07 07:23:58 +00:00
Policy : policyConfig ( ) ,
2022-09-11 19:37:23 +00:00
2022-11-18 17:48:34 +00:00
CLI : CLIConfig {
Address : viper . GetString ( "cli.address" ) ,
APIKey : viper . GetString ( "cli.api_key" ) ,
Timeout : viper . GetDuration ( "cli.timeout" ) ,
Insecure : viper . GetBool ( "cli.insecure" ) ,
} ,
2024-05-16 00:40:30 +00:00
Log : logConfig ,
2024-02-23 09:59:24 +00:00
// TODO(kradalby): Document these settings when more stable
Tuning : Tuning {
Redo OIDC configuration (#2020)
expand user, add claims to user
This commit expands the user table with additional fields that
can be retrieved from OIDC providers (and other places) and
uses this data in various tailscale response objects if it is
available.
This is the beginning of implementing
https://docs.google.com/document/d/1X85PMxIaVWDF6T_UPji3OeeUqVBcGj_uHRM5CI-AwlY/edit
trying to make OIDC more coherant and maintainable in addition
to giving the user a better experience and integration with a
provider.
remove usernames in magic dns, normalisation of emails
this commit removes the option to have usernames as part of MagicDNS
domains and headscale will now align with Tailscale, where there is a
root domain, and the machine name.
In addition, the various normalisation functions for dns names has been
made lighter not caring about username and special character that wont
occur.
Email are no longer normalised as part of the policy processing.
untagle oidc and regcache, use typed cache
This commits stops reusing the registration cache for oidc
purposes and switches the cache to be types and not use any
allowing the removal of a bunch of casting.
try to make reauth/register branches clearer in oidc
Currently there was a function that did a bunch of stuff,
finding the machine key, trying to find the node, reauthing
the node, returning some status, and it was called validate
which was very confusing.
This commit tries to split this into what to do if the node
exists, if it needs to register etc.
Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
2024-10-02 12:50:17 +00:00
NotifierSendTimeout : viper . GetDuration ( "tuning.notifier_send_timeout" ) ,
BatchChangeDelay : viper . GetDuration ( "tuning.batch_change_delay" ) ,
NodeMapSessionBufferedChanSize : viper . GetInt (
"tuning.node_mapsession_buffered_chan_size" ,
) ,
2024-02-23 09:59:24 +00:00
} ,
2022-06-05 15:47:12 +00:00
} , nil
2022-06-03 07:26:36 +00:00
}
2022-11-18 17:02:34 +00:00
2024-08-19 09:41:05 +00:00
type deprecator struct {
warns set . Set [ string ]
fatals set . Set [ string ]
}
// warnWithAlias will register an alias between the newKey and the oldKey,
2024-07-18 05:38:25 +00:00
// and log a deprecation warning if the oldKey is set.
2024-08-19 09:41:05 +00:00
func ( d * deprecator ) warnWithAlias ( newKey , oldKey string ) {
2024-07-18 05:38:25 +00:00
// NOTE: RegisterAlias is called with NEW KEY -> OLD KEY
viper . RegisterAlias ( newKey , oldKey )
if viper . IsSet ( oldKey ) {
Redo OIDC configuration (#2020)
expand user, add claims to user
This commit expands the user table with additional fields that
can be retrieved from OIDC providers (and other places) and
uses this data in various tailscale response objects if it is
available.
This is the beginning of implementing
https://docs.google.com/document/d/1X85PMxIaVWDF6T_UPji3OeeUqVBcGj_uHRM5CI-AwlY/edit
trying to make OIDC more coherant and maintainable in addition
to giving the user a better experience and integration with a
provider.
remove usernames in magic dns, normalisation of emails
this commit removes the option to have usernames as part of MagicDNS
domains and headscale will now align with Tailscale, where there is a
root domain, and the machine name.
In addition, the various normalisation functions for dns names has been
made lighter not caring about username and special character that wont
occur.
Email are no longer normalised as part of the policy processing.
untagle oidc and regcache, use typed cache
This commits stops reusing the registration cache for oidc
purposes and switches the cache to be types and not use any
allowing the removal of a bunch of casting.
try to make reauth/register branches clearer in oidc
Currently there was a function that did a bunch of stuff,
finding the machine key, trying to find the node, reauthing
the node, returning some status, and it was called validate
which was very confusing.
This commit tries to split this into what to do if the node
exists, if it needs to register etc.
Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
2024-10-02 12:50:17 +00:00
d . warns . Add (
fmt . Sprintf (
"The %q configuration key is deprecated. Please use %q instead. %q will be removed in the future." ,
oldKey ,
newKey ,
oldKey ,
) ,
)
2024-07-18 05:38:25 +00:00
}
}
2024-08-19 09:41:05 +00:00
// fatal deprecates and adds an entry to the fatal list of options if the oldKey is set.
Redo OIDC configuration (#2020)
expand user, add claims to user
This commit expands the user table with additional fields that
can be retrieved from OIDC providers (and other places) and
uses this data in various tailscale response objects if it is
available.
This is the beginning of implementing
https://docs.google.com/document/d/1X85PMxIaVWDF6T_UPji3OeeUqVBcGj_uHRM5CI-AwlY/edit
trying to make OIDC more coherant and maintainable in addition
to giving the user a better experience and integration with a
provider.
remove usernames in magic dns, normalisation of emails
this commit removes the option to have usernames as part of MagicDNS
domains and headscale will now align with Tailscale, where there is a
root domain, and the machine name.
In addition, the various normalisation functions for dns names has been
made lighter not caring about username and special character that wont
occur.
Email are no longer normalised as part of the policy processing.
untagle oidc and regcache, use typed cache
This commits stops reusing the registration cache for oidc
purposes and switches the cache to be types and not use any
allowing the removal of a bunch of casting.
try to make reauth/register branches clearer in oidc
Currently there was a function that did a bunch of stuff,
finding the machine key, trying to find the node, reauthing
the node, returning some status, and it was called validate
which was very confusing.
This commit tries to split this into what to do if the node
exists, if it needs to register etc.
Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
2024-10-02 12:50:17 +00:00
func ( d * deprecator ) fatal ( oldKey string ) {
2024-07-18 05:38:25 +00:00
if viper . IsSet ( oldKey ) {
Redo OIDC configuration (#2020)
expand user, add claims to user
This commit expands the user table with additional fields that
can be retrieved from OIDC providers (and other places) and
uses this data in various tailscale response objects if it is
available.
This is the beginning of implementing
https://docs.google.com/document/d/1X85PMxIaVWDF6T_UPji3OeeUqVBcGj_uHRM5CI-AwlY/edit
trying to make OIDC more coherant and maintainable in addition
to giving the user a better experience and integration with a
provider.
remove usernames in magic dns, normalisation of emails
this commit removes the option to have usernames as part of MagicDNS
domains and headscale will now align with Tailscale, where there is a
root domain, and the machine name.
In addition, the various normalisation functions for dns names has been
made lighter not caring about username and special character that wont
occur.
Email are no longer normalised as part of the policy processing.
untagle oidc and regcache, use typed cache
This commits stops reusing the registration cache for oidc
purposes and switches the cache to be types and not use any
allowing the removal of a bunch of casting.
try to make reauth/register branches clearer in oidc
Currently there was a function that did a bunch of stuff,
finding the machine key, trying to find the node, reauthing
the node, returning some status, and it was called validate
which was very confusing.
This commit tries to split this into what to do if the node
exists, if it needs to register etc.
Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
2024-10-02 12:50:17 +00:00
d . fatals . Add (
fmt . Sprintf (
"The %q configuration key has been removed. Please see the changelog for more details." ,
oldKey ,
) ,
)
2024-08-19 09:41:05 +00:00
}
}
// fatalIfNewKeyIsNotUsed deprecates and adds an entry to the fatal list of options if the oldKey is set and the new key is _not_ set.
// If the new key is set, a warning is emitted instead.
func ( d * deprecator ) fatalIfNewKeyIsNotUsed ( newKey , oldKey string ) {
if viper . IsSet ( oldKey ) && ! viper . IsSet ( newKey ) {
Redo OIDC configuration (#2020)
expand user, add claims to user
This commit expands the user table with additional fields that
can be retrieved from OIDC providers (and other places) and
uses this data in various tailscale response objects if it is
available.
This is the beginning of implementing
https://docs.google.com/document/d/1X85PMxIaVWDF6T_UPji3OeeUqVBcGj_uHRM5CI-AwlY/edit
trying to make OIDC more coherant and maintainable in addition
to giving the user a better experience and integration with a
provider.
remove usernames in magic dns, normalisation of emails
this commit removes the option to have usernames as part of MagicDNS
domains and headscale will now align with Tailscale, where there is a
root domain, and the machine name.
In addition, the various normalisation functions for dns names has been
made lighter not caring about username and special character that wont
occur.
Email are no longer normalised as part of the policy processing.
untagle oidc and regcache, use typed cache
This commits stops reusing the registration cache for oidc
purposes and switches the cache to be types and not use any
allowing the removal of a bunch of casting.
try to make reauth/register branches clearer in oidc
Currently there was a function that did a bunch of stuff,
finding the machine key, trying to find the node, reauthing
the node, returning some status, and it was called validate
which was very confusing.
This commit tries to split this into what to do if the node
exists, if it needs to register etc.
Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
2024-10-02 12:50:17 +00:00
d . fatals . Add (
fmt . Sprintf (
"The %q configuration key is deprecated. Please use %q instead. %q has been removed." ,
oldKey ,
newKey ,
oldKey ,
) ,
)
2024-08-19 09:41:05 +00:00
} else if viper . IsSet ( oldKey ) {
d . warns . Add ( fmt . Sprintf ( "The %q configuration key is deprecated. Please use %q instead. %q has been removed." , oldKey , newKey , oldKey ) )
}
}
// warn deprecates and adds an option to log a warning if the oldKey is set.
func ( d * deprecator ) warnNoAlias ( newKey , oldKey string ) {
if viper . IsSet ( oldKey ) {
Redo OIDC configuration (#2020)
expand user, add claims to user
This commit expands the user table with additional fields that
can be retrieved from OIDC providers (and other places) and
uses this data in various tailscale response objects if it is
available.
This is the beginning of implementing
https://docs.google.com/document/d/1X85PMxIaVWDF6T_UPji3OeeUqVBcGj_uHRM5CI-AwlY/edit
trying to make OIDC more coherant and maintainable in addition
to giving the user a better experience and integration with a
provider.
remove usernames in magic dns, normalisation of emails
this commit removes the option to have usernames as part of MagicDNS
domains and headscale will now align with Tailscale, where there is a
root domain, and the machine name.
In addition, the various normalisation functions for dns names has been
made lighter not caring about username and special character that wont
occur.
Email are no longer normalised as part of the policy processing.
untagle oidc and regcache, use typed cache
This commits stops reusing the registration cache for oidc
purposes and switches the cache to be types and not use any
allowing the removal of a bunch of casting.
try to make reauth/register branches clearer in oidc
Currently there was a function that did a bunch of stuff,
finding the machine key, trying to find the node, reauthing
the node, returning some status, and it was called validate
which was very confusing.
This commit tries to split this into what to do if the node
exists, if it needs to register etc.
Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
2024-10-02 12:50:17 +00:00
d . warns . Add (
fmt . Sprintf (
"The %q configuration key is deprecated. Please use %q instead. %q has been removed." ,
oldKey ,
newKey ,
oldKey ,
) ,
)
2024-08-19 09:41:05 +00:00
}
}
// warn deprecates and adds an entry to the warn list of options if the oldKey is set.
func ( d * deprecator ) warn ( oldKey string ) {
if viper . IsSet ( oldKey ) {
Redo OIDC configuration (#2020)
expand user, add claims to user
This commit expands the user table with additional fields that
can be retrieved from OIDC providers (and other places) and
uses this data in various tailscale response objects if it is
available.
This is the beginning of implementing
https://docs.google.com/document/d/1X85PMxIaVWDF6T_UPji3OeeUqVBcGj_uHRM5CI-AwlY/edit
trying to make OIDC more coherant and maintainable in addition
to giving the user a better experience and integration with a
provider.
remove usernames in magic dns, normalisation of emails
this commit removes the option to have usernames as part of MagicDNS
domains and headscale will now align with Tailscale, where there is a
root domain, and the machine name.
In addition, the various normalisation functions for dns names has been
made lighter not caring about username and special character that wont
occur.
Email are no longer normalised as part of the policy processing.
untagle oidc and regcache, use typed cache
This commits stops reusing the registration cache for oidc
purposes and switches the cache to be types and not use any
allowing the removal of a bunch of casting.
try to make reauth/register branches clearer in oidc
Currently there was a function that did a bunch of stuff,
finding the machine key, trying to find the node, reauthing
the node, returning some status, and it was called validate
which was very confusing.
This commit tries to split this into what to do if the node
exists, if it needs to register etc.
Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
2024-10-02 12:50:17 +00:00
d . warns . Add (
fmt . Sprintf (
"The %q configuration key is deprecated and has been removed. Please see the changelog for more details." ,
oldKey ,
) ,
)
2024-08-19 09:41:05 +00:00
}
}
func ( d * deprecator ) String ( ) string {
var b strings . Builder
for _ , w := range d . warns . Slice ( ) {
fmt . Fprintf ( & b , "WARN: %s\n" , w )
}
for _ , f := range d . fatals . Slice ( ) {
fmt . Fprintf ( & b , "FATAL: %s\n" , f )
}
return b . String ( )
}
func ( d * deprecator ) Log ( ) {
if len ( d . fatals ) > 0 {
log . Fatal ( ) . Msg ( "\n" + d . String ( ) )
} else if len ( d . warns ) > 0 {
log . Warn ( ) . Msg ( "\n" + d . String ( ) )
2024-07-18 05:38:25 +00:00
}
}