diff --git a/.env.example b/.env.example index da0a0831f..670e5c876 100644 --- a/.env.example +++ b/.env.example @@ -220,6 +220,23 @@ TINYAUTH_LDAP_AUTHCERT= TINYAUTH_LDAP_AUTHKEY= # Cache duration for LDAP group membership in seconds. TINYAUTH_LDAP_GROUPCACHETTL=900 + +# experimental config + +# Enable Tailscale integration. +TINYAUTH_EXPERIMENTAL_TAILSCALE_ENABLED=false +# Tailscale state directory. +TINYAUTH_EXPERIMENTAL_TAILSCALE_DIR="./tailscale_state" +# Tailscale hostname. +TINYAUTH_EXPERIMENTAL_TAILSCALE_HOSTNAME= +# Tailscale auth key. +TINYAUTH_EXPERIMENTAL_TAILSCALE_AUTHKEY= +# Use ephemeral Tailscale node. +TINYAUTH_EXPERIMENTAL_TAILSCALE_EPHEMERAL=false +# Enable Tailscale Funnel. +TINYAUTH_EXPERIMENTAL_TAILSCALE_FUNNEL=false +# Listen on the Tailscale address instead of standard address. +TINYAUTH_EXPERIMENTAL_TAILSCALE_LISTEN=false # Label provider to use for ACLs (auto, docker, kubernetes or none to disable). auto detects the environment. TINYAUTH_LABELPROVIDER="auto" @@ -241,20 +258,3 @@ TINYAUTH_LOG_STREAMS_APP_LEVEL= TINYAUTH_LOG_STREAMS_AUDIT_ENABLED=false # Log level for this stream. Use global if empty. TINYAUTH_LOG_STREAMS_AUDIT_LEVEL= - -# tailscale config - -# Enable Tailscale integration. -TINYAUTH_TAILSCALE_ENABLED=false -# Tailscale state directory. -TINYAUTH_TAILSCALE_DIR="./tailscale_state" -# Tailscale hostname. -TINYAUTH_TAILSCALE_HOSTNAME= -# Tailscale auth key. -TINYAUTH_TAILSCALE_AUTHKEY= -# Use ephemeral Tailscale node. -TINYAUTH_TAILSCALE_EPHEMERAL=false -# Enable Tailscale Funnel. -TINYAUTH_TAILSCALE_FUNNEL=false -# Listen on the Tailscale address instead of standard address. -TINYAUTH_TAILSCALE_LISTEN=false diff --git a/internal/bootstrap/app_bootstrap.go b/internal/bootstrap/app_bootstrap.go index 698c019e7..f9ca54725 100644 --- a/internal/bootstrap/app_bootstrap.go +++ b/internal/bootstrap/app_bootstrap.go @@ -279,7 +279,7 @@ func (app *BootstrapApp) Setup() error { app.runtime.ConfiguredProviders = configuredProviders // if tailscale is enabled and listening, replace the app url with the tailscale hostname - if app.services.tailscaleService != nil && app.config.Tailscale.Listen { + if app.services.tailscaleService != nil && app.config.Experimental.Tailscale.Listen { tailscaleUrl := "https://" + app.services.tailscaleService.GetHostname() // if the tailscale url is different from the app url, replace it diff --git a/internal/bootstrap/router_bootstrap.go b/internal/bootstrap/router_bootstrap.go index 8a92a1d01..f0ef90a98 100644 --- a/internal/bootstrap/router_bootstrap.go +++ b/internal/bootstrap/router_bootstrap.go @@ -130,9 +130,9 @@ func (app *BootstrapApp) setupRouter() error { // 2. Unix socket (if server.socketPath) // 3. HTTP - default func (app *BootstrapApp) getListenerFunc() (func(ctx context.Context) error, error) { - if app.config.Tailscale.Listen { + if app.config.Experimental.Tailscale.Listen { if app.services.tailscaleService == nil { - return nil, fmt.Errorf("tailscale.listen is enabled but tailscale service is not initialized") + return nil, fmt.Errorf("experimental.tailscale.listen is enabled but tailscale service is not initialized") } return app.serveTailscale, nil } diff --git a/internal/model/config.go b/internal/model/config.go index e51415306..39bcb31d3 100644 --- a/internal/model/config.go +++ b/internal/model/config.go @@ -81,8 +81,10 @@ func NewDefaultConfiguration(runtimeEnv RuntimeEnv) *Config { PrivateKeyPath: "./tinyauth_oidc_key", PublicKeyPath: "./tinyauth_oidc_key.pub", }, - Tailscale: TailscaleConfig{ - Dir: "./tailscale_state", + Experimental: ExperimentalConfig{ + Tailscale: TailscaleConfig{ + Dir: "./tailscale_state", + }, }, LabelProvider: "auto", } @@ -93,29 +95,28 @@ func NewDefaultConfiguration(runtimeEnv RuntimeEnv) *Config { cfg.Resources.Path = "/data/resources" cfg.OIDC.PrivateKeyPath = "/data/oidc/key.pem" cfg.OIDC.PublicKeyPath = "/data/oidc/key.pub" - cfg.Tailscale.Dir = "/data/tailscale" + cfg.Experimental.Tailscale.Dir = "/data/tailscale" } return cfg } type Config struct { - AppURL string `description:"The base URL where the app is hosted." yaml:"appUrl"` - Database DatabaseConfig `description:"Database configuration." yaml:"database"` - Analytics AnalyticsConfig `description:"Analytics configuration." yaml:"analytics"` - Resources ResourcesConfig `description:"Resources configuration." yaml:"resources"` - Server ServerConfig `description:"Server configuration." yaml:"server"` - Auth AuthConfig `description:"Authentication configuration." yaml:"auth"` - Apps map[string]App `description:"Application ACLs configuration." yaml:"apps"` - OAuth OAuthConfig `description:"OAuth configuration." yaml:"oauth"` - OIDC OIDCConfig `description:"OIDC configuration." yaml:"oidc"` - UI UIConfig `description:"UI customization." yaml:"ui"` - LDAP LDAPConfig `description:"LDAP configuration." yaml:"ldap"` - // Experimental ExperimentalConfig `description:"Experimental features, use with caution." yaml:"experimental"` - LabelProvider string `description:"Label provider to use for ACLs (auto, docker, kubernetes or none to disable). auto detects the environment." yaml:"labelProvider"` - Log LogConfig `description:"Logging configuration." yaml:"log"` - Tailscale TailscaleConfig `description:"Tailscale configuration." yaml:"tailscale"` - ConfigFile string `description:"Path to config file." yaml:"-"` + AppURL string `description:"The base URL where the app is hosted." yaml:"appUrl"` + Database DatabaseConfig `description:"Database configuration." yaml:"database"` + Analytics AnalyticsConfig `description:"Analytics configuration." yaml:"analytics"` + Resources ResourcesConfig `description:"Resources configuration." yaml:"resources"` + Server ServerConfig `description:"Server configuration." yaml:"server"` + Auth AuthConfig `description:"Authentication configuration." yaml:"auth"` + Apps map[string]App `description:"Application ACLs configuration." yaml:"apps"` + OAuth OAuthConfig `description:"OAuth configuration." yaml:"oauth"` + OIDC OIDCConfig `description:"OIDC configuration." yaml:"oidc"` + UI UIConfig `description:"UI customization." yaml:"ui"` + LDAP LDAPConfig `description:"LDAP configuration." yaml:"ldap"` + Experimental ExperimentalConfig `description:"Experimental features, use with caution." yaml:"experimental"` + LabelProvider string `description:"Label provider to use for ACLs (auto, docker, kubernetes or none to disable). auto detects the environment." yaml:"labelProvider"` + Log LogConfig `description:"Logging configuration." yaml:"log"` + ConfigFile string `description:"Path to config file." yaml:"-"` } type DatabaseConfig struct { @@ -237,8 +238,9 @@ type LogStreamConfig struct { Level string `description:"Log level for this stream. Use global if empty." yaml:"level"` } -// no experimental features -type ExperimentalConfig struct{} +type ExperimentalConfig struct { + Tailscale TailscaleConfig `description:"Tailscale configuration." yaml:"tailscale"` +} type TailscaleConfig struct { Enabled bool `description:"Enable Tailscale integration." yaml:"enabled"` diff --git a/internal/service/tailscale_service.go b/internal/service/tailscale_service.go index 183f6f273..861d9cceb 100644 --- a/internal/service/tailscale_service.go +++ b/internal/service/tailscale_service.go @@ -45,17 +45,17 @@ type TailscaleServiceInput struct { } func NewTailscaleService(i TailscaleServiceInput) (*TailscaleService, error) { - if !i.Config.Tailscale.Enabled { + if !i.Config.Experimental.Tailscale.Enabled { return nil, nil } srv := new(tsnet.Server) // node options - srv.Dir = i.Config.Tailscale.Dir - srv.Hostname = i.Config.Tailscale.Hostname - srv.AuthKey = i.Config.Tailscale.AuthKey - srv.Ephemeral = i.Config.Tailscale.Ephemeral + srv.Dir = i.Config.Experimental.Tailscale.Dir + srv.Hostname = i.Config.Experimental.Tailscale.Hostname + srv.AuthKey = i.Config.Experimental.Tailscale.AuthKey + srv.Ephemeral = i.Config.Experimental.Tailscale.Ephemeral // redirect logs to zerolog srv.Logf = i.Log.App.Printf @@ -94,7 +94,7 @@ func NewTailscaleService(i TailscaleServiceInput) (*TailscaleService, error) { i.Ding.Go(service.watchAndClose, ding.RingMajor) - if i.Config.Tailscale.Funnel && !i.Config.Tailscale.Listen { + if i.Config.Experimental.Tailscale.Funnel && !i.Config.Experimental.Tailscale.Listen { service.log.App.Warn().Msg("Tailscale Funnel is enabled but listen is disabled. Funnel will not work without listen enabled.") } @@ -153,7 +153,7 @@ func (ts *TailscaleService) CreateListener() (net.Listener, error) { return *ts.ln, nil } - if ts.config.Tailscale.Funnel { + if ts.config.Experimental.Tailscale.Funnel { ln, err := ts.srv.ListenFunnel("tcp", ":443") if err != nil { return nil, err